QEMU的模块化

来源:互联网 发布:域名停放 编辑:程序博客网 时间:2024/05/02 04:30

模块划分

    QEMU的也使用了类似LINUX内核中的模块的思想,对代码进行模块化开发。与内核的模块用法不太一样的是,QEMU将模块进行了类别划分,同一个类别的模块的初始化函数会在同一个时机被遍历调用。此外,只有MODULE_INIT_BLOCK支持像内核一样的动态模块化。QEMU模块类型的划分如下:

1
2
3
4
5
6
7
typedef enum {
    MODULE_INIT_BLOCK,      //块设备模块
    MODULE_INIT_MACHINE,    //Machine模块
    MODULE_INIT_QAPI,
    MODULE_INIT_QOM,        //QEMU对象模型模块,通常一个模块是一个类型
    MODULE_INIT_MAX
} module_init_type;


模块注册

    完成各类模块初始化函数注册的宏:

1
2
3
4
#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
#define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
#define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
#define type_init(function) module_init(function, MODULE_INIT_QOM)

    上面的几个宏就是将模块的初始化函数加入对应类型的链表中。模块的分类的实现是通过链表实现的,每个类型有一个链表,每个模块都会注册一个对应的链表节点,链表节点保存的是一个模块的初始化函数指针以及模块类型。


    上面的宏的实现共同依赖module_init宏:

1
2
3
4
5
#define module_init(function, type)                                         \
static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
{                                                                           \
    register_module_init(function, type);                                   \
}

    这个宏为每个模块的初始化函数实现了一个对应的静态函数,里面完成的是模块初始化函数的注册动作,即将模块初始化函数加入对应类型的链表中。GCC扩展属性__attribute__((constructor))保证了这个函数会在main函数之前被调用,所以在main函数调用之前,所有模块的初始化函数都被注册到了对应类型的链表中。

模块初始化

    

    module_call_init函数负责根据模块类型遍历调用模块的初始化函数。module_call_init概要实现:

1
2
3
4
5
6
void module_call_init(module_init_type type)
{
    QTAILQ_FOREACH(e, l, node) {    //遍历该类型的队列
        e->init();                  //调用模块注册的初始化函数
    }
}

    从main函数中可以看到,这几个模块的初始化书序为QOM——>MACHINE——>BLOCK,如下:

1
2
3
4
5
6
7
main()
    module_call_init(MODULE_INIT_QOM);             //初始化WOM
    module_call_init(MODULE_INIT_MACHINE);         //初始化QOM
  
    bdrv_init_with_whitelist();
        bdrv_init();
            module_call_init(MODULE_INIT_BLOCK);   //初始化BLOCK

最近在学习qemu的代码,在这里整理一下记录,希望一起探讨共同进步,恳请指正。转载请注明出处:http://blog.csdn.net/fenglinyixuan
0 0
原创粉丝点击