[内核:HVA]->[QEMU:HVA]的mmap地址映射
$ sudo cat /proc/2047239/maps | grep -i vfio
address perms offset dev inode pathname
7f4b5444a000-7f4b5445a000 rw-s 9da50000 00:0e 13037 anon_inode:[vfio-device]
7f4b5445a000-7f4b5446a000 rw-s 9da40000 00:0e 13037 anon_inode:[vfio-device]
7f4b5c00d000-7f4b5c01d000 rw-s 9da30000 00:0e 13037 anon_inode:[vfio-device]
输出的信息依次为:
第一列:本段在虚拟内存中的地址范围。
第二列:本段的权限。
第三列:偏移地址,即指本段映射地址在文件中的偏移。
第四列:主设备号与次设备号。
第五列:文件索引节点号。
第六列:映射的文件名。
[HPA]->[内核:HVA] 的ioremap地址映射
$ sudo cat /proc/vmallocinfo | grep -i mmap
0xffffac75cb9f0000-0xffffac75cba01000 69632 vfio_pci_mmap+0x1a7/0x1f0 [vfio_pci] phys=0x000000009da30000 ioremap
0xffffac75cba40000-0xffffac75cba51000 69632 vfio_pci_mmap+0x1a7/0x1f0 [vfio_pci] phys=0x000000009da40000 ioremap
0xffffac75cbea0000-0xffffac75cbeb1000 69632 vfio_pci_mmap+0x1a7/0x1f0 [vfio_pci] phys=0x000000009da50000 ioremap
./Documentation/filesystems/proc.rst
1174 vmallocinfo
1175 ~~~~~~~~~~~
1176
1177 Provides information about vmalloced/vmaped areas. One line per area,
1178 containing the virtual address range of the area, size in bytes,
1179 caller information of the creator, and optional information depending
1180 on the kind of area:
提供有关vmallocated/vmaped区域的信息。每个区域一行,
包含区域的虚拟地址范围、以字节为单位的大小、
创建者的调用方信息以及取决于区域类型的可选信息:
1181
1182 ========== ===================================================
1183 pages=nr number of pages
1184 phys=addr if a physical address was specified
1185 ioremap I/O mapping (ioremap() and friends)
1186 vmalloc vmalloc() area
1187 vmap vmap()ed pages
1188 user VM_USERMAP area
1189 vpages buffer for pages pointers was vmalloced (huge area)
1190 N<node>=nr (Only on NUMA kernels)
1191 Number of pages allocated on memory node <node>
1192 ========== ===================================================
1193
1194 ::
[QEMU:HVA]->[GPA]的IOMMU映射
memory_region_init_ram_device_ptr->
ram_block_notify_add->
notifier->ram_block_added(notifier, host, size, max_size)->
qemu_vfio_ram_block_added->
qemu_vfio_dma_map->
qemu_vfio_do_mapping->
ioctl(s->container, VFIO_IOMMU_MAP_DMA, &dma_map)
Host是需要开启IOMMU的,因为ioctl(s->container, VFIO_IOMMU_MAP_DMA, &dma_map)
用来关联[GPA]和[QEMU:HVA]的关系,通过VFIO的IOMMU_DOMAIN_UNMANAGED
类型domain
,填充Host IOMMU的Host device对应的IO页表,具体流程如下:
ioctl(pdev.vfio.container, VFIO_IOMMU_MAP_DMA, &dma_map);
vfio_iommu_type1_ioctl
vfio_iommu_type1_map_dma
vfio_dma_do_map
vfio_pin_map_dma
vfio_iommu_map
iommu_map
__iommu_map
__iommu_map_pages
ops->map_pages
intel_iommu_map_pages
intel_iommu_map
__domain_mapping
在__domain_mapping里,将IOVA(即GPA)和HVA对应的物理地址HPA的PFN填充到IOMMU的二级翻译页表项的PTE中,实现GPA->HPA的转换。
这样Host device DMA访问GPA,就可以通过IOMMU找到HPA,从而进行DMA读写。
DMA内存分配和地址传递
DMA内存是有Guest driver通过dma_alloc_coherent等DMA API接口分配,由于Guest中没有开启IOMMU,多以dma_alloc_coherent分配的内存的物理地址GPA就是DMA地址。GPA地址被写到Host device的寄存器中,Host device从而可以访问GPA地址。
Guest不开启iommu的情况下,GPA作为DMA的IOVA地址,传递给Host上的device。
dma_alloc_coherent接口,由于没有开启IOMMU,所以直接将CPU虚拟地址对应的物理地址作为IOVA。
没有IO页表。
其他
在网卡中,
这个IOVA地址就是GPA。传递给Host device,用于DMA操作。
CPU访问GPA->HPA的转换是通过EPT硬件完成的。
Host device DMA访问vring,需要经过GPA->HPA的寻址。
Host是需要开启IOMMU的,因为ioctl(s->container, VFIO_IOMMU_MAP_DMA, &dma_map)
用来关联GPA和用户HVA的关系,通过VFIO的unmanaged类型domain,填充Host IOMMU的IO页表,这样Host device DMA访问GPA,就可以找到HPA,从而进行DMA读写。
DMA读通过driver notify硬件触发;
DMA写完成,通过device中断通知driver读,msix bar已经mmap给Guest了,Posted中断可以直接传递个vCPU处理。