QEMU设备模拟

来源:互联网 发布:mac os彻底卸载程序 编辑:程序博客网 时间:2024/05/18 02:19

备模拟目的

我们好像不会干一件事而毫无目的,就算不停刷微信朋友圈也是为了打发你无聊的时间。
其实最装B的回答是:设备模拟的目的就是模拟设备。这话是屁话,不过也能说明些什么,确实是模拟设备,用软件的方式提供硬件设备具备的功能。
对于和PC机交互的硬件设备,主要要干两件事,一是提供IRQ中断,二是响应IO输入输出。IO包括PIO/MMIO/DMA等(DMA算不算IO?)
以i8254.c实现的pit为例,主要提供了IRQ注入和PIO响应,见初始化函数pit_initfn:

这里的pit_ioport_ops,主要注册GUEST操作系统读写PIO时候的回调函数。

模块注册

QEMU要模拟模块那么多,以程序员的喜好,至少得来一套管理这些模拟设备模块的接口,以示设计良好。
QEMU将被模拟的模块分为了四类:

  • BLOCK
    比如磁盘IO就属于BLOCK类型,e.g: block_init(bdrv_qcow2_init); block_init(iscsi_block_init);
  • MACHINE
    PC虚拟machine_init(pc_machine_init); XEN半虚拟化machine_init(xenpv_machine_init); MIPS虚拟machine_init(mips_machine_init);
  • QAPI
    QEMU GUEST AGENT模块里面会执行QAPI注册的回调
  • QOM
    QOM树大枝多,儿孙满堂,应该是这里面最复杂的一个,我们重点介绍。
    e.g:

注册QOM设备的时候,使用QEMU提供的宏,type_init宏进行注册:

这和写LINUX驱动类似,一般写在一个模块实现文件的最底部,以pit为例,写的是type_init(pit_register_types)展开后为:

那么,这个do_qemu_init_pit_register_types何时调用?
在gcc里面,给函数加上__attribute__((destructor)),表示此函数需要在main开始前自动调用,测试调用顺序是: 全局对象构造函数 -> __attribute__((constructor)) -> main -> 全局对象析构函数 -> __attribute__((destructor))。
调用register_module_init就是将pit_register_types回调函数插入util\module.c里定义的init_type_list[MODULE_INIT_QOM]链表内。

通过下面main函数的部分代码可以看出,模块初始化顺序是QOM->MACHINE->BLOCK,至于QAPI,在这个流程里没看到。

在main函数进来的时候,首先调用module_call_init(MODULE_INIT_QOM);

此module_call_init将依次调用注册的回调,如PIT的pit_register_types:

pit_register_types又进一步调用type_register_static -> type_register -> type_register_internal,这个函数完成的功能其实只是在qom\object.c的type_table里插入了一个HASH键值对,以TypeInfo的name为KEY,malloc了一个TypeInfo结构的超集TypeImpl为VALUE,在以name为KEY回溯parent时需要TypeImpl,其实这个hash也可以做成一个tree。

0 0