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 |
欲知后事如何,且看下回分解。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!