2. IOMMU与SMMU的关系:通用架构、异同与演进

好,我们进入第二章。这一章我打算把IOMMU和SMMU的关系彻底讲清楚。很多刚接触这个领域的工程师,包括我当年,都会困惑:这两个东西到底是不是一回事?为什么ARM体系里叫SMMU,而x86那边叫IOMMU?它们之间到底差在哪?

说白了,SMMU就是ARM体系下的IOMMU。但事情没这么简单。ARM为了在移动端、服务器端都能玩转,给SMMU加了不少私货。咱们今天就把这些私货一一拆开。

2.1 IOMMU通用架构

先看一张通用的IOMMU架构图。不管哪个厂商,核心思想都一样:让DMA设备也能访问虚拟地址。

核心思想:CPU有MMU,进程用虚拟地址。DMA设备没有MMU,直接物理地址。IOMMU就是给DMA设备配的“MMU”。

IOMMU通用架构 CPU 系统内存 IOMMU DMA设备 DMA设备 DMA设备 DMA设备通过IOMMU访问内存,IOMMU负责地址翻译和权限检查。 CPU访问内存走MMU,DMA访问内存走IOMMU,两者独立。

IOMMU的核心组件其实不多,我列个表大家就清楚了:

组件 功能 我踩过的坑
DMA重映射 将设备DMA请求中的地址翻译成物理地址 翻译表没配好,DMA直接写飞了
中断重映射 将设备中断路由到正确的CPU 中断路由错乱,系统直接panic
页表缓存(TLB) 缓存最近用过的地址翻译 TLB没刷干净,读到脏数据
权限检查 检查设备是否有权访问某段内存 权限设太松,设备乱读写

2.2 SMMU与IOMMU的异同

好,现在咱们来对比SMMU和IOMMU。我直接说结论:功能上,SMMU ≈ IOMMU + 缓存一致性 + ARM体系特有功能。

我的理解:SMMU就是ARM版的IOMMU,但ARM给它加了“缓存一致性”这个杀手锏。x86的IOMMU(VT-d/AMD-Vi)没有这个能力。

具体差异,我整理了一张表:

对比维度 IOMMU (x86) SMMU (ARM)
架构标准 VT-d (Intel) / AMD-Vi ARM SMMU架构规范
缓存一致性 不支持(需要软件维护) 支持(通过ACE/CHI总线)
页表格式 兼容x86页表 兼容ARM页表(支持2级/3级)
中断重映射 支持(MSI重映射) 支持(GICv3/v4集成)
虚拟化支持 支持(VT-d扩展) 支持(SMMUv3强化)
多级流控 有限 支持(Stream ID + Substream ID)

这里我要重点说一下缓存一致性。我在做某个项目时,x86平台下DMA写内存后,CPU读到的数据竟然是旧的。为什么?因为DMA绕过了CPU的Cache,直接写到了内存。CPU的Cache里还是老数据。这就是缓存不一致。

ARM的SMMU怎么解决?它通过ACE/CHI总线协议,让SMMU在DMA访问时,先通知CPU的Cache做窥探(Snoop),保证Cache和内存数据一致。说白了,就是DMA写内存时,CPU的Cache也跟着更新。

避坑指南:我曾经在调试SMMU时,发现DMA数据总是对不上。查了三天,最后发现是SMMU的缓存一致性没使能。ARM默认是关闭的,需要你在驱动里显式打开。这个坑,我替你们踩过了。

2.3 SMMU的演进历史

SMMU不是一天建成的。ARM从移动端杀到服务器端,SMMU也跟着一路进化。我按版本给大家捋一捋:

2.3.1 SMMUv1:初代目

  • 发布时间:ARMv7时代
  • 核心能力:基本地址翻译、权限控制
  • 局限:不支持虚拟化、TLB管理原始
  • 我的评价:能用,但别指望太多

2.3.2 SMMUv2:小步快跑

  • 改进点:支持2级页表、多Stream ID
  • 新增:TLB无效化命令、性能计数器
  • 应用:早期服务器芯片、网络设备
  • 我遇到的:TLB无效化命令有bug,需要workaround

2.3.3 SMMUv3:大版本升级

  • 发布时间:ARMv8.2时代
  • 核心变化:完全重写架构,支持虚拟化
  • 关键特性:
    • HTTU(硬件页表更新)
    • PRI(页请求接口)
    • MPAM(内存分区和监控)
    • Substream ID(细粒度流控)
  • 我的感受:这才是真正能打的东西

演进路线总结:SMMUv1(能用)→ SMMUv2(好用)→ SMMUv3(强大)。如果你现在做新设计,直接上SMMUv3,别犹豫。

我画了一张演进图,大家感受一下:

SMMU演进历史 SMMUv1 基本地址翻译 权限控制 ARMv7时代 SMMUv2 2级页表 多Stream ID TLB无效化 SMMUv3 虚拟化支持 HTTU/PRI Substream ID SMMUv1 → v2:功能增强,页表支持更灵活,TLB管理更精细。 SMMUv2 → v3:架构重写,虚拟化成为核心,缓存一致性原生支持。 当前主流:SMMUv3.1/v3.2,支持PCIe ATS/PRI等高级特性。

最后,我给大家一个选型建议:

  • 移动端/嵌入式:SMMUv2够用,资源占用少
  • 服务器/数据中心:必须SMMUv3,虚拟化和缓存一致性是刚需
  • 网络设备/加速器:SMMUv3 + PRI,支持页请求和按需映射

个人经验:我见过不少团队在选型时贪便宜用SMMUv2,结果后面虚拟化需求一来,整个架构要重做。我的建议是:一步到位SMMUv3,省得后面折腾。