QEMU源码全解析 —— PCI设备模拟(6)

这篇具有很好参考价值的文章主要介绍了QEMU源码全解析 —— PCI设备模拟(6)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

接前一篇文章:

上一回讲到了pci_edu_realize函数中的pci_register_bar函数,本回对于其进行详细解析。

再次贴出pci_register_bar函数源码,在hw/pci/pci.c中,代码如下:

void pci_register_bar(PCIDevice *pci_dev, int region_num,
                      uint8_t type, MemoryRegion *memory)
{
    PCIIORegion *r;
    uint32_t addr; /* offset in pci config space */
    uint64_t wmask;
    pcibus_t size = memory_region_size(memory);
    uint8_t hdr_type;
 
    assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */
    assert(region_num >= 0);
    assert(region_num < PCI_NUM_REGIONS);
    assert(is_power_of_2(size));
 
    /* A PCI bridge device (with Type 1 header) may only have at most 2 BARs */
    hdr_type =
        pci_dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
    assert(hdr_type != PCI_HEADER_TYPE_BRIDGE || region_num < 2);
 
    r = &pci_dev->io_regions[region_num];
    r->addr = PCI_BAR_UNMAPPED;
    r->size = size;
    r->type = type;
    r->memory = memory;
    r->address_space = type & PCI_BASE_ADDRESS_SPACE_IO
                        ? pci_get_bus(pci_dev)->address_space_io
                        : pci_get_bus(pci_dev)->address_space_mem;
 
    wmask = ~(size - 1);
    if (region_num == PCI_ROM_SLOT) {
        /* ROM enable bit is writable */
        wmask |= PCI_ROM_ADDRESS_ENABLE;
    }
 
    addr = pci_bar(pci_dev, region_num);
    pci_set_long(pci_dev->config + addr, type);
 
    if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
        r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
        pci_set_quad(pci_dev->wmask + addr, wmask);
        pci_set_quad(pci_dev->cmask + addr, ~0ULL);
    } else {
        pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
        pci_set_long(pci_dev->cmask + addr, 0xffffffff);
    }
}

(1)首先根据region_num找到PCIDevice->io_regions数组中对应的项。PCI设备的MMIO存放在PCIIORegion结构体中,结构体中保存了MMIO的地址、大小、类型等信息。

代码片段如下:

    r = &pci_dev->io_regions[region_num];

(2)得到region_num表示的PCIIORegion之后,进行一些初始化设置。

    r->addr = PCI_BAR_UNMAPPED;
    r->size = size;
    r->type = type;
    r->memory = memory;
    r->address_space = type & PCI_BASE_ADDRESS_SPACE_IO
                        ? pci_get_bus(pci_dev)->address_space_io
                        : pci_get_bus(pci_dev)->address_space_mem;

(3)然后将该region的type写到相应PCI配置空间对应BAR的地址处。代码片段如下:

    r->address_space = type & PCI_BASE_ADDRESS_SPACE_IO
                        ? pci_get_bus(pci_dev)->address_space_io
                        : pci_get_bus(pci_dev)->address_space_mem;

(4)最后设置PCI Device中wmask和cmask的值。代码片段如下:

    wmask = ~(size - 1);
    if (region_num == PCI_ROM_SLOT) {
        /* ROM enable bit is writable */
        wmask |= PCI_ROM_ADDRESS_ENABLE;
    }
 
    addr = pci_bar(pci_dev, region_num);
    pci_set_long(pci_dev->config + addr, type);
 
    if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) &&
        r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
        pci_set_quad(pci_dev->wmask + addr, wmask);
        pci_set_quad(pci_dev->cmask + addr, ~0ULL);
    } else {
        pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
        pci_set_long(pci_dev->cmask + addr, 0xffffffff);
    }

操作系统与PCI设备交互的主要方式是PIO和MMIO。MMIO虽然是一段内存,但是其没有EPT映射,在虚拟机访问设备的MMIO时,会产生VM Exit;KVM识别此MMIO访问并且将该访问分派到应用层QEMU中;QEMU根据内存虚拟化的步骤进行分派,找到设备注册的MMIO读写回调函数;设备的MMIO读写回调函数根据设备的功能进行模拟,完成模拟之后可能会发送中断到虚拟机中,从而完成一些MMIO访问。

下一回将开始解析edu设备的MMIO读写函数。文章来源地址https://www.toymoban.com/news/detail-792623.html

到了这里,关于QEMU源码全解析 —— PCI设备模拟(6)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • qemu源码解析一

    QEMU是一个开源的虚拟化软件,它能够模拟各种硬件设备,支持多种虚拟化技术,如TCG、Xen、KVM等 TCG 是 QEMU 中的一个组件,它可以将高级语言编写的代码(例如 C 代码)转换为可在虚拟机中执行的低级代码(例如 x86 机器指令)。TCG 生成的代码通常比直接使用 CPU 指令更简单

    2024年04月12日
    浏览(31)
  • QEMU源码全解析 —— virtio(20)

    接前一篇文章: 上回书重点解析了virtio_pci_modern_probe函数。再来回顾一下其中相关的数据结构: struct virtio_pci_device struct virtio_pci_device的定义在Linux内核源码/drivers/virtio/virtio_pci_common.h中,如下: virtio_pci_modern_probe执行完成后,相关数据结构如下图所示: 回到virtio_pci_probe函数

    2024年02月21日
    浏览(32)
  • QEMU源码全解析38 —— Machine(8)

    接前一篇文章:QEMU源码全解析37 —— Machine(7) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社 特此致谢! 上一回经过了重重周折,终于找到了MACHINE的定义所在: 本回就详细解析一下这段代码。别看代码

    2024年02月12日
    浏览(28)
  • QEMU源码全解析16 —— QOM介绍(5)

    接前一篇文章:QEMU源码全解析15 —— QOM介绍(4) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社 特此致谢! 上一回讲完了QOM第一部分 —— 类型的注册。本回开始讲解第二部分 —— 类型的初始化。 2. 类

    2024年02月15日
    浏览(32)
  • QEMU源码全解析23 —— QOM介绍(12)

    接前一篇文章:QEMU源码全解析22 —— QOM介绍(11) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社 特此致谢! 上一回分析了QEMU对象的构造和初始化的函数调用流程,本回结合实例对此流程进行深入介绍和

    2024年02月14日
    浏览(39)
  • qemu-kvm IO优化

    主要是磁盘方面的IO资源优化  四个方面去着手优化: 1. 磁盘的类型有IDE 、SATA 以及virtio 三种   建议使用 virtio 2. 磁盘缓存模式   目前KVM这块支持5种磁盘缓存模式,writethrough、writeback、none、directsync或者unsafe。一般用到的就是前面3种,后面两种几乎不会使用。   writethrou

    2023年04月08日
    浏览(35)
  • kvm qemu虚拟机的创建和启动

    qemu-img create -f qcow2 win1021H1.qcow2 10G sudo qemu-system-x86_64 -enable-kvm -m 8G -smp 4 -boot once=d -cdrom ./iso/cn_windows_7_enterprise_with_sp1_x64_dvd_u_677685.iso -hda ./win7_x64.qcow2 -vnc :1 -usb -usbdevice tablet 如果没有指定-hda ./win7.qcow2,则在安装系统的时候没有磁盘,如下图片是增加了之后才有的磁盘 默认不

    2024年02月12日
    浏览(52)
  • QEMU-KVM网络特性协商与虚拟机通信

    深入了解QEMU-KVM在启动虚拟机时如何通过代理进行网络前后端特性协商,包括与DPDK vhost-user和guest virtio-net驱动的交互。

    2024年02月01日
    浏览(34)
  • 巨页内存与Qemu/KVM虚拟化内存优化

    在虚拟化环境中,需要对虚拟机的优化,其中包括在某些情况下利用巨页内存进行内存的优化以提高虚拟机性能。那么什么是巨页内存?巨页内存有什么好处?Qemu/KVM虚拟化环境下如何使用巨页内存?本文将对这几个问题进行阐述。 对于内存管理,大多数现代操作系统都采用

    2024年02月07日
    浏览(48)
  • python可视化管理kvm虚拟机(使用libvirt、qemu连接虚拟机)

    对于云计算的实践,在虚拟机上面布置kvm虚拟机后使用python调用libvirt库进行远程可视化管理,实现输出虚拟机信息、新建虚拟机、删除虚拟机等功能,并在虚拟机集群上面运行mpi代码。 用pycharm专业版连接kvm的步骤见本文章。 mpi代码见本文章。

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包