4. SMMU硬件架构:ARM SMMUv2/v3模型、StreamID与SubstreamID、配置寄存器
ARM SMMU(System Memory Management Unit)是ARM架构下实现IOMMU功能的核心硬件单元,负责为DMA设备提供地址转换和内存保护。理解SMMU的硬件架构是进行DMA驱动开发与SMMU配置的基础。本节将深入剖析SMMUv2与v3模型的核心差异、StreamID与SubstreamID的寻址机制,以及关键的配置寄存器。
4.1 ARM SMMUv2 vs SMMUv3 模型对比
SMMUv2和SMMUv3是当前主流的两代架构。v3并非v2的简单升级,而是在设计哲学、接口协议和功能抽象上进行了重构。下表从关键维度对比两者的差异:
| 对比维度 | SMMUv2 | SMMUv3 |
|---|---|---|
| 接口协议 | 基于AMBA AXI/ACE 总线信号(带外信号传递StreamID) | 基于AMBA CHI 或 AXI,使用标准化的StreamID/SubstreamID 内联协议 |
| 配置方式 | MMIO 寄存器直接访问(每个SMMU实例有独立寄存器空间) | 基于内存的队列(Command Queue, Event Queue, PRI Queue)与MMIO结合 |
| 页表格式 | 支持ARMv7-A LPAE 和 ARMv8-A 页表格式 | 原生支持ARMv8-A 页表格式,并引入STE(Stream Table Entry)描述符 |
| SubstreamID | 不支持 | 支持,用于区分同一StreamID下的不同PASID(Process Address Space ID) |
| 性能优化 | TLB 通过广播或一致性协议维护 | 支持TLB 按需失效(CMDQ)、硬件预取、Stall/Abort 模型 |
| 虚拟化支持 | 支持Stage-2 转换(用于虚拟机) | 增强的Stage-2 支持,嵌套转换性能优化,支持SVA(Shared Virtual Addressing) |
| 中断模型 | 传统中断线(IRQ/FIQ) | MSI(Message Signaled Interrupts)或基于Event Queue 的事件通知 |
架构选型建议: 对于新设计的SoC,尤其是需要支持PCIe ATS/PRI、SVA或高性能虚拟化的场景,应优先选择SMMUv3。SMMUv2更适合对延迟敏感、配置固定的嵌入式系统。
4.2 StreamID 与 SubstreamID 寻址模型
StreamID 是SMMU识别DMA请求来源的唯一标识。在SMMUv3中,引入SubstreamID进一步细分同一设备内的不同进程上下文。
4.2.1 StreamID 定义与作用
- 定义: StreamID 是一个整数标识符,通常由总线主设备(如PCIe RC、DMA控制器)在发起事务时提供。在SMMU内部,StreamID用于索引Stream Table Entry(STE)。
- 作用: 决定该DMA请求使用哪个转换规则(Stage-1/Stage-2页表、是否bypass、安全域等)。
- 分配方式: 硬件设计时固定(如PCIe的Requester ID映射),或通过软件配置(如平台设备通过ACPI/IORT表分配)。
4.2.2 SubstreamID 与 PASID
- 定义: SubstreamID 是SMMUv3新增的字段,用于在同一个StreamID下区分不同的进程地址空间。通常与PCIe PASID(Process Address Space ID)对应。
- 作用: 实现SVA(Shared Virtual Addressing),允许设备直接访问进程的虚拟地址空间,无需驱动手动进行DMA映射。
- 组合寻址: SMMUv3使用
<StreamID, SubstreamID>二元组唯一确定一个转换上下文(Context Descriptor)。
关键概念: StreamID 标识“哪个设备”,SubstreamID 标识“设备上的哪个进程”。没有SubstreamID时,一个设备只能有一个DMA地址空间。
下图展示了StreamID与SubstreamID在SMMUv3中的寻址路径:
4.3 关键配置寄存器详解
SMMU的配置寄存器是驱动与硬件交互的接口。SMMUv2以MMIO寄存器为主,SMMUv3则引入基于内存的描述符队列。以下列出两类架构中最重要的寄存器。
4.3.1 SMMUv2 核心寄存器
| 寄存器名称 | 偏移 | 功能描述 |
|---|---|---|
| SMMU_CR0 | 0x000 | 控制寄存器0:全局使能、PTM模式、中断使能等 |
| SMMU_CR1 | 0x004 | 控制寄存器1:页表大小、地址空间大小配置 |
| SMMU_SMRn | 0x800 + n*8 | StreamID匹配寄存器:配置StreamID的掩码和值 |
| SMMU_S2CRn | 0x800 + n*8 + 4 | StreamID到Context Bank的映射寄存器 |
| SMMU_CB_BASE | 0x1000 | Context Bank基地址,每个Bank包含TTBR0/1、MAIR、ASID等 |
| SMMU_GR0_sTLBGEN | 0x064 | 全局TLB无效化寄存器,用于广播TLB失效 |
4.3.2 SMMUv3 关键配置接口
SMMUv3将大部分配置从MMIO寄存器迁移到内存中的描述符,通过Command Queue下发命令。核心MMIO寄存器仅用于控制队列和全局状态。
| 寄存器/队列 | 类型 | 功能描述 |
|---|---|---|
| SMMU_CMDQ | 内存队列 | Command Queue:驱动写入命令(如TLB无效、STE更新) |
| SMMU_EVTQ | 内存队列 | Event Queue:硬件写入事件(如转换错误、配置错误) |
| SMMU_PRIQ | 内存队列 | PRI Queue:处理PCIe PRI页请求 |
| SMMU_STRTAB_BASE | MMIO (0x0C0) | Stream Table基地址寄存器,指向内存中的STE数组 |
| SMMU_CR0 | MMIO (0x000) | 控制寄存器:使能SMMU、使能队列、设置Stall/Abort模式 |
| SMMU_CR1 | MMIO (0x004) | 控制寄存器1:配置队列大小、中断Coalescing |
| SMMU_IRQ_CTRL | MMIO (0x050) | 中断控制:使能/屏蔽Event Queue、PRI Queue、CMDQ错误中断 |
配置陷阱: SMMUv3的STE和Context Descriptor必须驻留在非Cacheable或Normal Cacheable但一致性的内存区域。驱动在更新STE后,必须通过CMDQ发送
CMD_PREFETCH_CONFIG 或 CMD_CFGI_STE 命令,确保硬件看到最新配置。
4.4 SMMUv3 STE 与 CD 描述符结构
STE(Stream Table Entry)和CD(Context Descriptor)是SMMUv3配置的核心数据结构。STE由StreamID索引,CD由SubstreamID索引。
4.4.1 STE 关键字段
- VALID (bit 0):STE是否有效。
- Config (bits [3:1]):配置模式(Bypass、Stage-1 only、Stage-2 only、Nested)。
- S1ContextPtr (bits [63:6]):指向Stage-1 Context Descriptor表的基地址。
- S2TTB (bits [63:12]):Stage-2 页表基地址。
- STRW (bits [5:4]):StreamID 匹配宽度。
4.4.2 CD 关键字段
- ASID (bits [15:0]):Address Space ID,用于TLB标记。
- TTBR0/TTBR1:Stage-1 页表基地址(支持两个地址空间)。
- MAIR (Memory Attribute Indirection Register):内存属性编码。
- HA/HD:硬件访问标志和脏页管理使能。
下图展示了STE与CD的层级关系:
4.5 配置流程示例(SMMUv3)
以下是一个简化的SMMUv3初始化与Stream配置流程,展示驱动如何操作硬件:
- 全局复位与使能: 读取
SMMU_CR0,设置SMMU_CR0.SMMUEN位使能SMMU。 - 配置队列基地址: 设置
SMMU_CMDQ_BASE、SMMU_EVTQ_BASE寄存器,分配内存队列。 - 分配STE表: 在内存中分配连续区域存放STE,将物理地址写入
SMMU_STRTAB_BASE。 - 填充STE: 根据设备StreamID,设置STE的Config字段(如Stage-1 only),并指向CD表基地址。
- 填充CD: 在CD表中设置TTBR0(指向进程页表)、ASID、MAIR等。
- 下发命令: 通过CMDQ发送
CMD_CFGI_STE命令,使硬件加载新的STE。 - 验证: 检查Event Queue是否有错误事件,确认配置生效。
驱动开发要点: SMMUv3的配置是“异步”的——驱动写入队列后,硬件异步处理。驱动必须轮询CMDQ的消费指针或等待中断,确认命令完成,才能进行后续DMA操作。