Skip to content

Machine 建模

QEMU 创建虚拟机的核心流程可分为 6 个阶段,每个阶段都涉及特定的组件和操作:

命令行参数解析与初始化

入口函数:main()(位于 softmmu/main.c) 关键操作:

  • 解析 -M 参数指定机器类型(如 virt)
  • 初始化 QOM(QEMU 对象模型)类型系统
  • 创建全局状态机 MachineState

代码流程:

// softmmu/main.c
int main(int argc, char **argv) {
    qemu_init(argc, argv); // 初始化核心系统
    qemu_main_loop();      // 进入主事件循环
}

// system/vl.c
void qemu_init(int argc, char **argv) {
    qemu_opts_parse();          // 解析命令行参数
    machine_opts_dict = qdict_new(); // 创建机器参数字典
    keyval_parse_into(machine_opts_dict, optarg, "type"); // 解析-M 参数
    qemu_create_machine(machine_opts_dict); // 创建机器实例
}

机器类型选择与注册

核心组件:MachineClass(机器类描述)

关键操作: - 通过 select_machine() 匹配用户指定的机器类型 - 从全局类型表 type_table 查找对应的 TypeImpl

// hw/core/machine.c
static MachineClass *select_machine(QDict *qdict) {
    const char *optarg = qdict_get_try_str(qdict, "type");
    GSList *machines = object_class_get_list(TYPE_MACHINE, false);
    machine_class = find_machine(optarg, machines); // 匹配机器类型
    return machine_class;
}

// qom/object.c
GSList *object_class_get_list(const char *implements_type) {
    g_hash_table_foreach(type_table, object_class_foreach_tramp, &data);
    // 遍历所有已注册的机器类型
}

机器对象实例化

核心组件:MachineState(机器运行时状态)

关键操作: - 通过 QOM 的 object_new_with_class() 实例化机器 - 初始化内存、CPU 拓扑等基础属性

// system/vl.c
static void qemu_create_machine(QDict *qdict) {
    MachineClass *machine_class = select_machine(qdict);
    current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));
    // 设置内存大小(示例)
    current_machine->ram_size = machine_class->default_ram_size;
}

// hw/core/machine.c
static void machine_initfn(Object *obj) {
    MachineState *ms = MACHINE(obj);
    ms->ram_size = mc->default_ram_size; // 默认内存大小
    ms->smp.cpus = mc->default_cpus;    // 默认 CPU 数量
}

硬件设备初始化

核心阶段:machine_run_board_init()

关键操作:

  • 调用机器专属的 init() 方法(如 RISC-V virt 的 virt_machine_init())
  • 初始化 CPU、内存控制器、总线等核心组件
// system/vl.c
void machine_run_board_init(MachineState *machine) {
    MachineClass *mc = MACHINE_GET_CLASS(machine);
    mc->init(machine); // 调用机器专属初始化函数
}

// hw/riscv/virt.c (RISC-V 示例)
static void virt_machine_init(MachineState *machine) {
    // 1. 初始化 CPU 拓扑
    for (int i = 0; i < smp_cpus; i++) {
        object_initialize_child(OBJECT(machine), "cpu", &s->soc[i], CPU_TYPE);
    }

    // 2. 初始化内存系统
    memory_region_init_ram(&s->ram, "riscv_virt_board.ram", ram_size);

    // 3. 初始化外设总线
    sysbus_init_mmio(SYS_BUS_DEVICE(&s->plic), &s->plic_mmio);

    // 4. 创建设备树 (FDT)
    create_fdt(s);
}

加速器与 CPU 初始化

核心组件:AccelState 和 CPUState

关键操作: - 根据 -accel 参数选择 KVM/TCG 加速器 - 创建 vCPU 线程并绑定到物理 CPU

// accel/accel-softmmu.c
void accel_init_machine(MachineState *ms) {
    AccelClass *ac = ACCEL_GET_CLASS(accel);
    ac->init_machine(ms); // 初始化加速器
}

// accel/kvm/kvm-all.c (KVM 示例)
static void kvm_init(MachineState *ms) {
    kvm_state->fd = open("/dev/kvm", O_RDWR); // 打开 KVM 设备
    kvm_state->vmfd = ioctl(kvm_state->fd, KVM_CREATE_VM); // 创建虚拟机
}

// cpu.c
void qemu_init_vcpu(CPUState *cpu) {
    cpus_accel->create_vcpu_thread(cpu); // 创建 vCPU 线程
}

启动虚拟机

最终阶段:qemu_main_loop()

关键操作: - 加载 BIOS 或内核镜像 - 启动 vCPU 线程执行客户机代码 - 进入主事件循环处理 I/O

// system/vl.c
void qemu_main_loop(void) {
    // 1. 加载 BIOS 或内核
    if (machine->kernel_filename) {
        load_kernel(machine->kernel_filename);
    }

    // 2. 启动所有 vCPU
    CPU_FOREACH(cpu) {
        qemu_cpu_kick(cpu);
    }

    // 3. 主事件循环
    while (!main_loop_should_exit()) {
        main_loop_wait(false);
    }
}

一个简化的 RISC-V virt Machine 代码示例:

/* hw/riscv/virt.c - RISC-V virt 机器实现 */

#define TYPE_RISCV_VIRT_MACHINE "riscv-virt-machine"

typedef struct RISCVVirtState {
    MachineState parent; // 继承 MachineState

    /* 硬件组件 */
    RISCVHartArrayState soc[RISCV_SOCKETS_MAX]; // CPU 集群
    MemoryRegion ram;                          // 内存区域
    DeviceState *plic;                         // 中断控制器
    DeviceState *uart;                         // 串口设备
} RISCVVirtState;

/* 机器类初始化 */
static void virt_machine_class_init(ObjectClass *oc, void *data) {
    MachineClass *mc = MACHINE_CLASS(oc);

    mc->desc = "RISC-V VirtIO Board";
    mc->init = virt_machine_init;          // 绑定初始化函数
    mc->max_cpus = 8;                      // 最大 CPU 数
    mc->default_ram_size = 256 * MiB;       // 默认内存大小
    mc->default_cpu_type = RISCV_CPU_TYPE_NAME("rv64");
}

/* 机器实例初始化 */
static void virt_machine_init(MachineState *machine) {
    RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
    const MemMapEntry *memmap = virt_memmap;

    /* === 1. 初始化 CPU 拓扑 === */
    for (int i = 0; i < machine->smp.cpus; i++) {
        char *name = g_strdup_printf("cpu%d", i);
        object_initialize_child(OBJECT(machine), name, &s->soc[i],
                               TYPE_RISCV_HART_ARRAY);
        qdev_realize(DEVICE(&s->soc[i]), NULL, &error_fatal);
    }

    /* === 2. 初始化内存系统 === */
    memory_region_init_ram(&s->ram, OBJECT(machine), "riscv_virt.ram",
                           machine->ram_size, &error_fatal);
    memory_region_add_subregion(get_system_memory(), memmap[VIRT_DRAM].base, &s->ram);

    /* === 3. 初始化中断控制器 === */
    s->plic = qdev_new(TYPE_RISCV_PLIC);
    qdev_prop_set_uint32(s->plic, "num-sources", VIRT_PLIC_NUM_SOURCES);
    sysbus_realize_and_unref(SYS_BUS_DEVICE(s->plic), &error_fatal);
    sysbus_mmio_map(SYS_BUS_DEVICE(s->plic), 0, memmap[VIRT_PLIC].base);

    /* === 4. 初始化串口 === */
    s->uart = qdev_new(TYPE_SERIAL_MM);
    qdev_prop_set_chr(s->uart, "chardev", serial_hd(0));
    sysbus_realize_and_unref(SYS_BUS_DEVICE(s->uart), &error_fatal);
    sysbus_mmio_map(SYS_BUS_DEVICE(s->uart), 0, memmap[VIRT_UART0].base);

    /* === 5. 创建设备树 === */
    s->fdt = create_device_tree(&s->fdt_size);
    create_fdt(s); // 生成设备树二进制

    /* === 6. 加载固件和内核 === */
    if (machine->firmware) {
        riscv_load_firmware(machine->firmware, memmap[VIRT_DRAM].base);
    }
    if (machine->kernel_filename) {
        riscv_load_kernel(machine->kernel_filename);
    }
}

/* === QOM 类型注册 === */
static const TypeInfo virt_machine_typeinfo = {
    .name = TYPE_RISCV_VIRT_MACHINE,
    .parent = TYPE_MACHINE,
    .class_init = virt_machine_class_init,
    .instance_size = sizeof(RISCVVirtState),
};

static void virt_machine_register_types(void) {
    type_register_static(&virt_machine_typeinfo);
}
type_init(virt_machine_register_types);