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事务被终止。
图中可见,设备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配置正确,再调试性能与缓存属性。