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、设备热迁移和性能调优的基础。只有把“地址翻译”和“中断投递”两条链路都打通,设备直通虚拟化才能既安全又高效。