文章目录
- 系列文章目录
- 第二章 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” 目标机器的创建工作。