QEMU的QOM

Posted powerrailgun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QEMU的QOM相关的知识,希望对你有一定的参考价值。


链接: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

以上是关于QEMU的QOM的主要内容,如果未能解决你的问题,请参考以下文章

我有.c源代码,如何在qemu中粘帖或者导入啊?

Qemu 远程代码执行漏洞(CVE-2017-2620)

使用QEMU调试Linux内核代码

如何让qemu产生外部中断并跳转到isr(裸机代码)

QEMU多进程(Multi-process QEMU)及vfio-user应用

QEMU多进程(Multi-process QEMU)及vfio-user应用