4. IOMMU架构原理

IOMMU(Input/Output Memory Management Unit)位于设备与系统内存之间,是设备直通虚拟化的核心硬件。它把“设备发出的DMA地址”从设备视角的地址空间,翻译成宿主物理地址空间中的真实位置,并在翻译过程中施加权限、隔离与中断投递控制。理解IOMMU,关键要抓住三条主线:DMA重映射解决“设备能访问哪里”,中断重映射解决“设备中断投给谁”,页表与地址转换解决“地址如何被翻译”。

一、IOMMU在系统中的位置与核心职责

在无IOMMU的系统中,设备驱动把物理地址直接写入设备寄存器,设备发起DMA时直接访问该物理地址。一旦设备被直通给虚拟机,设备看到的“物理地址”其实是客户机物理地址(GPA),与宿主物理地址(HPA)不一致,直接DMA会破坏宿主内存。IOMMU的引入,使设备DMA必须经过一次地址翻译与权限检查,从而把设备限制在受控的地址窗口内。

IOMMU的核心职责可归纳为:

  • DMA重映射:将设备DMA请求中的地址(IOVA/GPA)翻译为宿主物理地址HPA,并检查读/写权限。
  • 中断重映射:将设备产生的MSI/MSI-X中断请求,按中断重映射表翻译为可投递给目标vCPU的中断向量。
  • 隔离与保护:不同设备、不同虚拟机使用不同页表,防止越权访问与DMA攻击。
  • 地址空间管理:支持多级页表、大页映射、ATS/PASID等扩展,提高翻译效率。

一句话理解:MMU管CPU的地址翻译,IOMMU管设备的地址翻译;两者共享“页表+权限检查”的思想,但服务对象、页表基址和缓存结构不同。

二、DMA重映射与地址转换流程

当设备发起DMA时,IOMMU按以下路径完成翻译:设备发出带地址的DMA请求 → IOMMU根据设备标识(BDF:Bus/Device/Function)找到对应的设备表项 → 从设备表项获取该设备的页表基址 → 用请求地址逐级查页表 → 得到HPA并检查权限 → 通过则访问内存,失败则产生IOMMU故障(如DMAR fault)。

在虚拟化场景中,常见的是“两阶段翻译”:第一阶段把GPA翻译为HPA(由宿主VMM管理),第二阶段把IOVA翻译为GPA(由客户机管理)。硬件通过嵌套页表(如Intel VT-d的SLPT、AMD-Vi的嵌套页表)一次性完成两级翻译,减少软件介入。

设备DMA请求:  IOVA = 0x0000_7F00_1000
   │
   ▼
[设备表项] BDF=00:02.0 → 根表 → 上下文表 → 页表基址
   │
   ▼
[多级页表] PML4 → PDPT → PD → PT → 页内偏移
   │
   ▼
宿主物理地址 HPA = 0x0000_0001_2345_1000
权限检查: 读=允许, 写=允许, 执行=禁止

三、页表结构与关键参数

IOMMU页表通常采用与CPU MMU类似的多级结构,常见为4级或5级。每一级表项包含下一级表的物理基址和权限位。与CPU页表不同的是,IOMMU页表项还包含设备相关的控制位,例如:

字段/参数作用典型取值/说明
Present (P)表项是否有效1=有效,0=无效
Read (R)允许设备读取1=允许
Write (W)允许设备写入1=允许
Supervisor (S)特权级访问控制用于区分用户/管理域
Page Size页大小4KB、2MB、1GB大页
Address下一级表或物理页基址需按页对齐
Domain ID地址空间标识区分不同虚拟机/设备组

大页映射能显著减少页表级数和TLB压力。例如把一段1GB的直通设备BAR区域用1GB大页映射,只需一级表项即可覆盖,降低IOMMU翻译延迟。

四、中断重映射:让设备中断准确投递

设备直通后,设备产生的中断不能直接送到宿主,而应投递给拥有该设备的虚拟机vCPU。中断重映射表(Interrupt Remapping Table,IRT)把设备的中断请求(MSI/MSI-X中的地址与数据)翻译为“目标vCPU + 向量号”。其关键字段包括:

  • Source ID:发起中断的设备BDF。
  • Interrupt Index:中断重映射表项索引。
  • Destination ID:目标vCPU或物理CPU。
  • Vector:投递的中断向量。
  • Mode:兼容模式或重映射模式。

没有中断重映射时,设备中断可能被错误投递或无法投递,导致虚拟机“设备看似工作但无中断响应”。启用后,VMM只需配置好IRT,设备中断即可被硬件安全地路由到目标vCPU。

五、IOMMU与MMU的协同关系

MMU与IOMMU共享“地址翻译+权限检查”的抽象,但二者是独立硬件单元,协同体现在:

  • 页表格式相似:都采用多级页表,支持大页与权限位。
  • 缓存独立:CPU有TLB,IOMMU有IOTLB;二者不共享,需分别失效。
  • 地址空间衔接:CPU访问GPA经MMU翻译;设备访问GPA经IOMMU翻译,最终都落到HPA。
  • 一致性维护:修改页表后,需同时刷新TLB与IOTLB,否则会出现“CPU看到新映射、设备仍用旧映射”的不一致。

工程提示:在直通设备热插拔或迁移时,先停用设备DMA,再更新IOMMU页表并刷新IOTLB,最后恢复DMA,可避免设备使用过期映射访问错误内存。

六、典型场景与常见误区

场景:把一块NVMe SSD直通给虚拟机。VMM为该设备建立独立IOMMU域,把客户机物理地址映射到宿主物理地址,并配置中断重映射表,使SSD的MSI-X中断投递给虚拟机vCPU。虚拟机内驱动正常加载,DMA读写被限制在该域内。

误区1:认为“启用IOMMU就一定安全”。若页表权限过宽(如整段内存可读写),隔离效果会大打折扣。

误区2:忽略IOTLB刷新。修改映射后未刷新,设备可能继续使用旧翻译,导致数据损坏或故障。

误区3:把IOMMU故障当成设备故障。DMAR fault日志通常指向页表或权限问题,应先检查映射与设备BDF,而非直接更换硬件。

# 查看IOMMU故障日志(Linux示例)
dmesg | grep -i -E "DMAR|IOMMU|fault"
# 典型输出:
# DMAR: [DMA Read] Request device [00:02.0] fault addr 0x7f001000
# DMAR: Reason: 0x06 (Non-present page)

掌握IOMMU的DMA重映射、中断重映射、页表结构与MMU协同关系,是后续配置VFIO直通、SR-IOV、设备热迁移和性能调优的基础。只有把“地址翻译”和“中断投递”两条链路都打通,设备直通虚拟化才能既安全又高效。

IOMMU 架构原理:DMA重映射 · 中断重映射 · 地址转换 · 页表结构 · MMU协同 直通设备 BDF: 00:02.0 NVMe / GPU / NIC 发起 DMA 与 MSI-X 中断 DMA请求 中断请求 IOMMU DMA 重映射引擎 IOVA/GPA → HPA + 权限检查 中断重映射表 IRT Source ID → vCPU + Vector IOTLB 翻译缓存 缓存页表翻译结果 翻译后访问 宿主物理内存 HPA 地址空间 设备数据缓冲区 虚拟机内存页 中断投递 目标 vCPU 接收设备中断 IOMMU 多级页表结构(地址转换核心) PML4 顶级页表 9 bits PDPT 页目录指针 9 bits PD 页目录 9 bits PT 页表 9 bits 物理页 4KB / 2MB / 1GB Offset 12 bits IOMMU 与 MMU 协同关系 CPU MMU TLB 缓存 · 进程页表 IOMMU IOTLB 缓存 · 设备页表 宿主物理内存 HPA 最终访问目标 独立缓存 独立缓存