vfio-pci如何将硬件设备的寄存器和bar空间映射到用户空间的?[转载]
背景:
如果一块新的网卡,要对其开发DPDK驱动支持,DPDK的框架已经搭建好了,需要我们作的主要实现用户态的驱动。能够支持用户态驱动的关键是能够将硬件设备的寄存器,(pcie设备的话)bar空间,中断等映射到用户空间。
目前实现有两个UIO和VFIO两种方式,VFIO是比较新的方式,支持虚拟化和隔离,需要有IOMMU(SMMU)硬件的支持。如果没有IOMMU硬件,但是想用DPDK需要改用UI,否则报错-22 No such device
vfio-pci如何将硬件寄存器和bar空间映射到用户空间的呢?
rte_pci_map_device->pci_vfio_map_resource->pci_vfio_map_resource_primary->pci_vfio_mmap_bar->mmap
使用dpdk的程序(如ovs)调用rte_dev_probe向dpdk注册一个设备,rte_dev_probe的核心处理函数为local_dev_probe,这个函数主要包含了设备总线的匹配,pci设备的bar空间映射,以及最终为设备添加ixgbe驱动。
local_dev_probe的plug最终调用pci_plug,然后遍历bus上的所有驱动为设备匹配驱动,匹配驱动的函数为rte_pci_match,从这个函数可以看出,其实就是通过匹配驱动的id_table里的信息是否能匹配上设备的pci信息,以ixgbe为例,这里的id_table一开始就定义好的,然后存放在struct rte_pci_driver rte_ixgbe_pmd里,最终通过RTE_PMD_REGISTER_PCI将ixgbe_pmd驱动注册到pci总线上。
为设备找到驱动后,接下来一步比较重要的是为设备映射资源信息,如果使用vfio驱动,调用pci_vfio_map_resource,这个函数一开始先通过rte_vfio_setup_device为设备分配vfio_container_id、vfio_group_id,同时设置iommu_type,然后调用dma_map_func将rte_eal_get_configuration()->mem_config的内存信息进行dma映射,这里的mem_config表示dpdk管理的内存信息(从这里看,dpdk应该是一开始会将所有内存都进行dma映射?后面驱动的rx_ring、tx_ring分配dma地址的时候,貌似也没有进一步的dma映射,而是直接使用这里分配好的iova地址。)。 完成dma映射后,通过VFIO_DEVICE_GET_INFO获取设备的信息(主要是pci的bar个数信息及中断信息)。
获取到pci的bar个数信息后,先通过pci_vfio_get_region_info获取每个bar region的地址偏移及大小信息,然后再通过pci_vfio_mmap_bar将其映射到用户空间,并将映射后的bar地址信息存放在rte_pci_device->mem_resource。
接下来主要是调用驱动的probe函数,初始化设备信息,如ixgbe,最终调用eth_ixgbe_pci_probe,该probe函数主要是调用rte_eth_dev_create
参考:
https://www.twblogs.net/a/5efa9d0533599de3c62bb3aa/?lang=zh-cn
https://www.jianshu.com/p/4a240af0e5c6
https://docs.kernel.org/driver-api/vfio.html
https://cwshu.github.io/arm_virt_notes/notes/vfio/vfio_core2.html