(这里的设备创建以中断控制器即openpic为例)
1.main函数之前执行type_init
1> 在vl.c文件的main函数执行前会先执行 module_init的函数。因为该函数使用GNC中attribute属性constructor即构造函数属性,该属性的设置使得该函数在main函数之前被执行。函数原型如下:其路径为G:\qemu-3.1.0-rc0\hw\intc\openpic.c
static void openpic_register_types(void)
{
type_register_static(&openpic_info);
}
type_init(openpic_register_types)
2> type_init函数的宏定义为G:\qemu-3.1.0-rc0\include\qemu\module.h
#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
#define opts_init(function) module_init(function, MODULE_INIT_OPTS)
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define trace_init(function) module_init(function, MODULE_INIT_TRACE)
#define module_init(function, type) \
static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
{ \
register_module_init(function, type); \
}
3> register_module_init函数原型在G:\qemu-3.1.0-rc0\include\qemu\module.c文件中
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);
}
该函数首先动态分配指向ModuleEntry类型的结点,使该节点中的init函数指向openpic这个设备的openpic_register_types函数,其类型为MODULE_INIT_QOM,再将该节点插入链表中。具体执行过程在G:\qemu-3.1.0-rc0\include\qemu\queue.h文件中,执行过程 如下:
#define QTAILQ_INSERT_TAIL(head, elm, field) do { \//这是一个双向链表
(elm)->field.tqe_next = NULL; \//使插入结点的下一节点指向空
(elm)->field.tqe_prev = (head)->tqh_last; \//使插入结点的前一结点指向原链表的尾结点
*(head)->tqh_last = (elm); \//使链表的尾结点的下一节点指针指向指向这个
新插入的结点
(head)->tqh_last = &(elm)->field.tqe_next; \//链表的尾指针指向新插入结点
} while (/*CONSTCOND*/0)
现在已经将将其存储到链表中了。
2.main函数中,调用module_call_init函数,完成TypeInfo到TypeImpl的转换
1> main函数中调用module_call_init函数,路径为G:\qemu\qemu-3.1.0-rc0\vl.c
module_call_init(MODULE_INIT_QOM);
2> 执行moduleEntry节点中存储的init函数,路径为G:\qemu-3.1.0-rc0\util\module.c
void module_call_init(module_init_type type)
{
ModuleTypeList *l;
ModuleEntry *e;
l = find_type(type); //首先找到该类型的链表的头指针
QTAILQ_FOREACH(e, l, node) { //执行所存储的结点的init函数,在openpic中对应
//openpic_register_types函数
e->init();
}
}
3> openpic_register_types函数的执行,函数所在文件为G:\qemu-3.1.0-rc0\hw\intc\openpic.c
//首先执行
static void openpic_register_types(void)
{
type_register_static(&openpic_info);
}
//函数调用
TypeImpl *type_register_static(const TypeInfo *info)
{
return type_register(info);
}
//函数调用
TypeImpl *type_register(const TypeInfo *info)
{
assert(info->parent);
return type_register_internal(info);
}
//函数调用
static TypeImpl *type_register_internal(const TypeInfo *info)
{
TypeImpl *ti;
ti = type_new(info);
type_table_add(ti); //将这个typeimpl添加到hash表中
return ti;
}
//函数调用
static TypeImpl *type_new(const TypeInfo *info)
{
TypeImpl *ti = g_malloc0(sizeof(*ti));