2. SMMU基础架构

好,咱们正式开始啃SMMU的核心概念。说实话,这六个术语——IOVA、PA、STE、CD、TLB、页表遍历——就是整个SMMU的骨架。你把这六个东西搞明白了,后面调优、排错、甚至看芯片手册,都会顺很多。

我见过不少工程师,上来就盯着代码调性能,结果连IOVA和PA的映射关系都没理清。嗯,这就像修车不看发动机,光在那擦轮毂。咱们今天就把发动机拆开,一个一个讲透。

2.1 IOVA 与 PA:设备眼中的“虚拟地址”

先问个问题:为什么要有IOVA?

CPU有虚拟地址(VA),是为了隔离进程、方便内存管理。那设备呢?设备直接访问物理地址(PA)不行吗?

行,但很痛苦。你想想看,如果设备直接操作PA,那驱动分配内存时就得申请连续的物理内存。一旦系统跑久了,内存碎片化严重,大块连续物理内存根本申请不到。我早年做网络驱动时就踩过这个坑——申请2MB的DMA缓冲区,系统说“没有”,然后整个功能就挂了。

IOVA(I/O Virtual Address)就是来解决这个问题的。它是设备看到的“虚拟地址”,通过SMMU页表映射到真正的物理地址。

核心关系:

  • IOVA:设备发起的访问地址(设备视角)
  • PA:内存控制器看到的真实物理地址(系统视角)
  • SMMU:负责把IOVA翻译成PA

说白了,IOVA让设备可以访问不连续的物理内存,而设备自己完全感知不到。驱动只需要分配IOVA空间,SMMU在背后搞定映射。这跟CPU的MMU做虚拟地址映射是一个道理。

概念 谁在用 特点
IOVA 设备(DMA引擎、GPU、网卡) 连续、隔离、可映射到任意PA
PA 内存控制器、CPU直接访问 真实物理位置、可能不连续

个人习惯:我在设计SMMU页表时,会先把IOVA空间规划好。比如给GPU分配一段连续的IOVA区间,给网卡分配另一段。这样后面调页表缓存命中率时,心里有底。

2.2 STE 与 CD:SMMU的“配置入口”

有了IOVA和PA,SMMU怎么知道该为哪个设备做映射?这就轮到STE和CD上场了。

STE(Stream Table Entry)

每个连接到SMMU的设备都有一个Stream ID。你可以把Stream ID想象成设备的“身份证号”。SMMU拿到这个ID后,就去查STE表。

STE里存了什么?

  • 这个设备是否启用SMMU翻译
  • 如果启用,指向哪个页表(通过CD)
  • 一些安全属性、缓存策略等

我举个例子:系统里有一块网卡和一个GPU。网卡的Stream ID=0,GPU的Stream ID=1。SMMU根据ID找到对应的STE,然后决定:网卡走页表A,GPU走页表B。这样两个设备的地址空间就完全隔离了。

CD(Context Descriptor)

CD是STE的下级结构。它描述了一个地址空间的详细信息:

  • 页表基地址(TTBR)
  • 页表格式(4KB页、64KB页、还是混合)
  • ASID(Address Space ID,用于TLB标记)
  • 翻译粒度、权限控制等

你可以这样理解:STE是“哪个设备”,CD是“用哪张页表”。

我曾经踩过的坑:有一次配置STE时,忘了设置CD的有效位。结果设备发起的DMA请求全部被SMMU以“翻译错误”为由拒绝了。查了两天才发现,就是一位没置1。所以,配置完STE后,一定要回读验证。

2.3 TLB:SMMU的“缓存加速器”

页表遍历是很慢的。每次IOVA翻译都要走一遍多级页表,内存访问次数多、延迟高。所以SMMU内部有TLB(Translation Lookaside Buffer),专门缓存最近用过的翻译结果。

TLB的工作原理:

  1. 设备发起IOVA访问
  2. SMMU先在TLB里找有没有这个IOVA的缓存条目
  3. 如果命中(TLB hit),直接拿到PA,快速完成访问
  4. 如果未命中(TLB miss),才去走页表遍历,然后把结果塞进TLB

TLB的性能影响有多大?我直接给数据:

场景 延迟(大致)
TLB命中 几个时钟周期
TLB未命中(页表遍历) 几十到上百个时钟周期

所以,TLB命中率直接决定了SMMU的翻译性能。后面章节我会专门讲怎么调TLB命中率,这里先记住:TLB是性能的关键。

2.4 页表遍历:SMMU的“翻译引擎”

当TLB未命中时,SMMU会启动页表遍历(Page Table Walk)。这个过程跟CPU的页表遍历非常像,但有几个关键区别:

  • 多级结构:ARM SMMU通常支持3级或4级页表。每一级指向下一级的基地址,最后一级才指向物理页框。
  • 硬件自动完成:页表遍历是SMMU硬件自动做的,软件只需要配置好页表基地址。
  • 缓存友好性:页表本身也占用内存访问。如果页表数据不在CPU缓存里,遍历就会很慢。

我画了一张图,帮你把整个流程串起来:

SMMU核心概念关系图 设备(Device) 发起 IOVA 访问 Stream ID 设备身份证 STE Stream Table Entry CD Context Desc TLB 翻译缓存 页表遍历 Page Table Walk 未命中 物理地址(PA) 最终目标 流程总结: 设备发起 IOVA → 通过 Stream ID 找到 STE → STE 指向 CD → CD 给出页表基地址 → 先查 TLB(命中则直接得到 PA)→ 未命中则走页表遍历 → 最终得到 PA

2.5 六个概念的关系总结

到这,六个核心概念就全了。我帮你理一下它们之间的逻辑链条:

  1. 设备发起DMA访问,使用的是IOVA
  2. SMMU根据设备的Stream ID找到对应的STE
  3. STE指向CD,CD里存着页表基地址
  4. SMMU先查TLB,看有没有缓存
  5. 如果没命中,启动页表遍历,把IOVA翻译成PA
  6. 翻译结果写入TLB,后续访问加速

一句话记住:STE找设备,CD找页表,TLB加速,页表遍历出PA。