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.