彩票开奖网站建设,完整网站开发视频,wordpress中文切换,泸州网站优化推广接前一篇文章#xff1a; 上一回讲到了pci_edu_realize函数中的pci_register_bar函数#xff0c;本回对于其进行详细解析。
再次贴出pci_register_bar函数源码#xff0c;在hw/pci/pci.c中#xff0c;代码如下#xff1a;
void pci_register_bar(PCIDevice *pci_dev, in…接前一篇文章 上一回讲到了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 ExitKVM识别此MMIO访问并且将该访问分派到应用层QEMU中QEMU根据内存虚拟化的步骤进行分派找到设备注册的MMIO读写回调函数设备的MMIO读写回调函数根据设备的功能进行模拟完成模拟之后可能会发送中断到虚拟机中从而完成一些MMIO访问。
下一回将开始解析edu设备的MMIO读写函数。