3. IOMMU核心概念

IOMMU(Input/Output Memory Management Unit)位于设备与系统内存之间,是设备直通、虚拟化和安全隔离的硬件基石。它把“设备发出的DMA地址”翻译成“系统物理地址”,同时把设备中断安全地投递到目标CPU或虚拟机。理解IOMMU,必须抓住六个关键词:DMA重映射、中断重映射、地址空间、页表、域与设备表,以及它与MMU的本质区别。

一、核心原理:IOMMU在数据通路上做了什么

在没有IOMMU的系统中,设备驱动把物理地址直接写入设备寄存器,设备发起DMA时直接访问该物理地址。这带来三个问题:设备只能使用物理地址、恶意或缺陷设备可越界访问任意内存、虚拟机无法安全地把设备分配给客户机。

IOMMU引入后,设备发出的地址先经过IOMMU翻译。设备看到的是IOVA(I/O Virtual Address),IOMMU依据页表把它转换为系统物理地址(SPA/PA)。因此,DMA重映射的本质是“为设备建立一套独立的地址视图”,让设备像进程一样拥有自己的虚拟地址空间。

中断重映射则解决另一条通路:设备产生MSI/MSI-X中断时,写入的是中断地址和数据。IOMMU的中断重映射表(IRTE)会校验并重定向该中断,把它映射到指定CPU向量,甚至直接投递到某个虚拟机的虚拟APIC,从而避免中断被伪造或误投。

IOMMU 核心数据通路与中断通路 设备 / PCIe EP 发起 DMA 请求 使用 IOVA 地址 IOMMU DMA 重映射 中断重映射 权限检查 / 隔离 系统内存 物理地址空间 客户机 / 主机页 设备表 / 域 Device Table → 域 ID 域 → 页表根 中断重映射表 IRTE → 目标 CPU 虚拟 APIC 投递 页表 多级翻译 IOVA → PA DMA 请求 翻译后访问 查表 页表根 中断重定向 MSI 中断 关键关系: 设备 → 设备表 → 域 → 页表 → 物理内存;设备 → 中断重映射表 → 目标 CPU / 虚拟 APIC。 域是隔离边界,页表是地址翻译规则,设备表是“设备到域”的索引,IRTE 是中断投递规则。

二、地址空间、页表、域与设备表

IOMMU的地址空间由页表定义。与MMU类似,IOMMU页表也是多级结构,常见为4级或5级,每级索引若干位,最终得到物理页帧号。不同之处在于,IOMMU页表由系统软件(内核或Hypervisor)为设备建立,设备本身不参与页表管理。

域(Domain)是IOMMU的隔离单位。一个域拥有一套页表,域内设备共享同一地址视图;不同域之间默认不可互访。设备表(Device Table)则把“设备标识符(BDF,Bus/Device/Function)”映射到域ID。这样,当设备发起DMA时,IOMMU先根据BDF查设备表找到域,再用该域的页表翻译地址。

中断重映射表(IRTE)与设备表配合工作。每个设备的中断请求会携带源ID,IOMMU据此查找IRTE,决定该中断是否允许、投递到哪个CPU、使用哪个向量。对于虚拟化场景,IRTE还可以把中断直接注入客户机,减少Hypervisor介入。

概念 作用 关键数据结构 典型使用场景
DMA重映射 把设备IOVA翻译为物理地址 IOMMU页表 设备直通、驱动使用虚拟地址
中断重映射 校验并重定向MSI/MSI-X中断 IRTE 中断隔离、虚拟中断注入
域 定义隔离边界与共享地址空间 Domain结构 多设备分组、VM隔离
设备表 由BDF索引到域 Device Table Entry 设备发现与归属管理
页表 描述IOVA到PA的映射与权限 多级页表 地址翻译、读写权限控制

三、IOMMU与MMU的区别

MMU服务于CPU,翻译的是“进程虚拟地址 → 物理地址”,页表由操作系统为进程维护,切换进程时切换页表基址。IOMMU服务于设备,翻译的是“设备IOVA → 物理地址”,页表由内核或Hypervisor为设备/域维护,切换域时切换页表根。

两者都做地址翻译和权限检查,但触发者、地址来源、页表管理者和故障处理路径不同。MMU缺页会触发CPU异常,由操作系统处理;IOMMU翻译失败通常产生DMA故障,由IOMMU驱动记录并上报,严重时可能隔离设备或触发内核告警。

一句话区分:MMU让CPU进程以为自己独占内存;IOMMU让设备以为自己独占内存。前者保护进程,后者保护系统与虚拟机。

四、案例与场景:设备直通中的一次DMA

假设一台虚拟机需要使用直通网卡。Hypervisor先为网卡创建IOMMU域,建立客户机物理地址到主机物理地址的页表,并把网卡BDF写入设备表指向该域。网卡驱动在客户机内分配缓冲区,得到客户机物理地址,Hypervisor将其映射为IOVA并写入网卡寄存器。

网卡发起DMA,IOMMU根据BDF找到域,用页表把IOVA翻译为主机物理地址,完成数据写入。若网卡试图访问未映射地址,IOMMU会阻止并记录故障,避免破坏主机或其他虚拟机。中断路径上,网卡MSI写入被IRTE重定向到客户机vCPU,实现中断直通。

# 查看IOMMU分组与设备归属(Linux示例)
for g in /sys/kernel/iommu_groups/*; do
  echo "IOMMU Group ${g##*/}:"
  for d in $g/devices/*; do
    echo -e "\t$(lspci -nns ${d##*/})"
  done
done

# 典型日志:DMA翻译失败
DMAR: [DMA Read] Request device [03:00.0] fault addr 0xfffff000
DMAR: DRHD: handling fault status reg 3

五、误区与复盘

  • 误区一:开启IOMMU一定更安全。若使用宽松映射或直通整个域,隔离效果会下降;必须结合设备分组和最小权限页表。
  • 误区二:IOMMU页表就是MMU页表。两者格式可能相似,但归属、生命周期和故障路径不同,不能混用同一套管理逻辑。
  • 误区三:中断重映射可有可无。在虚拟化直通中,没有中断重映射,MSI中断可能无法正确投递或被恶意设备伪造。
  • 复盘要点:排障时先确认设备BDF、域ID、页表映射和IRTE四项是否一致,再检查DMA故障日志与中断统计。

工程建议:为每个直通设备建立独立域,页表只映射必要区域;启用中断重映射并校验源ID;在Hypervisor中记录DMA故障地址与设备BDF,便于快速定位越界访问。