QEMU源码全解析 —— virtio(10)

88 篇文章 19 订阅
本文详细解析了QEMU中virtio_balloon_pci_realize函数,介绍了如何通过VIRTIO_BALLOON_PCI宏将设备转换为VirtIOBalloonPCI类型,并详细阐述了DEVICE宏的展开过程,最后提到了qdev_realize函数的主要作用,包括设备挂载到virtio总线及设备具现化。
摘要由CSDN通过智能技术生成

接前一篇文章:

realize函数 parent_dc_realize函数
DeviceClass virtio_pci_dc_realize
PCIDeviceClass virtio_pci_realize
VirtioPCIClass virtio_balloon_pci_realize pci_qdev_realize

上一回开始,沿着device_set_realized() -> pci_qdev_realize() -> virtio_pci_realize()这一调用线,对于virtio_pci_realize函数进行了详细解析。最后,讲到virtio_pci_realize函数的最后一步调用了virtio_balloon_pci_realize函数。本回就来对于virtio_balloon_pci_realize函数进行解析。

virtio_balloon_pci_realize函数在hw/ virtio /virtio-balloon-pci.c中,如下:

  1. static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
  2. {
  3. VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
  4. DeviceState *vdev = DEVICE(&dev->vdev);
  5. vpci_dev->class_code = PCI_CLASS_OTHERS;
  6. qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
  7. }

virtio_balloon_pci_realize函数首先通过VIRTIO_BALLOON_PCI宏将VirtIOPCIProxy类型的设备转换为VirtIOBalloonPCI设备,相当于从一个父类转换为一个子类。代码片段如下:

    VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);

VIRTIO_BALLOON_PCI的具体定义如果在 QEMU 源码根目录下搜索是搜不到的,需要进行转换才可以。相关代码在hw/virtio/virtio-balloon-pci.c中,如下:

  1. /*
  2. * virtio-balloon-pci: This extends VirtioPCIProxy.
  3. */
  4. #define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base"
  5. DECLARE_INSTANCE_CHECKER(VirtIOBalloonPCI, VIRTIO_BALLOON_PCI,
  6. TYPE_VIRTIO_BALLOON_PCI)

这段代码最终展开为:

  1. static inline G_GNUC_UNUSED VirtIOBalloonPCI* VIRTIO_BALLOON_PCI(const void *obj)
  2. {
  3. return OBJECT_CHECK(VirtIOBalloonPCI, obj, "virtio-balloon-pci-base");
  4. }
  1. static inline G_GNUC_UNUSED VirtIOBalloonPCI* VIRTIO_BALLOON_PCI(const void *obj)
  2. {
  3. return ((VirtIOBalloonPCI*)object_dynamic_cast_assert ((ObjectClass *)(obj), ("virtio-balloon-pci-base"), __FILE__, __LINE__, __func__));
  4. }

接下来,得到设备VirtIOBalloonPCI的VirtIOBalloon部分,这就是实际的virtio balloon设备了。代码片段如下:

    DeviceState *vdev = DEVICE(&dev->vdev);

和VIRTIO_BALLOON_PCI一样,DEVICE的具体定义如果在QEMU源码根目录下搜索是搜不到的,需要进行转换才可以。相关代码在include/hw/qdev-core.h中,如下:

  1. #define TYPE_DEVICE "device"
  2. OBJECT_DECLARE_TYPE(DeviceState, DeviceClass, DEVICE)

OBJECT_DECLARE_TYPE宏的定义在include/qom/object.h中,如下:

  1. /**
  2. * OBJECT_DECLARE_TYPE:
  3. * @InstanceType: instance struct name
  4. * @ClassType: class struct name
  5. * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators
  6. *
  7. * This macro is typically used in a header file, and will:
  8. *
  9. * - create the typedefs for the object and class structs
  10. * - register the type for use with g_autoptr
  11. * - provide three standard type cast functions
  12. *
  13. * The object struct and class struct need to be declared manually.
  14. */
  15. #define OBJECT_DECLARE_TYPE(InstanceType, ClassType, MODULE_OBJ_NAME) \
  16. typedef struct InstanceType InstanceType; \
  17. typedef struct ClassType ClassType; \
  18. \
  19. G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstanceType, object_unref) \
  20. \
  21. DECLARE_OBJ_CHECKERS(InstanceType, ClassType, \
  22. MODULE_OBJ_NAME, TYPE_##MODULE_OBJ_NAME)

代入上边的值,初步展开为:

  1. typedef struct DeviceState DeviceState;
  2. typedef struct DeviceClass DeviceClass;
  3. G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
  4. DECLARE_OBJ_CHECKERS(DeviceState, DeviceClass, DEVICE, TYPE_DEVICE)

DECLARE_OBJ_CHECKERS宏的定义也在include/qom/object.h中,如下:

  1. /**
  2. * DECLARE_OBJ_CHECKERS:
  3. * @InstanceType: instance struct name
  4. * @ClassType: class struct name
  5. * @OBJ_NAME: the object name in uppercase with underscore separators
  6. * @TYPENAME: type name
  7. *
  8. * Direct usage of this macro should be avoided, and the complete
  9. * OBJECT_DECLARE_TYPE macro is recommended instead.
  10. *
  11. * This macro will provide the three standard type cast functions for a
  12. * QOM type.
  13. */
  14. #define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
  15. DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
  16. \
  17. DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)

因此,上式进一步展开为:

  1. typedef struct DeviceState DeviceState;
  2. typedef struct DeviceClass DeviceClass;
  3. G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
  4. DECLARE_INSTANCE_CHECKER(DeviceState, DEVICE, TYPE_DEVICE)
  5. DECLARE_CLASS_CHECKERS(DeviceClass, DEVICE, TYPE_DEVICE)

DECLARE_INSTANCE_CHECKER和DECLARE_CLASS_CHECKERS宏也都是在include/qom/object.h中,定义分别如下:

  1. /**
  2. * DECLARE_INSTANCE_CHECKER:
  3. * @InstanceType: instance struct name
  4. * @OBJ_NAME: the object name in uppercase with underscore separators
  5. * @TYPENAME: type name
  6. *
  7. * Direct usage of this macro should be avoided, and the complete
  8. * OBJECT_DECLARE_TYPE macro is recommended instead.
  9. *
  10. * This macro will provide the instance type cast functions for a
  11. * QOM type.
  12. */
  13. #define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
  14. static inline G_GNUC_UNUSED InstanceType * \
  15. OBJ_NAME(const void *obj) \
  16. { return OBJECT_CHECK(InstanceType, obj, TYPENAME); }
  1. /**
  2. * DECLARE_CLASS_CHECKERS:
  3. * @ClassType: class struct name
  4. * @OBJ_NAME: the object name in uppercase with underscore separators
  5. * @TYPENAME: type name
  6. *
  7. * Direct usage of this macro should be avoided, and the complete
  8. * OBJECT_DECLARE_TYPE macro is recommended instead.
  9. *
  10. * This macro will provide the class type cast functions for a
  11. * QOM type.
  12. */
  13. #define DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME) \
  14. static inline G_GNUC_UNUSED ClassType * \
  15. OBJ_NAME##_GET_CLASS(const void *obj) \
  16. { return OBJECT_GET_CLASS(ClassType, obj, TYPENAME); } \
  17. \
  18. static inline G_GNUC_UNUSED ClassType * \
  19. OBJ_NAME##_CLASS(const void *klass) \
  20. { return OBJECT_CLASS_CHECK(ClassType, klass, TYPENAME); }

因此,上式进一步展开为:

  1. typedef struct DeviceState DeviceState;
  2. typedef struct DeviceClass DeviceClass;
  3. G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
  4. static inline G_GNUC_UNUSED DeviceState *DEVICE(const void *obj)
  5. {
  6. return OBJECT_CHECK(DeviceState, obj, TYPE_DEVICE);
  7. }
  8. static inline G_GNUC_UNUSED DeviceClass* DEVICE_GET_CLASS(const void *obj)
  9. {
  10. return OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE);
  11. }
  12. static inline G_GNUC_UNUSED DeviceClass* DEVICE_CLASS(const void *klass)
  13. {
  14. return OBJECT_CLASS_CHECK(DeviceClass, klass, TYPE_DEVICE);
  15. }

再把TYPE_DEVICE的实际值代入,最终得到:

  1. typedef struct DeviceState DeviceState;
  2. typedef struct DeviceClass DeviceClass;
  3. G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
  4. static inline G_GNUC_UNUSED DeviceState *DEVICE(const void *obj)
  5. {
  6. return OBJECT_CHECK(DeviceState, obj, "device");
  7. }
  8. static inline G_GNUC_UNUSED DeviceClass* DEVICE_GET_CLASS(const void *obj)
  9. {
  10. return OBJECT_GET_CLASS(DeviceClass, obj, "device");
  11. }
  12. static inline G_GNUC_UNUSED DeviceClass* DEVICE_CLASS(const void *klass)
  13. {
  14. return OBJECT_CLASS_CHECK(DeviceClass, klass, "device");
  15. }

这里就不再深入展开了。

总之,通过DEVICE宏得到设备VirtIOBalloonPCI的VirtIOBalloon部分,这就是实际的virtio balloon设备了。

    DeviceState *vdev = DEVICE(&dev->vdev);

539e3e833e090bc7edd784e48609c32a.png

接下来,调用hw/core/qdev.c中的qdev_realize函数。代码片段如下:

    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);

qdev_realize函数代码如下:

  1. bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
  2. {
  3. assert(!dev->realized && !dev->parent_bus);
  4. if (bus) {
  5. if (!qdev_set_parent_bus(dev, bus, errp)) {
  6. return false;
  7. }
  8. } else {
  9. assert(!DEVICE_GET_CLASS(dev)->bus_type);
  10. }
  11. return object_property_set_bool(OBJECT(dev), "realized", true, errp);
  12. }

qdev_realize函数主要做了两件事情:

1)设置virtio balloon设备的总线为VirtIOPCIProxy设备中的bus成员,也就是把这个virtio balloon设备挂到virtio总线上。

2)调用object_property_bool函数,将virtio balloon设备具现化,这会导致virtio_device_realize函数的执行。

注:实际上在老版本中,并没有qdev_realize函数,它里边的两项工作是直接在virtio_balloon_pci_realize函数中完成的。

7cf531c21d7f91e255f3e058124ff81f.png

virtio_device_realize函数在hw/virtio/virtio.c中,代码如下:

  1. static void virtio_device_realize(DeviceState *dev, Error **errp)
  2. {
  3. VirtIODevice *vdev = VIRTIO_DEVICE(dev);
  4. VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev);
  5. Error *err = NULL;
  6. /* Devices should either use vmsd or the load/save methods */
  7. assert(!vdc->vmsd || !vdc->load);
  8. if (vdc->realize != NULL) {
  9. vdc->realize(dev, &err);
  10. if (err != NULL) {
  11. error_propagate(errp, err);
  12. return;
  13. }
  14. }
  15. virtio_bus_device_plugged(vdev, &err);
  16. if (err != NULL) {
  17. error_propagate(errp, err);
  18. vdc->unrealize(dev);
  19. return;
  20. }
  21. vdev->listener.commit = virtio_memory_listener_commit;
  22. vdev->listener.name = "virtio";
  23. memory_listener_register(&vdev->listener, vdev->dma_as);
  24. QTAILQ_INSERT_TAIL(&virtio_list, vdev, next);
  25. }

对于virtio_device_realize函数的深入解析,请看下回。

举报

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