文章目录

  • 系列文章目录
  • 第二章 QEMU系统仿真的机器创建分析实例
  • 前言
  • 一、QEMU是什么?
  • 二、QEMU系统仿真的机器创建分析实例
  • 1.系统仿真的命令行参数
  • 2.目标机器创建过程
  • 3. select_machine()
  • object_class_get_list(TYPE_MACHINE, false)
  • object_class_foreach_tramp()
  • type_initialize(type)
  • 程序执行与分析
  • 输出结果
  • 结果分析
  • type_initialize_interface()
  • 总结



前言

本文以 QEMU 8.2.2 为例,分析其作为系统仿真工具的工作过程,并为读者展示各种 QEMU 系统仿真的启动配置实例。
本文读者需要具备一定的 QEMU 系统仿真使用经验,并对 C 语言编程有一定了解。


一、QEMU是什么?

QEMU 是一个通用且开源的机器模拟器和虚拟机。
其官方主页是:https://www.qemu.org/


二、QEMU系统仿真的机器创建分析实例

1.系统仿真的命令行参数

QEMU 作为系统仿真工具,其入口代码在 system/main.c 文件中,初始化函数 qemu_init() 的实现在 system/vl.c 文件中。
本文将分析以下命令创建目标系统机器的运行过程,读者需要对 QEMU 系统启动过程的程序代码有所了解,相关内容可以参考《QEMU系统分析之启动篇》系列文章。

..\qemu\8.2.2-qkd\qemu-system-x86_64.exe -cpu "Penryn" -M  "q35,accel=whpx" -m "6G" -nodefaults

2.目标机器创建过程

这部分代码在 system/vl.c 文件中,实现如下:

int qemu_init(int argc, char **argv)
{
...
    qemu_create_machine(machine_opts_dict);
...
}

进入 qemu_create_machine() 后,第一步就是获取目标机器类型,代码如下:

static void qemu_create_machine(QDict *qdict)
{
    MachineClass *machine_class = select_machine(qdict, &error_fatal);
...
}

事实上,在 select_machine() 函数中同步也将建立对象字典中缺少的对象,接下来我们将添加调试代码,展示 select_machine() 是如何一步一步将对象字典补充完整的。


3. select_machine()

函数 select_machine() 在 /system/vl.c 文件中,定义如下:

static MachineClass *select_machine(QDict *qdict, Error **errp)
{
    const char *machine_type = qdict_get_try_str(qdict, "type");
    GSList *machines = object_class_get_list(TYPE_MACHINE, false);
    MachineClass *machine_class;
    Error *local_err = NULL;

    if (machine_type) {
        machine_class = find_machine(machine_type, machines);
        qdict_del(qdict, "type");
        if (!machine_class) {
            error_setg(&local_err, "unsupported machine type");
        }
    } else {
        machine_class = find_default_machine(machines);
        if (!machine_class) {
            error_setg(&local_err, "No machine specified, and there is no default");
        }
    }

    g_slist_free(machines);
    if (local_err) {
        error_append_hint(&local_err, "Use -machine help to list supported machines\n");
        error_propagate(errp, local_err);
    }
    return machine_class;
}

前一篇文章我们探索了

static MachineClass *select_machine(QDict *qdict, Error **errp)
{
    const char *machine_type = qdict_get_try_str(qdict, "type");
...
}

本文我们将探索

static MachineClass *select_machine(QDict *qdict, Error **errp)
{
...
    GSList *machines = object_class_get_list(TYPE_MACHINE, false);
...
}

object_class_get_list(TYPE_MACHINE, false)

函数 object_class_get_list() 在 /qom/object.c 文件中,定义如下:

GSList *object_class_get_list(const char *implements_type,
                              bool include_abstract)
{
    GSList *list = NULL;

    object_class_foreach(object_class_get_list_tramp,
                         implements_type, include_abstract, &list);
    return list;
}

添加调试代码:

GSList *object_class_get_list(const char *implements_type,
                              bool include_abstract)
{
    GSList *list = NULL;

    printf("huedbg: %s/%s(%d) tid=[%d] implements_type=[%s]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), implements_type);
    object_class_foreach(object_class_get_list_tramp,
                         implements_type, include_abstract, &list);
    printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    return list;
}

并逐个跟踪进入内部函数,函数 object_class_foreach 在 /qom/object.c 文件中,添加调试信息如下:

void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
                          const char *implements_type, bool include_abstract,
                          void *opaque)
{
    printf("huedbg: %s/%s(%d) tid=[%d] enter\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    OCFData data = { fn, implements_type, include_abstract, opaque };

    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    enumerating_types = true;
    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    enumerating_types = false;
    printf("huedbg: %s/%s(%d) tid=[%d] return\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
}

我们在函数入口和出口处打印输出调试信息,方便跟踪程序执行路径。

在函数 object_class_foreach() 中会调用函数 object_class_foreach_tramp() 对传入的参数做处理,此处有一个编程小技巧,我们将传入的参数统一封装在数据结构:

OCFData data = { fn, implements_type, include_abstract, opaque };

然后将 data 作为参数传给目标函数使用:

g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);

数据结构 OCFData 定义如下:

typedef struct OCFData
{
    void (*fn)(ObjectClass *klass, void *opaque);
    const char *implements_type;
    bool include_abstract;
    void *opaque;
} OCFData;

object_class_foreach_tramp()

继续跟踪进入函数 object_class_foreach_tramp(),添加调试信息如下:

static void object_class_foreach_tramp(gpointer key, gpointer value,
                                       gpointer opaque)
{
    OCFData *data = opaque;
    TypeImpl *type = value;
    ObjectClass *k;

    printf("huedbg: %s/%s(%d) tid=[%d] type->name=[%s]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), type->name);
    type_initialize(type);
    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    k = type->class;
    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());

    if (!data->include_abstract && type->abstract) {
        printf("huedbg: %s/%s(%d) tid=[%d] return-1\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
        return;
    }

    if (data->implements_type && 
        !object_class_dynamic_cast(k, data->implements_type)) {
        printf("huedbg: %s/%s(%d) tid=[%d] return-2\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
        return;
    }

    printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    data->fn(k, data->opaque);
    printf("huedbg: %s/%s(%d) tid=[%d] return-3\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
}

同样的,我们在函数入口和各个出口处添加打印输出。

在函数 object_class_foreach_tramp() 中,我们遇到类型对象实现的关键函数 type_initialize()。


type_initialize(type)

函数 type_initialize()在 /qom/object.c 文件中,我们同样添加调试信息进行执行跟踪,代码如下:

static void type_initialize(TypeImpl *ti)
{
    TypeImpl *parent;

    if (ti->class) {
        printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] class OK return\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), ti->name);
        return;
    }

    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    ti->class_size = type_class_get_size(ti);
    ti->instance_size = type_object_get_size(ti);
    ti->instance_align = type_object_get_align(ti);
    /* Any type with zero instance_size is implicitly abstract.
     * This means interface types are all abstract.
     */
    if (ti->instance_size == 0) {
        ti->abstract = true;
    }
    if (type_is_ancestor(ti, type_interface)) {
        assert(ti->instance_size == 0);
        assert(ti->abstract);
        assert(!ti->instance_init);
        assert(!ti->instance_post_init);
        assert(!ti->instance_finalize);
        assert(!ti->num_interfaces);
    }
    printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] new ti->class\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), ti->name);
    ti->class = g_malloc0(ti->class_size);

    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    parent = type_get_parent(ti);
    //printf("huedbg: %s/%s(%d) tid=[%d]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
    if (parent) {
        printf("huedbg: %s/%s(%d) tid=[%d] try parent->name=[%s]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), parent->name);
        type_initialize(parent);
        GSList *e;
        int i;

        g_assert(parent->class_size <= ti->class_size);
        g_assert(parent->instance_size <= ti->instance_size);
        memcpy(ti->class, parent->class, parent->class_size);
        ti->class->interfaces = NULL;

        for (e = parent->class->interfaces; e; e = e->next) {
            InterfaceClass *iface = e->data;
            ObjectClass *klass = OBJECT_CLASS(iface);

            printf("huedbg: %s/%s(%d) tid=[%d] try type_initialize_interface(%s,%s,%s)\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(),
                   ti->name, iface->interface_type->name, klass->type->name);
            type_initialize_interface(ti, iface->interface_type, klass->type);
            printf("huedbg: %s/%s(%d) tid=[%d] run-1\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
        }

        for (i = 0; i < ti->num_interfaces; i++) {
            //printf("huedbg: %s/%s(%d) tid=[%d] name=[%s]\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), ti->interfaces[i].typename);
            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
            if (!t) {
                error_report("missing interface '%s' for object '%s'",
                             ti->interfaces[i].typename, parent->name);
                abort();
            }
            for (e = ti->class->interfaces; e; e = e->next) {
                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;

                if (type_is_ancestor(target_type, t)) {
                    break;
                }
            }

            if (e) {
                continue;
            }

            printf("huedbg: %s/%s(%d) tid=[%d] try type_initialize_interface(%s,%s,%s])\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(),
                   ti->name, t->name, t->name);
            type_initialize_interface(ti, t, t);
            printf("huedbg: %s/%s(%d) tid=[%d] run-2\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
        }
    }

    ti->class->properties = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                                  object_property_free);

    ti->class->type = ti;

    while (parent) {
        if (parent->class_base_init) {
            printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] parent->class_base_init before\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), parent->name);
            parent->class_base_init(ti->class, ti->class_data);
            printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] parent->class_base_init after\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), parent->name);
        }
        parent = type_get_parent(parent);
    }

    if (ti->class_init) {
        printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] ti->class_init before\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), ti->name);
        ti->class_init(ti->class, ti->class_data);
        printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] ti->class_init after\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), ti->name);
    }
    printf("huedbg: %s/%s(%d) tid=[%d] name=[%s] new class return\n", __FILE__, __func__, __LINE__, qemu_get_thread_id(), ti->name);
}

如果让所有对象都创建出来,调试信息过大。因此,我们选择在初始化 x86 CPU 类型时退出函数,x86 CPU 类型初始化代码在 /target/i386/cpu.c 文件中,添加调试代码如下:

static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
{
    X86CPUClass *xcc = X86_CPU_CLASS(oc);
    CPUClass *cc = CPU_CLASS(oc);
    DeviceClass *dc = DEVICE_CLASS(oc);
    ResettableClass *rc = RESETTABLE_CLASS(oc);
    FeatureWord w;

    printf("huedbg: %s/%s(%d) tid=[%d] enter!\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());

...
    printf("huedbg: %s/%s(%d) tid=[%d] return!\n", __FILE__, __func__, __LINE__, qemu_get_thread_id());
}

程序执行与分析

添加调试代码并执行程序

D:\qkd-app\vmos>..\qemu\8.2.2-qkd\qemu-system-x86_64.exe -cpu "Penryn" -M "q35,accel=whpx" -m "6G" -nodefaults

输出结果

huedbg: ../system/vl.c/qemu_init(3845) tid=[34380] size=[3]
huedbg: ../system/vl.c/my_dump_qdict(2866) tid=[34380] key=[memory] obj_type=[4]
        huedbg: ../system/vl.c/my_dump_qdict(2866) tid=[34380] key=[size] obj_type=[3]
        huedbg: ../system/vl.c/my_dump_qdict(2871) tid=[34380] value=[6G]
huedbg: ../system/vl.c/my_dump_qdict(2866) tid=[34380] key=[accel] obj_type=[3]
huedbg: ../system/vl.c/my_dump_qdict(2871) tid=[34380] value=[whpx]
huedbg: ../system/vl.c/my_dump_qdict(2866) tid=[34380] key=[type] obj_type=[3]
huedbg: ../system/vl.c/my_dump_qdict(2871) tid=[34380] value=[q35]
huedbg: ../system/vl.c/qemu_create_machine(2101) tid=[34380]
huedbg: ../system/vl.c/select_machine(1661) tid=[34380]
huedbg: ../system/vl.c/select_machine(1663) tid=[34380]
huedbg: ../qom/object.c/object_class_get_list(1212) tid=[34380] implements_type=[machine]
huedbg: ../qom/object.c/object_class_foreach(1147) tid=[34380] enter
huedbg: ../qom/object.c/object_class_foreach_tramp(1121) tid=[34380] type->name=[Dhyana-v2-x86_64-cpu]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[Dhyana-v2-x86_64-cpu] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[x86_64-cpu]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[cpu]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[cpu] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[device]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[device] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[object]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[object] new ti->class
huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[object] ti->class_init before
huedbg: ../qom/object.c/object_class_init(2881) tid=[34380] enter
huedbg: ../qom/object.c/object_class_init(2884) tid=[34380] return
huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[object] ti->class_init after
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[object] new class return
huedbg: ../qom/object.c/type_initialize(374) tid=[34380] try type_initialize_interface(device,vmstate-if,vmstate-if])
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[device::vmstate-if] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[vmstate-if]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[vmstate-if] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[interface]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[interface] new ti->class
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[interface] new class return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[vmstate-if] new class return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[device::vmstate-if] new class return
huedbg: ../qom/object.c/type_initialize(377) tid=[34380] run-2
huedbg: ../qom/object.c/type_initialize(374) tid=[34380] try type_initialize_interface(device,resettable,resettable])
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[device::resettable] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[resettable]
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[resettable] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[interface]
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[interface] class OK return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[resettable] new class return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[device::resettable] new class return
huedbg: ../qom/object.c/type_initialize(377) tid=[34380] run-2
huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[device] ti->class_init before
huedbg: ../hw/core/qdev.c/device_class_init(814) tid=[34380] enter
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../hw/core/qdev.c/device_class_init(857) tid=[34380] return
huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[device] ti->class_init after
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[device] new class return
huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(cpu,vmstate-if,device::vmstate-if)
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[cpu::vmstate-if] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[device::vmstate-if]
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device::vmstate-if] class OK return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[cpu::vmstate-if] new class return
huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(cpu,resettable,device::resettable)
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[cpu::resettable] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[device::resettable]
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device::resettable] class OK return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[cpu::resettable] new class return
huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
huedbg: ../qom/object.c/type_initialize(388) tid=[34380] name=[device] parent->class_base_init before
huedbg: ../hw/core/qdev.c/device_class_base_init(724) tid=[34380] enter
huedbg: ../hw/core/qdev.c/device_class_base_init(731) tid=[34380] return
huedbg: ../qom/object.c/type_initialize(390) tid=[34380] name=[device] parent->class_base_init after
huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[cpu] ti->class_init before
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device] class OK return
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[cpu] ti->class_init after
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[cpu] new class return
huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(x86_64-cpu,vmstate-if,cpu::vmstate-if)
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu::vmstate-if] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[cpu::vmstate-if]
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[cpu::vmstate-if] class OK return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[x86_64-cpu::vmstate-if] new class return
huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(x86_64-cpu,resettable,cpu::resettable)
huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu::resettable] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[cpu::resettable]
huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[cpu::resettable] class OK return
huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[x86_64-cpu::resettable] new class return
huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
huedbg: ../qom/object.c/type_initialize(388) tid=[34380] name=[device] parent->class_base_init before
huedbg: ../hw/core/qdev.c/device_class_base_init(724) tid=[34380] enter
huedbg: ../hw/core/qdev.c/device_class_base_init(731) tid=[34380] return
huedbg: ../qom/object.c/type_initialize(390) tid=[34380] name=[device] parent->class_base_init after
huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[x86_64-cpu] ti->class_init before
huedbg: ../target/i386/cpu.c/x86_cpu_common_class_init(7952) tid=[34380] enter!

结果分析

选取我们关心的跟踪调试信息并做格式化处理

huedbg: ../system/vl.c/qemu_create_machine(2101) tid=[34380]
huedbg: ../system/vl.c/select_machine(1661) tid=[34380]
huedbg: ../system/vl.c/select_machine(1663) tid=[34380]
huedbg: ../qom/object.c/object_class_get_list(1212) tid=[34380] implements_type=[machine]
huedbg: ../qom/object.c/object_class_foreach(1147) tid=[34380] enter
huedbg: ../qom/object.c/object_class_foreach_tramp(1121) tid=[34380] type->name=[Dhyana-v2-x86_64-cpu]

huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[Dhyana-v2-x86_64-cpu] new ti->class
huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[x86_64-cpu]
    huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu] new ti->class
    huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[cpu]
        huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[cpu] new ti->class
        huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[device]
            huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[device] new ti->class
            huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[object]
                huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[object] new ti->class
                huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[object] ti->class_init before
                    huedbg: ../qom/object.c/object_class_init(2881) tid=[34380] enter
                    huedbg: ../qom/object.c/object_class_init(2884) tid=[34380] return
                huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[object] ti->class_init after
                huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[object] new class return
            huedbg: ../qom/object.c/type_initialize(374) tid=[34380] try type_initialize_interface(device,vmstate-if,vmstate-if])
                huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[device::vmstate-if] new ti->class
                huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[vmstate-if]
                    huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[vmstate-if] new ti->class
                    huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[interface]
                        huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[interface] new ti->class
                        huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[interface] new class return
                    huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[vmstate-if] new class return
                huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[device::vmstate-if] new class return
            huedbg: ../qom/object.c/type_initialize(377) tid=[34380] run-2
            huedbg: ../qom/object.c/type_initialize(374) tid=[34380] try type_initialize_interface(device,resettable,resettable])
                huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[device::resettable] new ti->class
                huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[resettable]
                    huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[resettable] new ti->class
                    huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[interface]
                        huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[interface] class OK return
                    huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[resettable] new class return
                huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[device::resettable] new class return
            huedbg: ../qom/object.c/type_initialize(377) tid=[34380] run-2
            huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[device] ti->class_init before
                huedbg: ../hw/core/qdev.c/device_class_init(814) tid=[34380] enter
                    huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
                    huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
                    huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
                    huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
                huedbg: ../hw/core/qdev.c/device_class_init(857) tid=[34380] return
            huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[device] ti->class_init after
            huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[device] new class return
        huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(cpu,vmstate-if,device::vmstate-if)
            huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[cpu::vmstate-if] new ti->class
            huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[device::vmstate-if]
                huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device::vmstate-if] class OK return
            huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[cpu::vmstate-if] new class return
        huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
        huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(cpu,resettable,device::resettable)
            huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[cpu::resettable] new ti->class
            huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[device::resettable]
                huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device::resettable] class OK return
            huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[cpu::resettable] new class return
        huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
        huedbg: ../qom/object.c/type_initialize(388) tid=[34380] name=[device] parent->class_base_init before
            huedbg: ../hw/core/qdev.c/device_class_base_init(724) tid=[34380] enter
            huedbg: ../hw/core/qdev.c/device_class_base_init(731) tid=[34380] return
        huedbg: ../qom/object.c/type_initialize(390) tid=[34380] name=[device] parent->class_base_init after
        huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[cpu] ti->class_init before
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device] class OK return
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device] class OK return
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[device] class OK return
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[object] class OK return
        huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[cpu] ti->class_init after
        huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[cpu] new class return
    huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(x86_64-cpu,vmstate-if,cpu::vmstate-if)
        huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu::vmstate-if] new ti->class
        huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[cpu::vmstate-if]
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[cpu::vmstate-if] class OK return
        huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[x86_64-cpu::vmstate-if] new class return
    huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
    huedbg: ../qom/object.c/type_initialize(348) tid=[34380] try type_initialize_interface(x86_64-cpu,resettable,cpu::resettable)
        huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu::resettable] new ti->class
        huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[cpu::resettable]
            huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[cpu::resettable] class OK return
        huedbg: ../qom/object.c/type_initialize(400) tid=[34380] name=[x86_64-cpu::resettable] new class return
    huedbg: ../qom/object.c/type_initialize(351) tid=[34380] run-1
    huedbg: ../qom/object.c/type_initialize(388) tid=[34380] name=[device] parent->class_base_init before
        huedbg: ../hw/core/qdev.c/device_class_base_init(724) tid=[34380] enter
        huedbg: ../hw/core/qdev.c/device_class_base_init(731) tid=[34380] return
    huedbg: ../qom/object.c/type_initialize(390) tid=[34380] name=[device] parent->class_base_init after
    huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[x86_64-cpu] ti->class_init before
        huedbg: ../target/i386/cpu.c/x86_cpu_common_class_init(7952) tid=[34380] enter!

此处,我将函数调用的嵌套关系通过缩进方式来表示,这样便于理解各层级的函数调用关系。

首先,我们需要查找字典中 “machine” 作为键值对应的哈希表值条目。

函数 g_hash_table_foreach () 是 GLib 库的哈希表函数,定义如下:

void g_hash_table_foreach (GHashTable *hash_table, GHFunc func, gpointer user_data);

其中,

hash_table:要遍历的哈希表。

func:对于哈希表中的每一个键值对,都会调用这个函数。该函数的原型是GHFunc,它的定义是void func(gpointer key, gpointer value, gpointer user_data);。

key:当前遍历到的键。

value:当前遍历到的值。

user_data:传递给func的用户数据。

结果显示,第一个条目是:

huedbg: ../qom/object.c/object_class_foreach_tramp(1121) tid=[34380] type->name=[Dhyana-v2-x86_64-cpu]

因此,第一个进入 type_initialize() 的类型条目就是名为 “Dhyana-v2-x86_64-cpu” 的类型实现。

系统查找发现没有名为 “Dhyana-v2-x86_64-cpu” 的类实现,因此需要新建一个,调试输出如下:

huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[Dhyana-v2-x86_64-cpu] new ti->class

接下来如果 “Dhyana-v2-x86_64-cpu” 类型有父节点,则对其也真实化,调试输出如下:

huedbg: ../qom/object.c/type_initialize(334) tid=[34380] try parent->name=[x86_64-cpu]

以上两句调试输出在同一层函数调用中输出,因此,在缩进格式上我们放在同层缩进。

接下来,进入父节点的正式化函数调用 type_realize(parent),调试输出如下:

huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu] new ti->class

注意,此处的 name=[x86_64-cpu] 与上层函数中的 try parent->name=[x86_64-cpu] 是一致的,方便调试查对。

据此可知,父节点是名为 “x86_64-cpu” 的类型实现,系统查找后发现没有此名字的类实现,因此需要新建一个,调试输出如下:

huedbg: ../qom/object.c/type_initialize(327) tid=[34380] name=[x86_64-cpu] new ti->class

如此反复,直到类型实现的类指针不为空,即类型实现有类实例,此时函数 type_realize() 直接返回,调试输出如下:

huedbg: ../qom/object.c/type_initialize(305) tid=[34380] name=[interface] class OK return

如果没有父节点,函数 type_realize() 最后会检查是否设置了 class_init(),如果设置了则执行该类初始化函数,调试输出如下:

huedbg: ../qom/object.c/type_initialize(396) tid=[34380] name=[object] ti->class_init before
                    huedbg: ../qom/object.c/object_class_init(2881) tid=[34380] enter
                    huedbg: ../qom/object.c/object_class_init(2884) tid=[34380] return
                huedbg: ../qom/object.c/type_initialize(398) tid=[34380] name=[object] ti->class_init after

如果有父节点,则需要通过函数 type_initialize_interface() 将本节点通过界面类型实现与父节点关联起来,调试输出如下:

huedbg: ../qom/object.c/type_initialize(374) tid=[34380] try type_initialize_interface(device,vmstate-if,vmstate-if])

此外,需要同步执行父节点中的 class_base_init() 初始化函数,调试输出如下:

huedbg: ../qom/object.c/type_initialize(388) tid=[34380] name=[device] parent->class_base_init before
            huedbg: ../hw/core/qdev.c/device_class_base_init(724) tid=[34380] enter
            huedbg: ../hw/core/qdev.c/device_class_base_init(731) tid=[34380] return
        huedbg: ../qom/object.c/type_initialize(390) tid=[34380] name=[device] parent->class_base_init after

这样,一张使用类实现来表示的机器设备关系图就建立好了。

type_initialize_interface()

函数 type_initialize_interface() 定义如下:

static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
                                      TypeImpl *parent_type)
{
    InterfaceClass *new_iface;
    TypeInfo info = { };
    TypeImpl *iface_impl;

    info.parent = parent_type->name;
    info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
    info.abstract = true;

    iface_impl = type_new(&info);
    iface_impl->parent_type = parent_type;
    type_initialize(iface_impl);
    g_free((char *)info.name);

    new_iface = (InterfaceClass *)iface_impl->class;
    new_iface->concrete_class = ti->class;
    new_iface->interface_type = interface_type;

    ti->class->interfaces = g_slist_append(ti->class->interfaces, new_iface);
}

从代码中可知,对于抽象界面类实现,其名字格式为 “[本节点]::[界面节点]”。因此,类实现名为 “device::vmstate-if” 是一个抽象界面类实现。

至此,我们对创建一个实例 “q35” 目标机器的类实现 (TypeImpl) 全过程做了分析,并直观展示了目标机器使用类实现字典的表示方式。


总结

以上分析了 QEMU 系统仿真实例 “q35” 目标机器的使用类实现(TypeImpl)的表示方式,接下来我们将继续在系统中完成实例 “q35” 目标机器的创建工作。