2. GPU内存映射基础:IOMMU/SMMU在SA8155中的作用
在SA8155显示子系统中,GPU与显示控制器通过系统内存管理单元(SMMU)实现虚拟地址到物理地址的转换。SMMU是ARM架构下的IOMMU实现,为GPU等非CPU设备提供地址翻译与内存保护能力。理解这一映射机制是排查显存分配异常、GPU page fault、显示内容错乱等问题的前提。
2.1 为什么GPU需要SMMU?
GPU直接操作物理地址存在三个核心问题:
- 内存碎片化:物理内存经过长时间分配释放后产生大量不连续区域,GPU需要连续大块显存时难以满足。
- 安全性:GPU若直接访问物理地址,可能越界读取其他进程或内核数据。
- 虚拟化支持:多虚拟机场景下,每个VM的GPU需要独立的地址空间隔离。
SMMU通过引入二级页表(Stage 2 translation)解决了上述问题:GPU看到的是连续的虚拟地址空间,SMMU将其映射到分散的物理页帧上,同时提供访问权限控制。
关键概念: SA8155集成的SMMU属于ARM MMU-500系列,支持多达32个上下文bank,每个bank可独立配置页表基地址和地址空间大小。
2.2 SA8155 SMMU架构概览
下图展示了SA8155中GPU与SMMU的硬件连接关系:
2.3 虚拟地址到物理地址的映射过程
GPU内存映射分为四级页表遍历(以4KB页粒度为例),SA8155的SMMU支持多种页大小(4KB/16KB/64KB/2MB/1GB)。映射过程如下表所示:
| 阶段 | 输入 | 页表级别 | 输出 | 说明 |
|---|---|---|---|---|
| 1 | VA[47:39] | L0 (PGD) | L1页表基地址 | 9位索引,512项 |
| 2 | VA[38:30] | L1 (PUD) | L2页表基地址 | 9位索引,512项 |
| 3 | VA[29:21] | L2 (PMD) | L3页表基地址 | 9位索引,512项 |
| 4 | VA[20:12] | L3 (PTE) | 物理页帧号PFN | 9位索引,512项 |
| 5 | VA[11:0] | 页内偏移 | 最终物理地址 | 与PFN组合 |
调试提示: 在SA8155上通过
cat /sys/kernel/debug/ion/mm/page_tables 可以查看当前GPU进程的页表映射情况。若出现"Unmapped"或"Invalid"条目,通常对应GPU page fault。
2.4 SMMU关键寄存器与配置
SA8155 SMMU的寄存器基地址位于 0x15000000(GPU SMMU实例)。调试中需要重点关注的寄存器组:
- SMMU_SCTLR(Stream Configuration Table Location Register):配置页表基地址和格式。
- SMMU_TTBR0/TTBR1(Translation Table Base Register 0/1):存放L0页表基地址,支持两个地址空间。
- SMMU_MAIR(Memory Attribute Indirection Register):定义内存属性(缓存策略、共享属性)。
- SMMU_FSR(Fault Status Register):记录最近一次地址转换错误类型。
- SMMU_FAR(Fault Address Register):触发错误的虚拟地址。
// 示例:读取SMMU故障寄存器(伪代码)
uint32_t fsr = readl(SMMU_BASE + 0x58); // SMMU_FSR offset
if (fsr & (1 << 0)) { // F_ASYNC bit
uint64_t far = readq(SMMU_BASE + 0x60); // SMMU_FAR
printf("SMMU Fault at VA: 0x%llx, FSR: 0x%x\n", far, fsr);
}
2.5 GPU显存分配与映射流程
在SA8155的显示栈中,GPU显存分配通常经过以下步骤:
- ION分配器:从系统内存中分配连续的物理内存块(通过DMA-BUF)。
- DMA-BUF导出:将物理内存封装为DMA-BUF对象,附带SG表(Scatter-Gather list)。
- SMMU映射:GPU驱动调用
iommu_map_sg()将SG表中的物理地址映射到GPU虚拟地址空间。 - 页表写入:SMMU驱动遍历页表,将虚拟地址与物理页帧写入L0~L3页表项。
- TLB刷新:映射完成后,通过
arm_smmu_tlb_inv_range()使失效TLB缓存。
常见异常: 若ION分配器返回的物理地址超出SMMU支持的地址范围(SA8155 SMMU支持48位物理地址),或SG表项未按页对齐,会导致映射失败,表现为GPU提交命令时返回 -ENOMEM 或 -EINVAL。
2.6 调试工具与方法
下表总结了SA8155上排查GPU内存映射问题的常用工具:
| 工具/接口 | 路径 | 用途 |
|---|---|---|
| dmesg | 内核日志 | 查看SMMU page fault、IOMMU错误 |
| trace-cmd | /sys/kernel/debug/tracing | 跟踪iommu_map/unmap调用 |
| IOMMU debugfs | /sys/kernel/debug/iommu | 查看每个设备的地址空间映射 |
| GPU devfreq | /sys/class/devfreq/... | 监控GPU内存带宽使用 |
| kgdb/jtag | 硬件调试 | 直接读取SMMU寄存器、页表内存 |
以下是一个典型的SMMU page fault调试流程:
# 1. 确认故障类型
dmesg | grep -i "iommu\|smmu\|page fault"
# 2. 查看故障地址和上下文
cat /sys/kernel/debug/iommu/arm-smmu/addresses
# 3. 检查GPU进程的页表
cat /sys/kernel/debug/ion/mm/page_tables | grep <pid>
# 4. 手动触发页表dump(需内核开启DEBUG选项)
echo 1 > /sys/kernel/debug/iommu/arm-smmu/dump_tables
2.7 映射异常案例分析
在SA8155实际项目中,最常见的映射异常是TLB未刷新导致的内存内容错乱。当GPU驱动修改页表后未正确调用TLB invalidation,SMMU仍使用缓存的旧映射,导致GPU读到错误的数据。典型现象:
- 显示画面出现撕裂或局部花屏。
- GPU渲染结果与预期不符,但无page fault报错。
- 重新分配显存后问题消失,但过一段时间复现。
排查要点: 在修改页表后,检查驱动是否调用了
arm_smmu_tlb_inv_range() 或 iommu_tlb_sync()。SA8155的SMMU要求TLB invalidation必须通过写入 SMMU_TLBIVAX 寄存器完成,且需要等待 SMMU_sTLBSYNC 寄存器确认完成。
下图展示了正常映射与TLB未刷新异常的对比:
2.8 本章小结
掌握SMMU地址映射原理是SA8155显示调试的基石。核心要点:
- SMMU为GPU提供虚拟地址到物理地址的转换,解决碎片化、安全性和虚拟化问题。
- 映射过程涉及四级页表遍历,任何一级页表项错误都会导致page fault。
- TLB缓存一致性是调试中的高频问题,必须确保页表修改后执行正确的invalidation序列。
- 利用debugfs、dmesg和trace-cmd可以快速定位映射异常。