当前位置: 首页 > news >正文

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

接前一篇文章:

上两回讲解了virtio balloon相关类所涉及的realize函数以及大致流程,如下表所示:

realize函数parent_dc_realize函数
DeviceClassvirtio_pci_dc_realize
PCIDeviceClassvirtio_pci_realize
VirtioPCIClassvirtio_balloon_pci_realizepci_qdev_realize

本回对于流程进行深入解析。

综合前文书所讲,当具现化TYPE_VIRTIO_BALLOON的时候,device_set_realized函数中会首先调用DeciceClass->realize即virtio_pci_dc_realize函数。再次贴出该函数源码,在hw/virtio/virtio-pci.c中,如下:

static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
{VirtioPCIClass *vpciklass = VIRTIO_PCI_GET_CLASS(qdev);VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);PCIDevice *pci_dev = &proxy->pci_dev;if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) &&virtio_pci_modern(proxy)) {pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;}vpciklass->parent_dc_realize(qdev, errp);
}

virtio_pci_dc_realize函数首先判断virtio PCI代理设备是否具有VIRTIO_PCI_FLAG_DISABLE_PCIE特性,该特性使得virtio PCI代理展现出PCIe的的接口。

之后调用了vpciklass->parent_dc_realize函数,由前文分析可知,该回调函数是pci_qdev_realize()。再次贴出pci_qdev_realize函数源码,在hw/virtio/virtio-pci.c中,如下:

static void pci_qdev_realize(DeviceState *qdev, Error **errp)
{PCIDevice *pci_dev = (PCIDevice *)qdev;PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);ObjectClass *klass = OBJECT_CLASS(pc);Error *local_err = NULL;bool is_default_rom;uint16_t class_id;/** capped by systemd (see: udev-builtin-net_id.c)* as it's the only known user honor it to avoid users* misconfigure QEMU and then wonder why acpi-index doesn't work*/if (pci_dev->acpi_index > ONBOARD_INDEX_MAX) {error_setg(errp, "acpi-index should be less or equal to %u",ONBOARD_INDEX_MAX);return;}/** make sure that acpi-index is unique across all present PCI devices*/if (pci_dev->acpi_index) {GSequence *used_indexes = pci_acpi_index_list();if (g_sequence_lookup(used_indexes,GINT_TO_POINTER(pci_dev->acpi_index),g_cmp_uint32, NULL)) {error_setg(errp, "a PCI device with acpi-index = %" PRIu32" already exist", pci_dev->acpi_index);return;}g_sequence_insert_sorted(used_indexes,GINT_TO_POINTER(pci_dev->acpi_index),g_cmp_uint32, NULL);}if (pci_dev->romsize != -1 && !is_power_of_2(pci_dev->romsize)) {error_setg(errp, "ROM size %u is not a power of two", pci_dev->romsize);return;}/* initialize cap_present for pci_is_express() and pci_config_size(),* Note that hybrid PCIs are not set automatically and need to manage* QEMU_PCI_CAP_EXPRESS manually */if (object_class_dynamic_cast(klass, INTERFACE_PCIE_DEVICE) &&!object_class_dynamic_cast(klass, INTERFACE_CONVENTIONAL_PCI_DEVICE)) {pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;}if (object_class_dynamic_cast(klass, INTERFACE_CXL_DEVICE)) {pci_dev->cap_present |= QEMU_PCIE_CAP_CXL;}pci_dev = do_pci_register_device(pci_dev,object_get_typename(OBJECT(qdev)),pci_dev->devfn, errp);if (pci_dev == NULL)return;if (pc->realize) {pc->realize(pci_dev, &local_err);if (local_err) {error_propagate(errp, local_err);do_pci_unregister_device(pci_dev);return;}}/** A PCIe Downstream Port that do not have ARI Forwarding enabled must* associate only Device 0 with the device attached to the bus* representing the Link from the Port (PCIe base spec rev 4.0 ver 0.3,* sec 7.3.1).* With ARI, PCI_SLOT() can return non-zero value as the traditional* 5-bit Device Number and 3-bit Function Number fields in its associated* Routing IDs, Requester IDs and Completer IDs are interpreted as a* single 8-bit Function Number. Hence, ignore ARI capable devices.*/if (pci_is_express(pci_dev) &&!pcie_find_capability(pci_dev, PCI_EXT_CAP_ID_ARI) &&pcie_has_upstream_port(pci_dev) &&PCI_SLOT(pci_dev->devfn)) {warn_report("PCI: slot %d is not valid for %s,"" parent device only allows plugging into slot 0.",PCI_SLOT(pci_dev->devfn), pci_dev->name);}if (pci_dev->failover_pair_id) {if (!pci_bus_is_express(pci_get_bus(pci_dev))) {error_setg(errp, "failover primary device must be on ""PCIExpress bus");pci_qdev_unrealize(DEVICE(pci_dev));return;}class_id = pci_get_word(pci_dev->config + PCI_CLASS_DEVICE);if (class_id != PCI_CLASS_NETWORK_ETHERNET) {error_setg(errp, "failover primary device is not an ""Ethernet device");pci_qdev_unrealize(DEVICE(pci_dev));return;}if ((pci_dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)|| (PCI_FUNC(pci_dev->devfn) != 0)) {error_setg(errp, "failover: primary device must be in its own ""PCI slot");pci_qdev_unrealize(DEVICE(pci_dev));return;}qdev->allow_unplug_during_migration = true;}/* rom loading */is_default_rom = false;if (pci_dev->romfile == NULL && pc->romfile != NULL) {pci_dev->romfile = g_strdup(pc->romfile);is_default_rom = true;}pci_add_option_rom(pci_dev, is_default_rom, &local_err);if (local_err) {error_propagate(errp, local_err);pci_qdev_unrealize(DEVICE(pci_dev));return;}pci_set_power(pci_dev, true);pci_dev->msi_trigger = pci_msi_trigger;
}

http://www.lryc.cn/news/260729.html

相关文章:

  • 金蝶云星空协同开发环境应用内执行单据类型脚本
  • 矩阵理论及其应用邱启荣习题3.5题解
  • Java面试题(每天10题)-------连载(49)
  • python——数据类型
  • hive中如何求取中位数?
  • 在C#中异步编程
  • 微服务保护--Feign整合Sentinel
  • 二进制to十六进制
  • Logistic 回归算法
  • ubuntu安装详细步骤
  • 力扣5. 最长回文子串
  • 肆[4],函数VectorToHomMat2d/AffineTransPoint2d
  • 下载文件 后端返回给前端 response header 响应头
  • lvs负载均集群
  • luttuce(RedisTempate)实现hash expire lua脚本
  • 【Xamarin】WebView连接局域网自动跳转外部浏览器问题的解决
  • 【Unity动画】实现不同的肢体动作自由搭配播放Layer+Avatar Mask
  • 将0x06(16进制)转换为二进制
  • 考PRINCE2有用么?有PMP证书了还需要考PRINCE2吗?
  • 06进程间关系-学习笔记
  • Vue的动画方式有几种
  • PyTorch: 基于【VGG16】处理MNIST数据集的图像分类任务【准确率98.9%+】
  • 【lombok】从easyExcel read不到值到cglib @Accessors(chain = true)隐藏的大坑
  • 1-SaaS通识
  • Spring Boot实现接口幂等
  • ShopsN commentUpload 文件上传漏洞复现
  • 【Qt5】ui文件最后会变成头文件
  • 数组笔试题解析(下)
  • PPT插件-好用的插件-图形缩放-大珩助手
  • 五:爬虫-数据解析之xpath解析