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, 0x7fffffff0x100000000, 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区间。


结束

相关推荐
Yana.nice2 小时前
Linux 只保留 30 天内日志(find命令删除日志文件)
linux·运维·chrome
2601_960567965 小时前
电商套图自动化效率的工程量化分析——从逐张生成到批量套图的架构演进
运维·架构·自动化
吳所畏惧6 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈6 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HiDev_6 小时前
【非标自动化】2、认识元器件(确定目标)
运维·自动化
维天说6 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zhang~Ling7 小时前
从 fopen 到 struct file:从零开始拆解 Linux 文件 I/O
linux·运维·服务器
DeeplyMind7 小时前
Linux 深入 per-VMA lock:Linux 缺页路径如何摆脱 mmap_lock
linux·per-vma lock
爱写代码的阿森7 小时前
鸿蒙三方库 | harmony-utils之PreferencesUtil首选项数据监听详解
服务器·华为·harmonyos·鸿蒙·huawei
爱写代码的森7 小时前
蒙三方库 | harmony-utils之FileUtil文件重命名与属性查询详解
linux·运维·服务器·华为·harmonyos·鸿蒙·huawei