3. IOMMU与SMMU概述

在DMA驱动开发中,设备直接访问内存时使用的是物理地址或总线地址,而CPU侧看到的是虚拟地址。当系统引入虚拟化、安全隔离或大地址空间设备时,设备访问地址与真实物理内存之间就需要一层“地址翻译与权限检查”机制。IOMMU与SMMU正是承担这一职责的硬件单元。理解它们的定义、区别、系统位置与作用,是排查DMA映射失败、SMMU fault、虚拟机直通异常等问题的基础。

3.1 定义:IOMMU与SMMU是什么

IOMMU(Input/Output Memory Management Unit)是位于设备与系统内存之间的地址翻译与访问控制单元。它把设备发出的IO虚拟地址(IOVA)翻译为物理地址(PA),并可对访问权限、缓存属性、中断重映射进行管理。SMMU(System Memory Management Unit)是ARM体系结构中对IOMMU类硬件的称呼,常见于ARMv7/v8平台,负责将设备DMA请求中的地址按页表规则翻译并做权限校验。

从工程视角看,两者本质相同:都是“设备侧MMU”。区别主要来自体系结构与术语习惯:x86平台通常称IOMMU,ARM平台通常称SMMU;Intel的实现常称VT-d,AMD称AMD-Vi,ARM则称SMMUv1/v2/v3。驱动开发中,Linux统一用IOMMU子系统抽象,通过DMA API、IOMMU domain、Stream Table等机制对接不同硬件。

核心理解:IOMMU/SMMU不是CPU的MMU,而是面向外设DMA的地址翻译与保护单元。CPU MMU管CPU访问,IOMMU/SMMU管设备访问。

3.2 系统架构位置与数据通路

在典型SoC中,CPU、内存控制器、外设与IOMMU/SMMU通过总线互连。设备发起DMA时,请求先经过SMMU,SMMU根据Stream ID或Requester ID找到对应页表,完成IOVA到PA的翻译和权限检查,再访问内存。若翻译失败或权限不足,则产生SMMU fault,DMA事务被终止。

IOMMU / SMMU 在系统中的位置与DMA翻译通路 CPU CPU MMU 虚拟地址 → 物理地址 DMA设备 网卡 / NVMe / GPU 发出 IOVA 访问请求 IOMMU / SMMU Stream Table / Context 页表遍历 · 权限检查 IOVA → PA 翻译 中断重映射 · 缓存属性 系统内存 物理地址空间 DMA缓冲区 页表 / 描述符 DMA请求 翻译后访问 配置页表 SMMU Fault 翻译失败 / 权限不足 DMA事务被终止 Linux IOMMU子系统 DMA API · IOMMU domain Stream Table 配置

图中可见,设备DMA请求先到SMMU,SMMU查表后访问内存;CPU通过IOMMU子系统配置页表与Stream Table。若配置错误,SMMU会报fault,DMA无法完成。

3.3 主要功能:翻译、隔离、重映射与安全

IOMMU/SMMU的功能可归纳为四类:

  • 地址翻译:将设备IOVA翻译为物理地址,支持多级页表和大地址空间。
  • 访问隔离:每个设备或设备组拥有独立页表,防止设备越权访问其他进程或内核内存。
  • 中断重映射:将设备MSI/MSI-X中断映射到正确的中断控制器与CPU,支持虚拟化中断注入。
  • 安全与虚拟化:在虚拟机直通场景中,SMMU把Guest的IOVA翻译到Host物理地址,实现设备隔离与安全域划分。

在虚拟化中,IOMMU/SMMU使能“设备直通”:Guest直接操作设备,SMMU负责地址翻译与隔离,避免Hypervisor频繁陷入。在安全场景中,SMMU可限制设备只能访问指定内存区域,防止DMA攻击。

3.4 区别与联系:IOMMU与SMMU对照

对比项 IOMMU SMMU
体系结构 x86、部分RISC-V平台 ARMv7/v8平台
常见实现 Intel VT-d、AMD-Vi ARM SMMUv1/v2/v3
设备标识 Requester ID / BDF Stream ID / SID
页表格式 多级页表,兼容CPU页表 ARM VMSAv8页表格式
Linux抽象 统一IOMMU子系统 统一IOMMU子系统
核心作用 DMA翻译、隔离、中断重映射 DMA翻译、隔离、中断重映射

联系在于:两者都通过Linux IOMMU子系统管理,驱动开发者使用DMA API时无需直接操作硬件寄存器;区别在于硬件寄存器、Stream Table/Context结构、页表格式与fault上报方式不同。排查问题时,需要根据平台查看对应的SMMU或IOMMU寄存器与日志。

3.5 案例与场景:SMMU fault排查

某ARM平台NVMe驱动在启用SMMU后DMA失败,内核日志出现:

arm-smmu 15000000.smmu: Unhandled context fault: fsr=0x402, iova=0xffff0000, sid=0x1
dmaengine: failed to map DMA buffer
nvme 0000:01:00.0: DMA mapping error

分析:fsr=0x402表示翻译错误,iova=0xffff0000不在有效映射范围,sid=0x1对应NVMe设备。常见原因是驱动未正确调用dma_map_sg或IOMMU domain未附加到设备。修复方式:确认设备已加入正确IOMMU group,检查dma_set_mask与dma_map_sg返回值,确保IOVA由DMA API分配而非硬编码。

误区:认为“启用SMMU后DMA地址就是物理地址”。实际上设备看到的是IOVA,必须经SMMU翻译;直接使用物理地址会导致fault或数据损坏。

3.6 复盘要点

  • IOMMU与SMMU本质相同,都是设备侧地址翻译与保护单元。
  • 系统位置在设备与内存之间,DMA请求必须经过它。
  • 核心功能:翻译、隔离、中断重映射、虚拟化与安全。
  • Linux统一用IOMMU子系统管理,驱动通过DMA API使用。
  • 排查SMMU fault时,关注fsr、iova、sid与IOMMU domain配置。

工程建议:在DMA驱动开发中,始终使用dma_alloc_coherent、dma_map_single等标准API,不要假设设备地址等于物理地址;启用SMMU后,先确认IOMMU group与Stream Table配置正确,再调试性能与缓存属性。