Machine Layer

Config parsing, machine class dispatch, and SoC initialization

Data Flow

graph TD A[main in temu.c] --> B[virt_machine_set_defaults] B --> C[virt_machine_load_config_file] C --> D[JSON parse: machine.c + json.c] D --> E[VirtMachineParams] E --> F[virt_machine_init] F --> G{Machine class?} G -->|riscv| H[riscv_machine_init] G -->|pc| I[pc_machine_init] H --> J[phys_mem_map_init] H --> K[riscv_cpu_init] H --> L[Register RAM + Devices] H --> M[copy_bios / FDT]

Configuration Parsing

The emulator starts in main() inside temu.c. It parses CLI flags, sets defaults, loads a JSON configuration file, and then overrides parameters like RAM size or acceleration.

int main(int argc, char **argv)
{
    VirtMachine *s;
    VirtMachineParams p_s, *p = &p_s;
    /* ... option parsing ... */
    virt_machine_set_defaults(p);
    virt_machine_load_config_file(p, path, NULL, NULL);
    /* override parameters */
    if (ram_size > 0) p->ram_size = (uint64_t)ram_size << 20;
    /* open drives, filesystems, network */
    s = virt_machine_init(p);
    for(;;) { virt_machine_run(s); }
}

JSON Config Loader

machine.c defines virt_machine_parse_config() which walks the JSON object and fills VirtMachineParams: machine name, RAM size, drives, filesystems, network interfaces, display, and input devices.

int virt_machine_parse_config(VirtMachineParams *p,
                              const char *buf, int buf_len)
{
    /* parse JSON into VM parameters */
}

Machine Class Dispatch

machine.h defines the VirtMachineClass vtable. Two classes are exported: riscv_machine_class and pc_machine_class. The config machine_name selects which class is used.

struct VirtMachineClass {
    const char *machine_names;
    void (*virt_machine_set_defaults)(VirtMachineParams *p);
    VirtMachine *(*virt_machine_init)(const VirtMachineParams *p);
    void (*virt_machine_end)(VirtMachine *s);
    int (*virt_machine_get_sleep_duration)(VirtMachine *s, int delay);
    void (*virt_machine_interp)(VirtMachine *s, int max_exec_cycle);
    BOOL (*vm_mouse_is_absolute)(VirtMachine *s);
    void (*vm_send_mouse_event)(VirtMachine *s1, int dx, int dy, int dz,
                                unsigned int buttons);
    void (*vm_send_key_event)(VirtMachine *s1, BOOL is_down, uint16_t key_code);
};

RISC-V Machine Initialization

riscv_machine_init() in riscv_machine.c is the heart of SoC setup. It creates the memory map, initializes the CPU, registers RAM, CLINT, PLIC, HTIF, and all VirtIO devices, then copies the BIOS/kernel into RAM and builds the Flattened Device Tree (FDT).

static VirtMachine *riscv_machine_init(const VirtMachineParams *p)
{
    RISCVMachine *s;
    /* select xlen from machine_name */
    s->mem_map = phys_mem_map_init();
    s->cpu_state = riscv_cpu_init(s->mem_map, max_xlen);
    cpu_register_ram(s->mem_map, RAM_BASE_ADDR, p->ram_size, 0);
    cpu_register_ram(s->mem_map, 0x00000000, LOW_RAM_SIZE, 0);
    cpu_register_device(s->mem_map, CLINT_BASE_ADDR, CLINT_SIZE, s,
                        clint_read, clint_write, DEVIO_SIZE32);
    cpu_register_device(s->mem_map, PLIC_BASE_ADDR, PLIC_SIZE, s,
                        plic_read, plic_write, DEVIO_SIZE32);
    cpu_register_device(s->mem_map, HTIF_BASE_ADDR, 16,
                        s, htif_read, htif_write, DEVIO_SIZE32);
    /* virtio devices */
    virtio_console_init(vbus, p->console);
    virtio_net_init(vbus, p->tab_eth[i].net);
    virtio_block_init(vbus, p->tab_drive[i].block_dev);
    virtio_9p_init(vbus, p->tab_fs[i].fs_dev, p->tab_fs[i].tag);
    /* display & input */
    simplefb_init(s->mem_map, FRAMEBUFFER_BASE_ADDR, fb_dev, p->width, p->height);
    virtio_input_init(vbus, VIRTIO_INPUT_TYPE_KEYBOARD);
    virtio_input_init(vbus, VIRTIO_INPUT_TYPE_TABLET);
    /* copy bios/kernel/cmdline and build FDT */
    copy_bios(s, ...);
    return (VirtMachine *)s;
}

Key Data Structures