QEMU和KVMTOOL在GPA(IOVA)和HVA映射方面的异同

之前分析过,在KVMTOOL虚拟化环境下,VM OS中的GPA和HOST OS中的HVA有简单的线性映射关系,并且线性偏移因子是一个固定值,但是最近在QEMU中发现,这种线性关系并非普遍实现,QEMU中虽然GPA地址空间和HVA也有线性关系,但是可以有多于一个的线性偏移,也就是说,不同的GPA区域和QEMU中分配给VM的HVA区域的偏移可以有多个。下面是启动VFIO透传后,在VFIO DOMAIN下 进行IOVA MAP和UNMAP的LOG,去掉对称的MAP/UNMAP,剩下的就是VM运行时HVA和GPA(IOVA)的实际映射了:

复制代码
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabe00000, iova 0x0, size 0xa0000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabec0000, iova 0xc0000, size 0x7ff40000.*/
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aaac00000, iova 0xfffc0000, size 0x40000.
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737b2be00000, iova 0x100000000, size 0x80000000.
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xc0000, size 0x7ff40000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aaaa00000, iova 0xc0000, size 0x20000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aaac20000, iova 0xe0000, size 0x20000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabf00000, iova 0x100000, size 0x7ff00000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xc0000, size 0x20000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xe0000, size 0x20000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0x100000, size 0x7ff00000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabec0000, iova 0xc0000, size 0x18000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aaaa18000, iova 0xd8000, size 0x8000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aaac20000, iova 0xe0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabef0000, iova 0xf0000, size 0x7ff10000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xc0000, size 0x18000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xd8000, size 0x8000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xe0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xf0000, size 0x7ff10000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabec0000, iova 0xc0000, size 0x7ff40000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9800000, iova 0xfd000000, size 0x1000000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0x0, size 0xa0000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xc0000, size 0x7ff40000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabe00000, iova 0x0, size 0x80000000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0x0, size 0x80000000.*/
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabe00000, iova 0x0, size 0xa0000.
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabec0000, iova 0xc0000, size 0x7ff40000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9600000, iova 0xfebc0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xfebc0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9400000, iova 0xfeb40000, size 0x40000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xfeb40000, size 0x40000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xc0000, size 0x7ff40000.*/
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabec0000, iova 0xc0000, size 0xb000.
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabecb000, iova 0xcb000, size 0x3000.
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabece000, iova 0xce000, size 0xa000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabed8000, iova 0xd8000, size 0x18000.*/
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabef0000, iova 0xf0000, size 0x10000.
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabf00000, iova 0x100000, size 0x7ff00000.
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xce000, size 0xa000.*/
/*kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_unmap line 1312, unmap iova 0xd8000, size 0x18000.*/
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabece000, iova 0xce000, size 0x1a000.
kern  :warn  : [日 3月 15 16:23:58 2026] vfio_dma_do_map line 1588, vaddr 0x737aabee8000, iova 0xe8000, size 0x8000.
/*kern  :warn  : [日 3月 15 16:23:59 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9800000, iova 0xa0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:24:00 2026] vfio_dma_do_unmap line 1312, unmap iova 0xfd000000, size 0x1000000.*/
kern  :warn  : [日 3月 15 16:24:00 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9800000, iova 0xfd000000, size 0x1000000.
/*kern  :warn  : [日 3月 15 16:24:02 2026] vfio_dma_do_unmap line 1312, unmap iova 0xa0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:24:02 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9800000, iova 0xa0000, size 0x10000.*/
/*kern  :warn  : [日 3月 15 16:24:06 2026] vfio_dma_do_unmap line 1312, unmap iova 0xa0000, size 0x10000.*/
kern  :warn  : [日 3月 15 16:24:06 2026] vfio_dma_do_map line 1588, vaddr 0x737aa9800000, iova 0xa0000, size 0x10000.

分析后如下图:

最终的映射图为:

可以看到,IOVA/GPA其实被映射成了两个部分,对照VM中lsmem输出,QEMU启动参数中指定的4G HVA被分成两个2G的部分,分别映射到[0, 0x7fffffff]和[0x100000000, 0x17fffffff],其中[0, 0x7fffffff]中有一部分被影视给了设备,这个视图和VCPU看到的是一致的。

所以,可以看到,只有前2G可以用如下公式区定位指定VM中的GPA地址 在HOST OS中的HVA :

hva = hva_base + gpa(iova).

后2G的映射需要再减去两个区间中的2G偏移。

hva = hva_base + gpa(iova) -2G.

几个HVA区间位于QEMU的地址空间:

VM OS内从VCPU视角看到的GPA映射分布,和VFIO进行的IOVA映射分配是完全一样的。

所以,如果不想反查页表格而是超捷径利用这种线性关系来定位一个VM中的地址在HOST中的具体位置,需要注意OFFSET和GPA本身的位置有关了,不同的GPA,OFFSET可能是不同的。

不过话又说回来,没有任何一份文档约定了这种线性关系的存在,只是GPA和HVA保持线性是一种最自然合理的实现而以。QEMU和KVMTOOL中也并非是通过固定的线性关系来进行翻译,而是针对不同的MEM SLOT计算不同的偏移,这里的分析说明了这样作的原因,因为不同的MEMORY SLOT,拥有不同的偏移,即便是同一个MEMORY SLOT,也可以按照本篇分析的这样,不同的区间段映射到不同的GPA区间。


结束

相关推荐
Xzq2105092 小时前
部分重要协议或技术(DNS,ICMP,NAT,代理服务器)
运维·服务器·网络
艾莉丝努力练剑2 小时前
文件描述符fd:跨进程共享机制
java·linux·运维·服务器·开发语言·c++
工藤新一¹2 小时前
《操作系统》第一章(1)
java·服务器·前端
原来是猿2 小时前
Linux-【文件系统下】
linux·运维·数据库
勇闯逆流河2 小时前
【Linux】linux进程概念(冯洛伊曼体系、操作系统、进程详解)
linux·运维·服务器
姓刘的哦2 小时前
RK3568之热插拔
linux
Penguido2 小时前
解决 VS Code 中 Git 推送报错:ECONNREFUSED vscode-git.sock 与鉴权失败
linux·git·vscode
Han.miracle2 小时前
Lombok 构造相关核心注解全解析
java·linux·算法
小杰帅气3 小时前
网络层IP理解
服务器·网络·tcp/ip