3、IOMMU(SMMU)原理:SMMU硬件架构、页表与转换、TLB与缓存一致性

在SA8155平台中,SMMU(System Memory Management Unit,系统内存管理单元)是GPU与系统内存之间的关键桥梁。它负责将GPU等外设发起的设备虚拟地址(Device Virtual Address, DVA)转换为物理地址(Physical Address, PA),并提供内存保护与隔离机制。本章深入剖析SMMU的硬件架构、页表转换机制、TLB工作原理以及缓存一致性问题。

3.1 SMMU硬件架构

SMMU本质上是一种专为外设设计的IOMMU(Input-Output Memory Management Unit)。在SA8155中,SMMU集成在系统总线上,位于GPU、显示控制器等主设备与内存控制器之间。其核心架构包含以下组件:

核心组件:
  • Translation Control Unit (TCU):负责执行页表遍历(Page Table Walk),是SMMU的运算核心。
  • Translation Buffer Unit (TBU):包含TLB(Translation Lookaside Buffer),缓存最近使用的页表转换结果。
  • Context Banks:每个Context Bank对应一个独立的地址空间,用于隔离不同设备或不同进程的地址映射。
  • Stream ID (SID) 与 Substream ID (SSID):SID标识主设备,SSID标识设备内的不同上下文(如进程),用于路由转换请求。
  • PMU (Performance Monitoring Unit):用于统计TLB命中率、页表遍历次数等性能指标。
SMMU硬件架构图 SMMU硬件架构图 GPU 主设备 显示控制器 主设备 其他外设 主设备 SMMU TCU 页表遍历引擎 TBU (TLB) 转换缓存 Context Banks PMU 内存控制器 DDR SID/SSID 标识设备与上下文

3.2 页表(Page Table)与转换(Translation)

SMMU使用多级页表结构将设备虚拟地址(DVA)转换为物理地址(PA)。SA8155的SMMU支持多达4级页表,与ARMv8 CPU的页表格式兼容,便于统一管理。

3.2.1 页表层级结构

页表级别 粒度 覆盖范围 典型用途
L0 (PGD) 512GB 整个地址空间 顶级页表,指向L1页表
L1 (PUD) 1GB 大块内存区域 映射大块连续显存
L2 (PMD) 2MB 中等粒度 纹理、帧缓冲
L3 (PTE) 4KB 小粒度 细粒度分配、稀疏映射
实战提示:GPU驱动中,显存分配通常优先使用2MB或1GB大页(Huge Page),以减少页表级数和TLB压力,提升GPU访问性能。

3.2.2 地址转换流程

当GPU发起内存访问时,SMMU执行以下转换步骤:

  1. 输入:GPU发出设备虚拟地址(DVA)和Stream ID。
  2. TLB查找:SMMU首先在TLB中查找DVA对应的物理地址。
  3. TLB命中:直接返回物理地址,访问内存。
  4. TLB未命中:TCU启动页表遍历(Page Table Walk),从L0到L3逐级查找。
  5. 权限检查:验证访问权限(读/写/执行)和内存属性(可缓存、可共享等)。
  6. 返回结果:将转换结果写入TLB,并返回物理地址。
SMMU地址转换流程图 SMMU地址转换流程图 GPU发起DVA + Stream ID TLB查找 命中? TLB命中 返回PA TLB未命中 启动页表遍历 页表遍历 L0→L1→L2→L3 权限检查 读/写/执行 转换结果写入TLB 后续访问加速

3.3 TLB(Translation Lookaside Buffer)与缓存一致性

TLB是SMMU中关键的硬件缓存,用于加速地址转换。然而,在多核异构系统中,TLB与CPU缓存、GPU缓存之间的数据一致性是必须解决的核心问题。

3.3.1 TLB结构与管理

TLB类型 存储内容 特点
微TLB (Micro TLB) 最近使用的少量条目 极低延迟,容量小(通常32-64条)
主TLB (Main TLB) 大量转换条目 容量大(512-1024条),命中率更高
共享TLB (Shared TLB) 多Context共享 减少重复缓存,节省面积

3.3.2 TLB无效化(TLB Invalidation)

当页表被修改(如释放显存、更改映射)时,必须使对应的TLB条目失效,否则SMMU可能使用过时的转换结果,导致数据错误或安全漏洞。

关键风险:TLB未及时无效化是GPU驱动中常见的Bug来源。例如,在释放显存后未执行TLB无效化,可能导致后续分配的内存被错误映射,引发数据泄露或GPU崩溃。

TLB无效化操作分为两种粒度:

  • 全局无效化:清除所有TLB条目,开销大,但简单可靠。
  • 按地址空间无效化:仅清除特定Context Bank或特定地址范围的TLB条目,效率更高。

3.3.3 缓存一致性问题

在SA8155中,GPU、CPU、DSP等多个主设备共享系统内存。SMMU的页表属性中包含了内存类型和共享属性,用于控制缓存一致性:

内存属性 描述 适用场景
Non-cacheable 不缓存,直接访问内存 寄存器、同步变量
Write-back Cacheable 回写缓存,延迟写入 纹理、帧缓冲(性能优先)
Write-through Cacheable 写直达缓存,立即写入内存 共享数据,需要实时可见
Inner Shareable 在CPU集群内保持一致 CPU与GPU共享数据
Outer Shareable 在系统全局保持一致 多主设备共享(GPU+DPU+VPU)
缓存一致性与TLB关系图 缓存一致性与TLB关系图 CPU L1/L2 Cache MMU (TLB) GPU GPU Cache SMMU (TLB) 系统内存 DDR 共享数据 缓存一致性总线 (CCI/ACE) TLB无效化触发条件 页表修改 | 显存释放 | 进程切换 内存属性变更 | 安全域切换

3.4 实战要点:SMMU配置与调试

在SA8155 GPU驱动开发中,SMMU配置涉及以下关键步骤:

SMMU初始化流程:
  1. 解析设备树:获取SMMU寄存器基地址、中断号、Stream ID映射表。
  2. 复位与使能:复位SMMU硬件,使能TCU和TBU。
  3. 配置Context Bank:为GPU分配独立的Context Bank,设置页表基地址寄存器(TTBR)。
  4. 设置Stream ID:将GPU的Stream ID绑定到对应的Context Bank。
  5. 分配页表:在内存中分配页表结构,建立DVA到PA的映射。
  6. 使能转换:设置SMMU_CRx寄存器,使能地址转换。

调试SMMU问题时,常用的手段包括:

  • 读取SMMU故障寄存器:如SMMU_FSR(Fault Status Register),获取转换错误类型和地址。
  • 检查页表内容:通过dump页表内存,验证映射是否正确。
  • 使用PMU统计:监控TLB命中率,判断是否需要调整页表粒度。
  • TLB无效化验证:在关键操作前后执行TLB无效化,观察是否解决数据不一致问题。
// 示例:SMMU故障寄存器读取(伪代码)
uint32_t fsr = readl(smmu_base + SMMU_FSR);
if (fsr & FSR_TF) {
    uint32_t far = readl(smmu_base + SMMU_FAR);  // 故障地址
    uint32_t sid = readl(smmu_base + SMMU_FSYNR0); // Stream ID
    printf("SMMU Fault: addr=0x%x, sid=0x%x\n", far, sid);
    writel(fsr, smmu_base + SMMU_FSR);  // 清除故障
}
性能优化建议:
  • 使用2MB大页映射GPU频繁访问的显存区域,减少TLB压力。
  • 在进程切换时,使用按地址空间TLB无效化而非全局无效化,降低开销。
  • 对于只读数据(如纹理),设置页表属性为只读,防止意外写入。