QEMU源码全解析9 —— 定义一个QEMU模块(1)

88 篇文章 19 订阅
本文深入探讨了QEMU模块的创建过程,通过分析`type_init`和`module_init`宏,展示了如何在QEMU中定义和注册一个模块,如KVM。通过这些宏,模块的初始化函数被添加到特定类型的模块列表中,等待在后续的初始化阶段调用执行。
摘要由CSDN通过智能技术生成

接前一篇文章: QEMU源码全解析8 —— 初始化所有Module

本文内容参考:

《趣谈 Linux操作系统 》 —— 刘超,极客时间

QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社

特此致谢!

定义一个 QEMU 模块会调用type_init。以kvm为例,kvm模块在accel/kvm/kvm-all.c中实现。在此文件中,有以下1行代码:

type_init(kvm_type_init);

type_init是一个宏定义,在include/qemu/module.h中,代码如下:

#define type_init(function) module_init(function, MODULE_INIT_QOM)

因此,type_init(kvm_type_init)展开来为:

module_init(kvm_type_init, MODULE_INIT_QOM)

而module_init的定义在include/qemu/module.h中,代码如下:

  1. #ifdef BUILD_DSO
  2. void DSO_STAMP_FUN(void);
  3. /* This is a dummy symbol to identify a loaded DSO as a QEMU module, so we can
  4. * distinguish "version mismatch" from "not a QEMU module", when the stamp
  5. * check fails during module loading */
  6. void qemu_module_dummy(void);
  7. #define module_init(function, type) \
  8. static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
  9. { \
  10. register_dso_module_init(function, type); \
  11. }
  12. #else
  13. /* This should not be used directly. Use block_init etc. instead. */
  14. #define module_init(function, type) \
  15. static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
  16. { \
  17. register_module_init(function, type); \
  18. }
  19. #endif

由于系统中并未定义BUILD_DSO,因此实际上走的是#else分支,即以下代码:

  1. /* This should not be used directly. Use block_init etc. instead. */
  2. #define module_init(function, type) \
  3. static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
  4. { \
  5. register_module_init(function, type); \
  6. }

代入module_init(kvm_type_init, MODULE_INIT_QOM),为:

  1. static void __attribute__((constructor)) do_qemu_init_kvm_type_init(void)
  2. {
  3. register_module_init(kvm_type_init, MODULE_INIT_QOM);
  4. }

而register_module_init在util/module.c中,代码如下:

  1. void register_module_init(void (*fn)(void), module_init_type type)
  2. {
  3. ModuleEntry *e;
  4. ModuleTypeList *l;
  5. e = g_malloc0(sizeof(*e));
  6. e->init = fn;
  7. e->type = type;
  8. l = find_type(type);
  9. QTAILQ_INSERT_TAIL(l, e, node);
  10. }

又见find_type函数,上一回已经对其进行了分析。这里为了便于理解,再贴一下代码,在同文件中(其实就在register_module_init上边):

  1. static ModuleTypeList *find_type(module_init_type type)
  2. {
  3. init_lists();
  4. return &init_type_list[type];
  5. }

QTAIL_INSERT_TAIL当然还是在include/qemu/queue.h中定义,代码如下:

  1. #define QTAILQ_INSERT_TAIL(head, elm, field) do { \
  2. (elm)->field.tqe_next = NULL; \
  3. (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev; \
  4. (head)->tqh_circ.tql_prev->tql_next = (elm); \
  5. (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
  6. } while (/*CONSTCOND*/0)

这样,对于register_module_init(kvm_type_init, MODULE_INIT_QOM)来说,register_module_init函数实际是这样:

  1. void register_module_init(void (*fn)(void), module_init_type type)
  2. {
  3. ModuleEntry *e;
  4. ModuleTypeList *l;
  5. e = g_malloc0(sizeof(*e));
  6. e->init = fn; //实际上是:e->init = kvm_type_init;
  7. e->type = type; //实际上是:e->type = MODULE_INIT_QOM;
  8. l = find_type(type); //实际上是:l = find_type(MODULE_INIT_QOM);
  9. QTAILQ_INSERT_TAIL(l, e, node);
  10. }

对于type_init(kvm_type_init)来说,最终要调用到register_module_init(kvm_type_init, MODULE_INIT_QOM),也就是MODULE_INIT_QOM这种类型。属于MODULE_INIT_QOM这种类型的,有一个Module列表ModuleTypeList(上一回已分析过),列表里边是一项一项的ModuleEntry。KVM就是其中的一项,当然还有很多其他项,比如Machine、CPU等。会 初始化 每一项的init函数为参数表示的函数fn,对于KVM这个module来说,其init函数就是kvm_type_init;而对于Machine这个module来说,其init函数为machine_register_types。最终在上一回分析的module_call_init函数中实际调用这里赋值的初始化fn,进行实际的初始化工作。

下一回我们就来看看KVM的这个初始化函数kvm_type_init。

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他