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区间。


结束

相关推荐
测试员周周4 小时前
【Appium 系列】第16节-WebView-H5上下文切换 — 混合应用的自动化难点
运维·开发语言·人工智能·功能测试·appium·自动化·测试用例
小辰记事本6 小时前
从零读懂RoCEv2数据包构造:从WQE到线缆上的完整旅程
服务器·网络·网络协议·rdma
小鹏linux7 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
在角落发呆7 小时前
Linux转发配置:解锁网络互联的核心密码
linux·运维·网络
齐潇宇8 小时前
Zabbix 7 概述与配置
linux·zabbix·监控告警
裴东青9 小时前
10-实战:RuoYi-Cloud的自动化发布
运维·ci/cd·自动化
江公望9 小时前
Ubuntu htop命令,10分钟讲清楚
linux·服务器
哎呦,帅小伙哦9 小时前
Linux 时间:从原子钟到 clock_gettime 的每一面
linux·运维·服务器
sxgzzn9 小时前
新能源场站数智化转型:基于数字孪生与AI的智慧运维管理平台解析
大数据·运维·人工智能
张小姐的猫9 小时前
【Linux】多线程 —— 线程互斥
linux·运维·服务器·c++