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

接前一篇文章:

本回分析在VirtioPCIClass类还没有初始化时的realize函数。如下表所示:

DeviceClass pci_qdev_realize
PCIDeviceClass pci_default_realize

VirtioPCIClass类的相关定义是在所有virtio PCI代理设备的父设备TYPE_VIRTIO_PCI中进行的,其中的类初始化函数是virtio_pci_class_init,其在hw/virtio/virtio-pci.c中,代码如下:

static void virtio_pci_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
    ResettableClass *rc = RESETTABLE_CLASS(klass);

    device_class_set_props(dc, virtio_pci_properties);
    k->realize = virtio_pci_realize;
    k->exit = virtio_pci_exit;
    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
    k->revision = VIRTIO_PCI_ABI_VERSION;
    k->class_id = PCI_CLASS_OTHERS;
    device_class_set_parent_realize(dc, virtio_pci_dc_realize,
                                    &vpciklass->parent_dc_realize);
    rc->phases.hold = virtio_pci_bus_reset_hold;
}

static const TypeInfo virtio_pci_info = {
    .name          = TYPE_VIRTIO_PCI,
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(VirtIOPCIProxy),
    .class_init    = virtio_pci_class_init,
    .class_size    = sizeof(VirtioPCIClass),
    .abstract      = true,
};

如上一回所讲,virtio_pci_class_init函数首先把PCIDeviceClassClass->realize函数(指针)替换成了自己的virtio_pci_realize函数。

接下来较为关键的一句是:

device_class_set_parent_realize(dc, virtio_pci_dc_realize,
                                    &vpciklass->parent_dc_realize);

device_class_set_parent_realize函数在hw/core/qdev.c中,代码如下:

void device_class_set_parent_realize(DeviceClass *dc,
                                     DeviceRealize dev_realize,
                                     DeviceRealize *parent_realize)
{
    *parent_realize = dc->realize;
    dc->realize = dev_realize;
}

device_class_set_parent函数上下文先将vpciklass->parent_dc_realize设置成了dc->realize,这个值是pci_qdev_realize。在在hw/pci/pci.c的pci_device_class_init函数中,如下所示(见上一回):

static void pci_device_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
 
    k->realize = pci_qdev_realize;
    k->unrealize = pci_qdev_unrealize;
    k->bus_type = TYPE_PCI_BUS;
    device_class_set_props(k, pci_props);
}

然后将dc->realize设置成了virtio_pci_dc_realize(通过中间变量dev_realize)。

通常来说,父类的realize函数会调用子类的realize函数,如DeviceClass->realize(pci_qdev_realize)会调用PCIDeviceClass->realize回调,而PCIDeviceClass->realize回调又可以调用子类型的realize函数。但是这两条语句改变了这个顺序。在这里,dc->realize被设置成了virtio_pci_dc_realize,由于DeviceClass->realize即dc->realize所指向的函数会先被执行,因此virtio_pci_dc_realize函数会最先执行,然后将原来的dc->realize即pci_qdev_realize函数保存到VirtioPCIClass->parent_dc_realize函数中。见上边的片段:

device_class_set_parent_realize(dc, virtio_pci_dc_realize,
                                    &vpciklass->parent_dc_realize);
void device_class_set_parent_realize(DeviceClass *dc,
                                     DeviceRealize dev_realize,
                                     DeviceRealize *parent_realize)
{
    *parent_realize = dc->realize;
    dc->realize = dev_realize;
}

通常在设备具现化过程中,子类型的realize函数需要先做某些事情的时候会使用这种方法。

回到virtio balloon PCI代理设备类型的初始化函数virtio_balloon_pci_class_init(),在hw/virtio/virtio-balloon-pci.c中,代码如下:

static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
    k->realize = virtio_balloon_pci_realize;
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
    pcidev_k->class_id = PCI_CLASS_OTHERS;
}

可以看到,其中设置了VirtioPCIClass->realize函数指针指向virtio_balloon_pci_realize()。

综上所述,virtio balloon相关类所涉及的realize函数如下表所示:

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

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

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/134986090