3. SMMU核心数据结构:Stream Table、Context Descriptor、Stage 1/2 页表
好,咱们进入正题。SMMU 这东西,说白了就是个地址翻译和权限管控的硬件模块。你写驱动也好,调性能也罢,最终都要跟它的数据结构打交道。我个人习惯把这三块——Stream Table、Context Descriptor、Stage 1/2 页表——称为 SMMU 的「三驾马车」。搞不懂它们,调试的时候你连日志都看不懂。
3.1 Stream Table:设备身份的「户口本」
每个连接到 SMMU 的设备,都有一个唯一的 Stream ID。硬件发起事务时,会拿着这个 ID 去查 Stream Table。你可以把它理解成派出所的户籍系统——先找到这个人,再看他的权限和配置。
Stream Table 有两种组织形式:线性和 2级。我遇到过不少工程师一上来就选 2 级,觉得省内存。其实对于设备数量少于 64 个的场景,线性表更简单,查表延迟也更低。
| 特性 | 线性 Stream Table | 2级 Stream Table |
|---|---|---|
| 内存占用 | 连续大块,浪费可能多 | 按需分配,节省内存 |
| 查表延迟 | 固定,一次访存 | 两次访存,延迟略高 |
| 适用场景 | 设备少(<64),性能敏感 | 设备多(>256),内存受限 |
| 配置复杂度 | 低,基地址+大小即可 | 高,需配置 L1/L2 基址 |
Stream Table 的每个条目叫 STE(Stream Table Entry)。STE 里最重要的字段就是 Context Descriptor 指针。它指向了下一步要用的配置结构体。
3.2 Context Descriptor:翻译规则的「指挥中心」
Context Descriptor(CD)是 SMMU 里承上启下的关键。它告诉硬件:这个设备用哪个页表?是 Stage 1 还是 Stage 2?要不要做嵌套翻译?
CD 里有两个核心指针:
- TTB0/TTB1:Stage 1 页表的基地址。TTB0 通常用于进程地址空间,TTB1 用于内核或全局映射。
- VTTB:Stage 2 页表的基地址。在虚拟化场景下,由 Hypervisor 管控。
我记得有一次调试 GPU 驱动,发现某个上下文切换后地址翻译全乱套了。查了两天才定位到——CD 里的 ASID(Address Space ID)字段没更新。硬件用 ASID 来区分 TLB 条目属于哪个进程,你忘了改,那可不就乱了吗?
3.3 Stage 1/2 页表:两层翻译的「分工协作」
这是 SMMU 最核心的能力——两阶段地址翻译。Stage 1 由 OS 管理,负责虚拟地址(VA)到中间物理地址(IPA)的映射。Stage 2 由 Hypervisor 管理,负责 IPA 到真实物理地址(PA)的映射。
为什么要搞两层?说白了就是为了虚拟化。Guest OS 管自己的进程,Hypervisor 管物理内存。两边各管各的,互不干扰。
页表的层级结构(4KB 页为例):
- L0/L1 表:覆盖大范围,每个条目指向下一级表。
- L2 表:中等粒度,每个条目指向 L3 表或直接映射 2MB 块。
- L3 表:最细粒度,每个条目映射 4KB 页。
我建议你在调优时重点关注 块映射(Block Mapping)。如果设备访问的是连续大块内存(比如显示缓冲区),直接用 L2 的 2MB 块映射,能大幅减少页表遍历次数和 TLB 压力。
3.4 三者的协作流程
来,我们画个图,把这三块串起来。设备发起一次内存访问,SMMU 内部是怎么一步步找到物理地址的?
流程很清晰:
- 设备发起 DMA 请求,携带 Stream ID。
- SMMU 用 Stream ID 查 Stream Table,找到对应的 STE。
- STE 指向 Context Descriptor,CD 里存着页表基地址和配置。
- 硬件先走 Stage 1 页表(VA→IPA),再走 Stage 2 页表(IPA→PA)。
- 最终拿到物理地址,访问内存。
perf stat -e smmu_tlb_miss 先看整体缺失率,再用 smmu_debugfs 导出页表统计信息,分析大页使用情况。
3.5 关键配置参数速查
最后,我整理了一张常用配置参数表。调试的时候对照着看,能省不少时间。
| 参数 | 所属结构 | 作用 | 常见错误 |
|---|---|---|---|
| StreamID | 事务请求 | 标识设备 | ID 超出范围,查不到 STE |
| STE.S1ContextPtr | Stream Table | 指向 Stage 1 CD | 指针未对齐,触发异常 |
| CD.TTB0 | Context Descriptor | Stage 1 页表基址 | 地址写错,翻译全乱 |
| CD.ASID | Context Descriptor | 标识地址空间 | 未更新,TLB 命中错误 |
| Stage1/2 页表 | 页表层级 | VA→IPA→PA 映射 | 权限位设置错误,触发 Fault |