KVM分为两部分,User态部分在Qemu中,Kernel态部分集成到了Linux的代码里作为Kernel Module的形式对上提供服务。由于整个大的流程还是在QEMU里面的,所以本篇先介绍一下设备注册的相关信息。
Reference: Mctrain’s Blog: Qemu中的设备注册
QEMU Object Module
其发展如下图(从Mactrain’s Blog里面摘过来的,原来的PDF链接失效了)
在kvm-all.c
文件的最后,我们可以发现有个type_init(kvm_type_init)
, 其中type_init
的定义在
1 | 35 |
可以发现最终会变成do_qemu_init_kvm_type_init(void) { ... }
,其中
register_module_init
的实现在对应的C文件↓
1 | 33 static ModuleTypeList init_type_list[MODULE_INIT_MAX]; |
find_type
会调用init_lists
进行链表的初始化。
register_module_init
里面会malloc一个新的ModuleEntry
并插入对应init_type_list[Module_Init_Type]
链表中,
Entry的初始化函数指针init
和类型type
会被赋值为传进来的参数。
Module_Init_Type
稍后再说,这里主要强调一下__attribute__((constructor))
,这个是GCC提供的特性,能够让函数在
main()
执行前被执行。所以这些代码都在main()
之前执行了!
关于__attribute__((constructor))
的介绍可以参考这篇: C Language Constructors and Destructors with GCC。
因此在QEMU运行之前,全局的所有Module对应的Entry就已经被插入到init_type_list
中。
KVM_accel_module
1 | 42 typedef enum { |
Qemu里面一共就4种Module: BLOCK
,OPT
,QOM
,TRACE
,在include/qom/object.h
中详细介绍了如何使用已有的接口来实现自己的Module_Init_Type
, 所以根据上面的分析,
在Main函数执行之前,我们就获得了一个这样的链表↓:
1 | init_type_list: init_type_list[MODULE_INIT_QOM]: |
其中kvm_accel_type
就是QOM的其中一个ModuleEntry:
1 | 2615 static const TypeInfo kvm_accel_type = { |
根据上面的分析,kvm 通过type_init
这个洪在init_type_list[MODULE_INIT_QOM]
链表中加入了一个自己的ModuleEntry
,其中ModuleEntry
的init
被初始化为
kvm_type_init
, 进而注册了kvm_accel_type
这个module的信息。
类似的,在QEMU运行的时候只要挨着调用这些List里面Entry的 .init函数就会挨着初始化所有的Module.