接前一篇文章:
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中,如下:
- static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
- {
- VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- vpci_dev->class_code = PCI_CLASS_OTHERS;
- qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
- }
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中,如下:
- /*
- * virtio-balloon-pci: This extends VirtioPCIProxy.
- */
- #define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base"
- DECLARE_INSTANCE_CHECKER(VirtIOBalloonPCI, VIRTIO_BALLOON_PCI,
- TYPE_VIRTIO_BALLOON_PCI)
这段代码最终展开为:
- static inline G_GNUC_UNUSED VirtIOBalloonPCI* VIRTIO_BALLOON_PCI(const void *obj)
- {
- return OBJECT_CHECK(VirtIOBalloonPCI, obj, "virtio-balloon-pci-base");
- }
- static inline G_GNUC_UNUSED VirtIOBalloonPCI* VIRTIO_BALLOON_PCI(const void *obj)
- {
- return ((VirtIOBalloonPCI*)object_dynamic_cast_assert ((ObjectClass *)(obj), ("virtio-balloon-pci-base"), __FILE__, __LINE__, __func__));
- }
接下来,得到设备VirtIOBalloonPCI的VirtIOBalloon部分,这就是实际的virtio balloon设备了。代码片段如下:
DeviceState *vdev = DEVICE(&dev->vdev);
和VIRTIO_BALLOON_PCI一样,DEVICE的具体定义如果在QEMU源码根目录下搜索是搜不到的,需要进行转换才可以。相关代码在include/hw/qdev-core.h中,如下:
- #define TYPE_DEVICE "device"
- OBJECT_DECLARE_TYPE(DeviceState, DeviceClass, DEVICE)
OBJECT_DECLARE_TYPE宏的定义在include/qom/object.h中,如下:
- /**
- * OBJECT_DECLARE_TYPE:
- * @InstanceType: instance struct name
- * @ClassType: class struct name
- * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators
- *
- * This macro is typically used in a header file, and will:
- *
- * - create the typedefs for the object and class structs
- * - register the type for use with g_autoptr
- * - provide three standard type cast functions
- *
- * The object struct and class struct need to be declared manually.
- */
- #define OBJECT_DECLARE_TYPE(InstanceType, ClassType, MODULE_OBJ_NAME) \
- typedef struct InstanceType InstanceType; \
- typedef struct ClassType ClassType; \
- \
- G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstanceType, object_unref) \
- \
- DECLARE_OBJ_CHECKERS(InstanceType, ClassType, \
- MODULE_OBJ_NAME, TYPE_##MODULE_OBJ_NAME)
代入上边的值,初步展开为:
- typedef struct DeviceState DeviceState;
- typedef struct DeviceClass DeviceClass;
-
- G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
-
- DECLARE_OBJ_CHECKERS(DeviceState, DeviceClass, DEVICE, TYPE_DEVICE)
DECLARE_OBJ_CHECKERS宏的定义也在include/qom/object.h中,如下:
- /**
- * DECLARE_OBJ_CHECKERS:
- * @InstanceType: instance struct name
- * @ClassType: class struct name
- * @OBJ_NAME: the object name in uppercase with underscore separators
- * @TYPENAME: type name
- *
- * Direct usage of this macro should be avoided, and the complete
- * OBJECT_DECLARE_TYPE macro is recommended instead.
- *
- * This macro will provide the three standard type cast functions for a
- * QOM type.
- */
- #define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
- DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
- \
- DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)
因此,上式进一步展开为:
- typedef struct DeviceState DeviceState;
- typedef struct DeviceClass DeviceClass;
-
- G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
-
- DECLARE_INSTANCE_CHECKER(DeviceState, DEVICE, TYPE_DEVICE)
-
- DECLARE_CLASS_CHECKERS(DeviceClass, DEVICE, TYPE_DEVICE)
DECLARE_INSTANCE_CHECKER和DECLARE_CLASS_CHECKERS宏也都是在include/qom/object.h中,定义分别如下:
- /**
- * DECLARE_INSTANCE_CHECKER:
- * @InstanceType: instance struct name
- * @OBJ_NAME: the object name in uppercase with underscore separators
- * @TYPENAME: type name
- *
- * Direct usage of this macro should be avoided, and the complete
- * OBJECT_DECLARE_TYPE macro is recommended instead.
- *
- * This macro will provide the instance type cast functions for a
- * QOM type.
- */
- #define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
- static inline G_GNUC_UNUSED InstanceType * \
- OBJ_NAME(const void *obj) \
- { return OBJECT_CHECK(InstanceType, obj, TYPENAME); }
- /**
- * DECLARE_CLASS_CHECKERS:
- * @ClassType: class struct name
- * @OBJ_NAME: the object name in uppercase with underscore separators
- * @TYPENAME: type name
- *
- * Direct usage of this macro should be avoided, and the complete
- * OBJECT_DECLARE_TYPE macro is recommended instead.
- *
- * This macro will provide the class type cast functions for a
- * QOM type.
- */
- #define DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME) \
- static inline G_GNUC_UNUSED ClassType * \
- OBJ_NAME##_GET_CLASS(const void *obj) \
- { return OBJECT_GET_CLASS(ClassType, obj, TYPENAME); } \
- \
- static inline G_GNUC_UNUSED ClassType * \
- OBJ_NAME##_CLASS(const void *klass) \
- { return OBJECT_CLASS_CHECK(ClassType, klass, TYPENAME); }
因此,上式进一步展开为:
- typedef struct DeviceState DeviceState;
- typedef struct DeviceClass DeviceClass;
-
- G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
-
- static inline G_GNUC_UNUSED DeviceState *DEVICE(const void *obj)
- {
- return OBJECT_CHECK(DeviceState, obj, TYPE_DEVICE);
- }
-
- static inline G_GNUC_UNUSED DeviceClass* DEVICE_GET_CLASS(const void *obj)
- {
- return OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE);
- }
-
- static inline G_GNUC_UNUSED DeviceClass* DEVICE_CLASS(const void *klass)
- {
- return OBJECT_CLASS_CHECK(DeviceClass, klass, TYPE_DEVICE);
- }
再把TYPE_DEVICE的实际值代入,最终得到:
- typedef struct DeviceState DeviceState;
- typedef struct DeviceClass DeviceClass;
-
- G_DEFINE_AUTOPTR_CLEANUP_FUNC(DeviceState, object_unref)
-
- static inline G_GNUC_UNUSED DeviceState *DEVICE(const void *obj)
- {
- return OBJECT_CHECK(DeviceState, obj, "device");
- }
-
- static inline G_GNUC_UNUSED DeviceClass* DEVICE_GET_CLASS(const void *obj)
- {
- return OBJECT_GET_CLASS(DeviceClass, obj, "device");
- }
-
- static inline G_GNUC_UNUSED DeviceClass* DEVICE_CLASS(const void *klass)
- {
- return OBJECT_CLASS_CHECK(DeviceClass, klass, "device");
- }
这里就不再深入展开了。
总之,通过DEVICE宏得到设备VirtIOBalloonPCI的VirtIOBalloon部分,这就是实际的virtio balloon设备了。
DeviceState *vdev = DEVICE(&dev->vdev);
接下来,调用hw/core/qdev.c中的qdev_realize函数。代码片段如下:
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
qdev_realize函数代码如下:
- bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
- {
- assert(!dev->realized && !dev->parent_bus);
-
- if (bus) {
- if (!qdev_set_parent_bus(dev, bus, errp)) {
- return false;
- }
- } else {
- assert(!DEVICE_GET_CLASS(dev)->bus_type);
- }
-
- return object_property_set_bool(OBJECT(dev), "realized", true, errp);
- }
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函数中完成的。
virtio_device_realize函数在hw/virtio/virtio.c中,代码如下:
- static void virtio_device_realize(DeviceState *dev, Error **errp)
- {
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev);
- Error *err = NULL;
-
- /* Devices should either use vmsd or the load/save methods */
- assert(!vdc->vmsd || !vdc->load);
-
- if (vdc->realize != NULL) {
- vdc->realize(dev, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
- }
-
- virtio_bus_device_plugged(vdev, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- vdc->unrealize(dev);
- return;
- }
-
- vdev->listener.commit = virtio_memory_listener_commit;
- vdev->listener.name = "virtio";
- memory_listener_register(&vdev->listener, vdev->dma_as);
- QTAILQ_INSERT_TAIL(&virtio_list, vdev, next);
- }
对于virtio_device_realize函数的深入解析,请看下回。