3、SMMU架构详解:SMMU硬件组成(STE、CD、TBU、TCU)、Stream ID与Substream ID、SMMU与ARM体系结构的关系
好,咱们进入第三章。这一章我打算把SMMU的硬件骨架给你拆开看看。说白了,SMMU就是给IO设备用的MMU。你想想看,CPU有MMU,那DMA、GPU这些设备访问内存,谁来管?就是SMMU。
我个人习惯,看一个硬件模块,先看它的组成,再看它的数据流。SMMU也不例外。咱们先从它的核心部件讲起。
3.1 SMMU硬件组成:STE、CD、TBU、TCU
SMMU内部不是铁板一块。它分成了几个关键模块。我当年第一次看SMMU spec时,也被一堆缩写搞晕过。咱们一个一个来。
3.1.1 STE(Stream Table Entry)—— 流的“身份证”
每个连接到SMMU的设备,都有一个Stream ID。STE就是根据这个ID查到的配置项。它告诉SMMU:这个设备该怎么翻译地址、用哪个页表、权限如何。
我在项目中遇到过一个问题:某个加速器DMA老是报错,查了半天,发现是STE里配置的地址空间大小不对。设备访问的地址超出了范围,直接被SMMU拦下来了。嗯,STE的配置,一个字都不能错。
STE关键字段:
- Config:决定是否启用翻译(bypass、fault、translate)
- TTB0/TTB1:页表基地址,类似CPU的TTBR0/1
- ASID:地址空间ID,用于TLB区分不同进程
- S1DSS:Stage1的地址空间大小配置
3.1.2 CD(Context Descriptor)—— 进程的“上下文”
CD是STE的下级结构。一个STE可以指向多个CD,每个CD对应一个进程(Substream)。你想想看,一个GPU可能有几十个上下文在跑,每个上下文有自己的页表。CD就是用来描述这些上下文的。
说白了,STE管设备,CD管进程。这个分层设计,让SMMU能同时服务多个虚拟化环境。
我的经验:调试时,先看STE是否配置正确,再看CD。如果STE配错了,CD再对也没用。我曾经在bring-up阶段,花了三天才意识到STE的Config字段被默认设成了bypass,导致所有翻译都没生效。
3.1.3 TBU(Translation Buffer Unit)—— 翻译的“缓存”
TBU就是SMMU里的TLB。它缓存最近用过的地址翻译结果。为什么需要它?因为查页表太慢了,要走内存。TBU能大幅提升翻译速度。
每个TBU通常对应一个或多个设备。比如,一个PCIe RC可以挂一个TBU。TBU的大小和关联度,直接影响性能。
3.1.4 TCU(Translation Control Unit)—— 翻译的“大脑”
TCU负责控制逻辑。它管理TBU的一致性、处理缺页异常、协调Stage1和Stage2的翻译。你可以把TCU理解为SMMU的控制器,TBU是它的缓存。
TCU和TBU之间通过内部总线通信。有些设计中,TCU是全局的,TBU是分布式的。这种架构的好处是:TBU靠近设备,延迟低;TCU统一管理,逻辑简单。
注意:TBU和TCU之间的一致性维护是个坑。如果多个TBU缓存了同一个地址的翻译,其中一个被invalidated,其他TBU必须同步。我曾经遇到一个bug,就是TBU之间没有正确同步,导致DMA读到了旧数据。
3.2 Stream ID与Substream ID
这两个概念,是理解SMMU地址翻译的关键。
3.2.1 Stream ID —— 设备的“身份证号”
每个发起DMA请求的设备,都有一个唯一的Stream ID。这个ID通常由硬件连接方式决定。比如,PCIe设备的BDF号可以映射成Stream ID。
SMMU收到一个请求时,先用Stream ID查STE。找到对应的配置后,才知道怎么翻译这个请求的地址。
我建议你在设计系统时,给每个设备分配固定的Stream ID。不要动态变化,否则调试起来会非常痛苦。
3.2.2 Substream ID —— 进程的“身份证号”
Substream ID是Stream ID的补充。一个设备可以有多个Substream。比如,一个支持多个进程的GPU,每个进程可以分配一个Substream ID。
SMMU用Stream ID找到STE,再用Substream ID找到CD。这样,同一个设备的不同进程,就能使用不同的页表,实现地址隔离。
说白了,Stream ID是“谁在发请求”,Substream ID是“哪个进程在发请求”。
翻译流程:
- 设备发起DMA请求,携带Stream ID和Substream ID
- SMMU用Stream ID查STE,获取Stage1和Stage2的配置
- 如果启用了Substream,用Substream ID查CD,获取进程的页表
- 执行Stage1翻译(VA -> IPA)
- 执行Stage2翻译(IPA -> PA)
- 返回物理地址,访问内存
3.3 SMMU与ARM体系结构的关系
SMMU不是凭空出现的。它和ARM的体系结构紧密相关。
3.3.1 与CPU MMU的相似性
SMMU的翻译机制,和CPU的MMU非常像。它也支持Stage1和Stage2翻译,也使用页表,也有TLB。你如果熟悉ARMv8的MMU,学SMMU会很快。
但有一个关键区别:CPU MMU是给软件用的,SMMU是给硬件设备用的。CPU MMU的页表由OS管理,SMMU的页表由SMMU驱动管理。
3.3.2 与GIC的关系
SMMU和GIC(通用中断控制器)也有关系。当SMMU检测到翻译错误时,会触发一个中断。这个中断通过GIC路由到CPU。
我记得有一次,SMMU报了一个“Stepped Fault”,但CPU没收到中断。查了半天,发现是GIC的配置没设好,中断被mask掉了。嗯,这种跨模块的问题,最让人头疼。
3.3.3 与内存系统的关系
SMMU位于设备和内存之间。它翻译地址后,通过AXI总线访问内存。SMMU的页表也存放在内存中。所以,SMMU本身也会产生内存访问。
这里有个性能问题:SMMU查页表时,如果TLB miss,就要访问内存。这个延迟会影响设备性能。所以,TBU的大小和命中率,是设计时需要考虑的重点。
避坑指南:我曾经在一个项目中,SMMU的页表放在DDR里,但DDR的延迟很高。结果GPU的性能下降了30%。后来我们把页表移到了SRAM里,问题才解决。所以,页表的位置,直接影响性能。
3.4 知识体系结构图
下面这张图,帮你理清SMMU的核心逻辑。我画的是数据流和模块关系。
这张图展示了SMMU的核心数据流。设备发起请求,携带Stream ID和Substream ID。SMMU用它们查STE和CD,获取翻译配置。TBU缓存翻译结果,TCU控制整个流程。最后,翻译后的物理地址访问内存。
嗯,这一章的内容就到这里。SMMU的硬件组成,说白了就是STE、CD、TBU、TCU这四个部分。Stream ID和Substream ID是翻译的钥匙。SMMU和ARM体系结构的关系,体现在它与CPU MMU、GIC、内存系统的协同上。搞懂了这些,你就掌握了SMMU的骨架。