QEMU源码全解析33 —— Machine(3)

接前一篇文章:QEMU源码全解析32 ------ Machine(2)

本文内容参考:

《趣谈Linux操作系统》 ------ 刘超,极客时间

QEMU/KVM》源码解析与应用 ------ 李强,机械工业出版社

特此致谢!

前面两篇文章分别介绍了Intel 440FX主板和QEMU模拟该主板的架构。本回开始,用几篇文章讲解QEMU的主板模拟与初始化。

虚拟机初始化

QEMU主板模拟对应的类型是MachineClass,对位文件主要有:hw/core/machine.c、hw/i386/pc_piix.c。Machine在这里表明了主板在虚拟机模拟中的地位。本文以i440FX+piix3主板为例进行讲解。

机器类型的定义是通过DEFINE_I440FX_MACHINE宏完成的,该宏在hw/i386/pc_piix.c中定义,代码如下:

cpp 复制代码
#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
    static void pc_init_##suffix(MachineState *machine) \
    { \
        void (*compat)(MachineState *m) = (compatfn); \
        if (compat) { \
            compat(machine); \
        } \
        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
                 TYPE_I440FX_PCI_DEVICE); \
    } \
    DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)

DEFINE_I440FX_MACHINE的定义比较简单,包含一个函数以及另一个宏DEFINE_PC_MACHINE。DEFINE_PC_MACHINE在include/hw/i386/pc.h中定义,代码如下:

cpp 复制代码
#define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \
    static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \
    { \
        MachineClass *mc = MACHINE_CLASS(oc); \
        optsfn(mc); \
        mc->init = initfn; \
    } \
    static const TypeInfo pc_machine_type_##suffix = { \
        .name       = namestr TYPE_MACHINE_SUFFIX, \
        .parent     = TYPE_PC_MACHINE, \
        .class_init = pc_machine_##suffix##_class_init, \
    }; \
    static void pc_machine_init_##suffix(void) \
    { \
        type_register(&pc_machine_type_##suffix); \
    } \
    type_init(pc_machine_init_##suffix)

在DEFINE_PC_MACHINE宏中,定义了一个函数pc_machine_##suffix##class_init,从函数的名字可以看出,这是machine_class从纸面上的class初始化为Class对象的方法。在这个函数中,创建了一个MachineClass对象,这就是Class对象。MachineClass对象的init函数指向上边定义的pc_init##suffix,说明此函数是machine这种类型初始化的函数,后面会被调用。

接着DEFINE_PC_MACHINE定义了一个pc_machine_type_##suffix的TypeInfo,这是用于生成纸面上的class的原材料,果真后边调用了type_init函数。

每一个新版本都会定义一种新的机器类型。这里给出其中的一些例子,都是在hw/i386/pc_piix.c中:

cpp 复制代码
DEFINE_I440FX_MACHINE(v7_1, "pc-i440fx-7.1", NULL,
                      pc_i440fx_7_1_machine_options);
cpp 复制代码
DEFINE_I440FX_MACHINE(v7_0, "pc-i440fx-7.0", NULL,
                      pc_i440fx_7_0_machine_options);
cpp 复制代码
DEFINE_I440FX_MACHINE(v6_2, "pc-i440fx-6.2", NULL,
                      pc_i440fx_6_2_machine_options);
......
cpp 复制代码
DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5_fn,
                      pc_i440fx_1_5_machine_options);
cpp 复制代码
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn,
                      pc_i440fx_1_4_machine_options);

以最新的7.1版本为例进行说明。

cpp 复制代码
DEFINE_I440FX_MACHINE(v7_1, "pc-i440fx-7.1", NULL,
                      pc_i440fx_7_1_machine_options);

先进行初步展开,得到:

cpp 复制代码
static void pc_init_v7_1(MachineState *machine)
{
        void (*compat)(MachineState *m) = (NULL);
        if (compat) {
            compat(machine);
        }
        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
                 TYPE_I440FX_PCI_DEVICE);
    }
    DEFINE_PC_MACHINE(v7_1, "pc-i440fx-7.1", pc_init_v7_1, pc_i440fx_7_1_machine_options)

再将DEFINE_PC_MACHINE也展开,得到:

cpp 复制代码
static void pc_init_v7_1(MachineState *machine)
{
        void (*compat)(MachineState *m) = (NULL);
        if (compat) {
            compat(machine);
        }
        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
                 TYPE_I440FX_PCI_DEVICE);
}

static void pc_machine__class_init(ObjectClass *oc, void *data)
{
        MachineClass *mc = MACHINE_CLASS(oc);
        pc_i440fx_7_1_machine_options(mc);
        mc->init = pc_init_v7_1;
}
static const TypeInfo pc_machine_type_v7_1 = {
        .name       = "pc-i440fx-7.1" TYPE_MACHINE_SUFFIX,
        .parent     = TYPE_PC_MACHINE,
        .class_init = pc_machine_v7_1_class_init,
};
static void pc_machine_init_v7_1(void)
{
        type_register(&pc_machine_type_v7_1);
}
type_init(pc_machine_init_v7_1)

可以看到,DEFINE_I440FX_MACHINE宏直接完成了定义一个新类型的全部工作。在7.1版本中,它定义了"pc-i440fx-7.1-machine"这个新的TypeInfo。

看到这里,有读者可能也会有疑问,这个"pc-i440fx-7.1-machine"怎么来的?另外TypeInfo的对象明明是pc_machine_type_v7_1,怎么说是它呢?其实不难理解,将TYPE_MACHINE_SUFFIX这个宏代入你就明白了。TYPE_MACHINE_SUFFIX的定义在include/hw/boards.h中,如下:

cpp 复制代码
#define TYPE_MACHINE_SUFFIX "-machine"

将它代入,得到"pc-i440fx-7.1-machine",它是TypeInfo pc_machine_type_v7_1的name即名字,因此说DEFINE_I440FX_MACHINE(v7_1, "pc-i440fx-7.1", NULL, pc_i440fx_7_1_machine_options)定义了"pc-i440fx-7.1-machine"这个TypeInfo就不难理解了。

不单是v7_1上边列出的所有与"DEFINE_I440FX_MACHINE(v7_1, "pc-i440fx-7.1", NULL, pc_i440fx_7_1_machine_options);"类似的所有机器类型都会被加入到QOM类型链表中。

欲知后事如何,且看下回分解。

相关推荐
Roadinforest12 天前
wsl2配置xv6全解(包括22.04Jammy)
linux·操作系统·qemu·wsl·环境配置·xv6
千航@abc13 天前
虚拟机添加多块网卡,重启时,ip绑定错误如何解决
linux·服务器·网络·虚拟化·kvm
千航@abc13 天前
kvm虚拟机的基本使用
linux·运维·centos·虚拟化·kvm·virsh
itachi-uchiha14 天前
Huawei 鲲鹏(ARM/Aarch64)服务器安装KVM虚拟机(非桌面视图)
kvm·命令行·无桌面
GKDf1sh20 天前
通过qemu仿真树莓派系统调试IoT固件和程序
linux·网络·物联网·qemu
禾仔仔21 天前
RISC-V汇编学习(四)—— RISCV QEMU平台搭建(基于芯来平台)
汇编·qemu·risc-v·芯来科技
Evoxt 益沃斯1 个月前
How to enable Qemu Guest Agent for Virtual Machines
linux·运维·服务器·qemu
迷茫运维路1 个月前
麒麟V10-SP2-x86_64架构系统下通过KVM创建虚拟机及配置虚机的NAT、Bridge两种网络模式全过程
运维·虚拟机·kvm
skywalk81631 个月前
PolyOS 是面向 RISC-V 架构的智能终端和 AIoT 开源操作系统(基于开源鸿蒙)
qemu·harmonyos·risc-v
黑马金牌编程2 个月前
CentOS 7操作系统部署KVM软件和创建虚拟机
linux·运维·centos·虚拟化·kvm