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


结束

相关推荐
能喵烧香3 小时前
深度解析:Linux 与 Windows 超级权限账户的本质差异
linux·windows
pixcarp3 小时前
知识库系统的内容资产闭环怎么设计
服务器·数据库·后端·golang
江畔柳前堤4 小时前
github实战指南01-账号配置与 SSH 密钥
运维·人工智能·深度学习·ssh·github·pyqt·信号处理
Moshow郑锴5 小时前
Ubuntu 26.04 中文输入法 : fcitx5+Rime中州韵引擎
linux·运维·ubuntu
莫名的好感°6 小时前
手机RAR解压怎么选?2026年二季度四款产品问答
服务器·网络·智能手机
qq_163135756 小时前
Linux 【04-more命令超详细教程】
linux
sevencheng7987 小时前
【ADB】adb命令行常用按键模拟代码
linux·adb·模拟按键,返回键,音量键
暗影天帝7 小时前
BPI-R3 Mini 刷 Yuzhii DHCPD U-Boot 教程
linux
小赖同学啊8 小时前
智能连接器集群化高可用生产方案
linux·运维·人工智能
wanghao6664558 小时前
DevOps 从入门到实践:构建高效交付流水线
运维·devops