QEMU源码全解析40 —— Machine(10)

88 篇文章 19 订阅
本文深入探讨QEMU中的机器创建过程,分析`qemu_create_machine`函数调用,比较新老版本代码差异,涉及`object_new_with_class`与`object_new`函数,解释了ObjectClass结构及其Type成员。最终,MachineState对象被创建并用于后续设备初始化。
摘要由CSDN通过智能技术生成

接前一篇文章: QEMU源码全解析39 —— Machine(9)

本文内容参考:

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

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

特此致谢!

前边几篇文章围绕MACHINE函数的定义进行了探索,最终得到了MACHINE函数的代码,在include/hw/boards.h中,如下:

  1. static inline G_GNUC_UNUSED MachineState *MACHINE(const void *obj)
  2. {
  3. return OBJECT_CHECK(MachineState, obj, TYPE_MACHINE);
  4. }

并且得到了OBJECT_CHECK宏展开后的函数代码:

  1. static inline G_GNUC_UNUSED MachineState *MACHINE(const void *obj)
  2. {
  3. return ((MachineState*)object_dynamic_cast_assert(OBJECT(obj), ("machine"), __FILE__, __LINE__, __func__));
  4. }

现在要回过头来,看看qemu_create_machine函数(softmmu/vl.c中)的实际调用。代码片段如下:

 current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));

老版本 QEMU 代码中这一句是这样:

 current_machine = MACHINE(object_new(object_class_get_name(OBJECT_CLASS(machine_class))));

之前MACHINE函数是重点,现在其参数object_new_with_class以及object_new函数成为了关注焦点。其均在qom/object.c中,代码如下:

  1. Object *object_new(const char *typename)
  2. {
  3. TypeImpl *ti = type_get_by_name(typename);
  4. return object_new_with_type(ti);
  5. }
  1. Object *object_new_with_class(ObjectClass *klass)
  2. {
  3. return object_new_with_type(klass->type);
  4. }

可以看到,甭管是哪一个函数,最终都会调用到object_new_with_type函数。不过这里要先看看新老两个版本的差异细节,也就是怎样“殊途同归”的。

先说新版本。新版本调用的是object_new_with_class(OBJECT_CLASS(machine_class)),这个machine_class是qemu_create_machine函数第一步以下函数得到的:

MachineClass *machine_class = select_machine(qdict, &error_fatal);

这一步的细节可以参看本系列之前文章: QEMU源码全解析34 —— Machine(4)

OBJECT_CLASS是一个宏,在include/qom/object.h中定义,代码如下:

  1. /**
  2. * OBJECT_CLASS:
  3. * @class: A derivative of #ObjectClass.
  4. *
  5. * Converts a class to an #ObjectClass. Since all objects are #Objects,
  6. * this function will always succeed.
  7. */
  8. #define OBJECT_CLASS(class) \
  9. ((ObjectClass *)(class))

而ObjectClass结构的定义在include/qemu/typedefs.h中,如下:

typedef struct ObjectClass ObjectClass;

struct ObjectClass的定义在include/qom/object.h中,代码如下:

  1. /**
  2. * struct ObjectClass:
  3. *
  4. * The base for all classes. The only thing that #ObjectClass contains is an
  5. * integer type handle.
  6. */
  7. struct ObjectClass
  8. {
  9. /* private: */
  10. Type type;
  11. GSList *interfaces;
  12. const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
  13. const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];
  14. ObjectUnparent *unparent;
  15. GHashTable *properties;
  16. };

最终用到的是ObjectClass中的Type type成员。

再来看老版本。老版本调用的是object_new(object_class_get_name(OBJECT_CLASS(machine_class)))。OBJECT_CLASS宏和machine_class上边都已经说过了,object_class_get_name函数在qom/object.c中,代码如下:

  1. const char *object_class_get_name(ObjectClass *klass)
  2. {
  3. return klass->type->name;
  4. }

看一下ObjectClass结构中Type类型的定义,在include/qom/object.h中,代码如下:

  1. struct TypeImpl;
  2. typedef struct TypeImpl *Type;

从这里就可以看到,实际上Type和TypeImpl是同宗同源的,TypeImpl就是struct TYpeImpl,而Type是struct TypeImpl *。

object_new函数中还调用了type_get_by_name函数,其同样在qom/object.c中,代码如下:

  1. static TypeImpl *type_get_by_name(const char *name)
  2. {
  3. if (name == NULL) {
  4. return NULL;
  5. }
  6. return type_table_lookup(name);
  7. }

type_table_lookup函数在同文件中,代码如下:

  1. static TypeImpl *type_table_lookup(const char *name)
  2. {
  3. return g_hash_table_lookup(type_table_get(), name);
  4. }

以上过程可能比较容易乱,我们在从头捋一下。

  • 新版本

新版本调用的是object_new_with_class(OBJECT_CLASS(machine_class)) 。逐层展开如下:

object_new_with_class(OBJECT_CLASS(machine_class)) --->

object_new_with_class(((ObjectClass *)(machine_class))) --->

object_new_with_type(((ObjectClass *)(machine_class))->type)

  • 老版本

老版本调用的是object_new(object_class_get_name(OBJECT_CLASS(machine_class)))。逐层展开如下:

object_new(object_class_get_name(OBJECT_CLASS(machine_class))) --->

object_new(object_class_get_name(((ObjectClass *)(machine_class)))) --->

object_new(((ObjectClass *)(machine_class))->type->name) --->

object_new_with_type(type_get_by_name(((ObjectClass *)(machine_class))->type->name))

从两者最后(一行)代码的对比就能看得出来,新版本比旧版本省了一道事。明明ObjectClass->type可以直接获得,老版本还非得先ObjectClass->type->name再通过type_get_by_name回溯回ObjectClass->type。我看这次更新是很应该的且是要点赞的。

Machine函数最终将新建的MachineState对象返回给了current_machine。

    current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));

current_machine是一个MachineState类型的指针,其在hw/core/machine.c中定义,如下:

MachineState *current_machine;

MachineState结构的定义在include/hw/boards.h中,如下:

OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE)

OBJECT_DECLARE_TYPE宏在此不展开了,只需要知道MachineState是从struct MachineState来的:

typedef struct MachineState MachineState;

struct MachineState的定义也在include/hw/boards.h中,如下:

  1. /**
  2. * MachineState:
  3. */
  4. struct MachineState {
  5. /*< private >*/
  6. Object parent_obj;
  7. /*< public >*/
  8. void *fdt;
  9. char *dtb;
  10. char *dumpdtb;
  11. int phandle_start;
  12. char *dt_compatible;
  13. bool dump_guest_core;
  14. bool mem_merge;
  15. bool usb;
  16. bool usb_disabled;
  17. char *firmware;
  18. bool iommu;
  19. bool suppress_vmdesc;
  20. bool enable_graphics;
  21. ConfidentialGuestSupport *cgs;
  22. HostMemoryBackend *memdev;
  23. /*
  24. * convenience alias to ram_memdev_id backend memory region
  25. * or to numa container memory region
  26. */
  27. MemoryRegion *ram;
  28. DeviceMemoryState *device_memory;
  29. ram_addr_t ram_size;
  30. ram_addr_t maxram_size;
  31. uint64_t ram_slots;
  32. BootConfiguration boot_config;
  33. char *kernel_filename;
  34. char *kernel_cmdline;
  35. char *initrd_filename;
  36. const char *cpu_type;
  37. AccelState *accelerator;
  38. CPUArchIdList *possible_cpus;
  39. CpuTopology smp;
  40. struct NVDIMMState *nvdimms_state;
  41. struct NumaState *numa_state;
  42. };

至此,兜兜转转了一大圈,有关主板(Machine)的对象才创建完毕。接下来很多设备(CPU、内存等)的初始化,都是围绕着主板的对象展开的,后面会常常看到current_machine。

欲知后事如何,且看下回分解。

举报

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