链接:https://www.cnblogs.com/powerrailgun/p/12653864.html
在上面这个链接中大概知道了相关设备的初始化流程。但是如果要深入其中,分析各个设备的关系,在QEMU是如何管理的,那么就有必要分析QOM了。
QOM是对QEMU中各种资源的抽象和管理,比如这里说到的设备的创建,销毁,配置等。
一、设备模块的注册。
在hw/
目录下面的几乎每一个模块的C文件里面, 都有包含有以下的声明:
type_init(xxxxxxxxx)
例如,hw/virtio/virtio-pci.c
中有:
type_init(virtio_pci_register_types)
深入type_init()
,可以发现type_init
是一个macro,在include/qemu/module.h
中:
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define module_init(function, type) \
static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
{ \
register_module_init(function, type); \
}
typedef enum {
MODULE_INIT_BLOCK,
MODULE_INIT_OPTS,
MODULE_INIT_QAPI,
MODULE_INIT_QOM,
MODULE_INIT_TRACE,
MODULE_INIT_MAX
} module_init_type;
这里的__attribute__
属性是需要关注的,表示后面的do_qemu_init_##
函数会先于vl.c的main()
函数执行(很神奇吧!)
那么结合起来看的话,也就是说do_qemu_init_virtio_pci_register_types()
函数会先于main()执行。那这个函数做了什么呢?
从上面看出,它调用的是register_module_init(function, type);
函数,
void register_module_init(void (*fn)(void), module_init_type type)
{
ModuleEntry *e;
ModuleTypeList *l;
e = g_malloc0(sizeof(*e));
e->init = fn;
e->type = type;
l = find_type(type);
QTAILQ_INSERT_TAIL(l, e, node);
}
static ModuleTypeList *find_type(module_init_type type)
{
init_lists();
return &init_type_list[type];
}
static ModuleTypeList init_type_list[MODULE_INIT_MAX];
这里的init_type_list
是一个全局的数组,那么结合以上的分析就是将type_init()
初始化的对象放到全局的init_type_list[MODULE_INIT_QOM]
这个list上。
综上所述,在vl.c的main()执行之前,所有hw/
中的设备对象都已经准备好了。
那么何时调用呢?把这些对象加入到init_type_list后,在mian执行,注意,以下流程就说的是在main()中的执行流程了。
module_call_init(MODULE_INIT_QOM);
调用这些对象.
定义如下:
void module_call_init(module_init_type type)
{
ModuleTypeList *l;
ModuleEntry *e;
l = find_type(type);
QTAILQ_FOREACH(e, l, node) {
e->init();
}
}
可以看出了,这里会调用每个对象的init()
函数,回头看看上面的,type_init()
就可以知道,这里的init()函数实际上是type_init()
中传入的函数指针,例如:
type_init(virtio_pci_register_types)
那么,init()对应的就是virtio_pci_register_types
,从这里可以推及到其他所有的对象。
然后再继续调用virtio_pci_register_types
里面的其他函数。如下:
static void virtio_pci_register_types(void)
{
/* Base types: */
type_register_static(&virtio_pci_bus_info);
type_register_static(&virtio_pci_info);
}
type_register_static()
遵循着这样的流程:
type_register_static --> type_register --> type_register_internal --> type_new