QEMU建模之设备创建总体流程

本文详细介绍了QEMU中设备创建的过程,以中断控制器openpic为例,从main函数之前的type_init开始,通过module_init函数执行typeInfo到typeImpl的转换,再到main函数中调用module_call_init,最后在特定单板中利用qdev_create函数创建设备,完成设备初始化。
摘要由CSDN通过智能技术生成

(这里的设备创建以中断控制器即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)); 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值