QEMU学习笔记(2020-12-03)

QEMU学习笔记

1 QEMU构建系统架构

1.1 Makefiles

QEMU 构建系统需要使用 GNU make。

QEMU 当前支持 VPATH 和非 VPATH 构建,因此有三种通用方式调用 configure 并执行构建。

VPATH,完全在 QEMU 源码树之外构建产品

$ cd ../
$ mkdir build
$ cd build
$ ../qemu/configure
$ make

VPATH,在 QEMU 源码树的一个子目录中构建产品

$ mkdir build
$ cd build
$ ../configure
$ make

非 VPATH,在任何地方构建产品

$ ./configure
$ make

QEMU 的维护者通常建议开发者使用 VPATH 构建。QEMU 的补丁期待确保 VPATH 构建依然有效。

1.2 模块结构

QEMU 构建系统有大量的重要输出:

  • 工具 - qemu-img,qemu-nbd,qga (guest agent),等等
  • 系统模拟器 - qemu-system-$ARCH
  • 用户空间模拟器 - qemu-$ARCH
  • 单元测试

源码是高度模块化的,分割多个文件,以便尽可能少地重复编译所有这些组件。可以认为是两个不同的文件组,包括独立于 QEMU 仿真目标的文件和依赖于QEMU 仿真目标的文件组。

独立于仿真目标的文件集合中是各种通用辅助代码,比如错误处理基础设施,标准数据结构,平台移植性封装函数,等等。这些代码可以只被编译一次,而把它们的 .o 文件链接到所有的输出二进制文件。

依赖于仿真目标的文件集合中是 CPU 模拟,设备模拟和许多胶水代码。这有时还不得不编译多次,为每个目标编译一次。

所有二进制文件都用到的实用代码被编译为一个称为 libqemuutil.a 静态包,它会被链接进所有的二进制文件。为了提供只有一部分二进制文件需要的钩子,libqemuutil.a 中的代码可能依赖于其它不完全由 QEMU 二进制实现的函数。为了处理这种情况,还有另一个称为 libqemustub.a 的库,它为所有这些函数提供了 dummy stubs。如果没有真正的实现,则它们将被延迟链接进二进制中。以这种方式,libqemustub.a 静态库可以被看作一个弱符号概念的可移植实现。所有的二进制文件应该同时链接 libqemuutil.a 和 libqemustub.a。比如

 qemu-img$(EXESUF): qemu-img.o ..snippet.. libqemuutil.a libqemustub.a

1.3 目标变量命名

QEMU 用约定变量来列出不同的目标文件组的。它们的命名约定为 $PREFIX-obj-y。比如,libqemuutil.a 文件将与变量 util-obj-y 列出的所有目标文件链接。因此,比如,util/Makefile.obj 将包含一系列看起来像这样的定义:

  util-obj-y += bitmap.o bitops.o hbitmap.o
  util-obj-y += fifo8.o
  util-obj-y += acl.o
  util-obj-y += error.o qemu-error.o

当有一个目标文件需要基于主机系统的一些特性有条件地构建时,配置脚本将条件定义一个变量。比如,在 Windows 上它将定义 $(CONFIG_POSIX) 值为 'n',而 $(CONFIG_WIN32) 值为 'y'。现在可以在列出目标文件时使用配置变量了。比如,

  util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
  util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o

在 Windows 上被扩展为

  util-obj-y += oslib-win32.o qemu-thread-win32.o
  util-obj-n += oslib-posix.o qemu-thread-posix.o

由于 libqemutil.a 被链接进 $(util-obj-y) ,在 Windows 平台构建中,$(util-obj-n) 中列出的 POSIX 特有文件被忽略。

2 模块的注册与加载

2.1 模块的注册

QEMU 4.2.0 版本的入口在 vl.cmain函数中,其中在vl.c的 2885 行是module_call_init(MODULE_INIT_QOM);

module_call_initinclude/qemu/module.h中声明,在util/module.c中定义,其作用是遍历init_type_list[MODULE_INIT_QOM]调用所有已注册 QOM(QEMU Object Module) 模块的init函数,完成 QOM 模块的初始化。

QOM 模块的注册在每个模块文件末尾的type_init中进行,type_init通过include/qemu/module.h#module_init宏定义的__attribute__((constructor))将注册函数转换成构造函数,在运行main入口函数之前完成注册。

hw/virtio/virtio-blk-pci.c为例,module_call_init会调用init,而init实际指向virtio_blk_pci_register, virtio_blk_pci_register最终会将设备对应的TypeImpl注册到哈希表中(以TypeInfo的name属性为索引)

2.2 参数解析

两次循环中解析argv,将解析结果保存到QemuOpts链表中

2.3 模块加载

1. 在main函数中会遍历指定的-device参数,然后调用device_init_func来做设备的初始化。

2. 会依次调用device_init_func-> qdev_device_add -> object_new -> object_initialize_with_type。主要的初始化工作都是在object_initialize_with_type中完成的。

3. 首先会调用type_initialize完成类的初始化。在类的初始化中会设置类的realize回调函数为virtio_balloon_pci_realize。该函数在做类对象的实例化的时候会调用。

4. 之后会调用object_init_with_type做类对象的初始化。会递归从父对象开始执行instance_init。TYPE_DEVICE的instance_init函数为device_initfn。该函数调用执行了object_property_add_bool增加了三个属性。其中realized属性是当设置了对象真正创建的时候调用的。其set回调函数设置为device_set_realized。任何一个设备创建的时候都会调用该函数。

image

5. 设备类和对象实例初始化完成后会回到qdev_device_add函数,接下来就会进行具体的设备实现过程。

6. 调用object_property_set_bool将realized属性设置为true,从而会调用刚才设置的回调函数device_set_realized。

7. 会首先调用DeviceClass的realize函数即virtio_pci_dc_realize。该函数是在virtio_pci_class_init中设置的。

image

8. 父类的realize函数会一次调用子类的realize函数。接着会调用PCIDeviceClass的realize函数即pci_qdev_realize。

9. 然后依次调用VirtioPCIClass、VirtioBalloonPCIClass的realize函数。从而实现了VirtioBalloonPCI设备的创建。最后还需要创建VirtioBalloon设备,将其挂载到PCI总线上。

10. 即依次调用VirtioDeviceClass、VirtioBalloonDeviceClass的realize函数。VirtioBalloon设备的具体实现就是在函数virtio_balloon_device_realize中。

整个流程如下图所示,类之间的调用流则如类继承关系图中红线所示。

image

在virtio_balloon_device_realize中,调用virtio_add_queue为设备添加了三个virtqueue。其中两个的回调处理函数为virtio_ballon_handle_output,另一个是virtio_balloon_receive_stats。从而构建了从设备的输入输出通道,以及当收到输入输出信息时调用的回调处理函数。

image

至此设备创建完成,但是还差最后一步将设备挂载到virtio总线上去。该步骤是在函数virtio_device_realize中实现的。该函数调用vdc->realize创建了具体设备后,会调用virtio_bus_device_plugged,该函数的作用就是将virtio设备插入到virtio总线。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341

推荐阅读更多精彩内容