SMMU 技术文档整理

> 来源整理:基于 Linux 内核 IOMMU 文档与 arm-smmu-v3 驱动代码的技术总结。

一、背景:为什么需要 SMMU

在 SoC 或服务器平台里,外设(网卡、GPU、NPU、NVMe、DMA 控制器等)会直接发起 DMA 访问内存。问题是:

SMMU(System Memory Management Unit)本质上就是 ARM 体系下的 IOMMU:

如果一句话总结: SMMU 把“设备 DMA”纳入了和 CPU MMU 类似的受控内存管理体系。

二、SMMU 的核心概念

1. Stream 与 Stream Table

设备请求进入 SMMU 时,通常带有 Stream ID(SID)。SMMU 根据 SID 在 Stream Table 里找到对应配置(STE, Stream Table Entry),决定该请求:

你可以把它理解为“设备侧的进程上下文入口”。

2. Context Descriptor(CD)

当启用 Stage-1 时,STE 会进一步引用 Context Descriptor:

这让同一设备下不同地址空间(如 SVA/PASID 场景)成为可能。

3. 翻译阶段

在云和虚拟化平台里,Stage-2 对隔离边界尤其关键。

4. 队列模型(v3 重点)

SMMUv3 典型是队列驱动模型:

队列化模型有利于高并发吞吐和更清晰的软硬件接口。

三、Linux 内核里的 SMMU(arm-smmu-v3)

Linux 中 ARM SMMUv3 的核心驱动位于:

驱动工作大致分为:

1. 枚举与探测:从 ACPI/IORT 或 DeviceTree 获取 SMMU 实例与设备关系。 2. 域管理:创建并管理 iommu_domain,配置翻译模式。 3. 映射管理:通过通用 IOMMU API 维护 IOVA 映射。 4. 命令与失效:向 CMDQ 提交命令,执行 TLB/缓存失效。 5. 故障处理:消费 EVTQ/PRIQ,上报并恢复(或隔离)异常。

一个抽象流程可以写成:


设备发起 DMA(IOVA)
  -> SMMU 根据 SID 找到 STE/CD
  -> 执行页表遍历与权限检查
  -> 输出 PA 并访问内存
  -> 若缺页/权限错,事件进入 EVTQ/PRIQ

四、和 DMA API / IOMMUFD 的关系

在 Linux 驱动开发里,设备通常不直接“操纵 SMMU 寄存器”,而是走上层抽象:

因此,SMMU 在很多项目中属于“平台透明但性能/隔离关键”的基础设施。

五、详细机制讲解(工程视角)

1. 为什么要频繁失效(invalidate)

页表更新后,SMMU 侧缓存(TLB/ATC 等)不立即失效会导致设备继续用旧翻译。

后果包括:

所以“映射更新 + 正确失效时序”是稳定性的核心。

2. 故障分类常见点

典型 fault 原因:

调试时通常结合:

3. 性能与隔离的平衡

SMMU 打开后不是“白送性能”:

工程上通常目标是: 在满足隔离前提下,把映射策略和失效策略做成可预测、可批量化。

六、典型应用场景

场景 A:虚拟化与多租户

场景 B:高性能设备(GPU/NPU/DPU)

场景 C:安全与合规

七、落地建议(可直接用)

1. 先画清 DMA 数据流:谁发起 DMA、IOVA 从哪里来、映射谁负责。 2. 明确域模型:哪些设备共享域,哪些必须独立域。 3. 审计失效路径:map/unmap/权限变更后是否都触发了正确 invalidate。 4. 建立故障字典:把常见 fault code 映射到可执行排查步骤。 5. 压测观察:吞吐、尾延迟、fault rate 与失效率关联分析。

八、总结

SMMU 不是“可选优化项”,而是现代 ARM 平台设备内存访问的关键控制面。

它同时承担三件事:

对内核/驱动工程来说,真正的难点不在“知道它是什么”,而在把映射、失效、故障处理三条路径做成稳定且可验证的系统工程

---

参考资料

评论