2. GPU内存管理基础:物理内存与虚拟内存概念、GPU地址空间(GPA)与CPU地址空间(CPA)的区别、内存映射(MMIO)基础
2.1 物理内存与虚拟内存:GPU视角下的核心概念
在SA8155这样的异构SoC中,GPU和CPU共享同一片物理DRAM(LPDDR5),但两者对内存的访问方式和地址理解截然不同。理解物理内存与虚拟内存的差异,是掌握GPU内存管理的起点。
关键认知: GPU看到的“物理地址”与CPU看到的“物理地址”在硬件层面是同一块DRAM颗粒,但经过IOMMU/SMMU映射后,GPU和CPU各自拥有独立的虚拟地址空间。
2.1.1 物理内存(Physical Memory)
- 定义: SoC外部DRAM芯片的硬件存储单元,由内存控制器统一管理。
- 特点: 地址连续、容量固定、资源稀缺。
- GPU视角: GPU通过AXI总线直接访问物理地址(PA),但现代GPU几乎不直接操作PA,而是通过IOMMU进行地址转换。
2.1.2 虚拟内存(Virtual Memory)
- 定义: 由MMU(CPU侧)或IOMMU(GPU侧)提供的地址转换层,使每个进程/上下文拥有独立的地址空间。
- GPU优势:
- 碎片消除:GPU驱动可以分配不连续的物理页框,通过页表映射为连续的虚拟地址。
- 隔离保护:不同GPU上下文(Context)的虚拟地址空间互不干扰。
- 按需分配:虚拟地址范围远大于物理内存,允许延迟分配物理页。
实战提示: SA8155的GPU驱动(kgsl)在分配显存时,优先分配虚拟地址(GVA),物理页框在GPU实际访问时通过缺页中断按需填充。这种机制称为“惰性分配”(Lazy Allocation),能显著降低显存浪费。
2.2 GPU地址空间(GPA)与CPU地址空间(CPA)的区别
这是嵌入式GPU开发中最容易混淆的概念。SA8155的Adreno GPU拥有独立的地址空间,与CPU的地址空间在硬件上通过IOMMU/SMMU隔离。
| 对比维度 | CPU地址空间(CPA) | GPU地址空间(GPA) |
|---|---|---|
| 管理单元 | CPU MMU(ARMv8.2) | GPU IOMMU(SMMU v3) |
| 地址宽度 | 48位(虚拟地址)/ 40位(物理地址) | 48位(GPU虚拟地址GVA) |
| 页表格式 | 4级页表(L0-L3),4KB/64KB页 | 2级页表(TTBR0/TTBR1),4KB/64KB/2MB页 |
| 访问发起者 | CPU核心(Cortex-A76/A55) | GPU着色器核心(Shaders) |
| 缓存一致性 | 硬件ACE/CHI协议保证 | 需软件显式flush或使用IO-coherent |
| 典型映射范围 | 0x0000_0000_0000 ~ 0xFFFF_FFFF_FFFF | 0x0000_0000_0000 ~ 0x0000_FFFF_FFFF(用户区) 0xFFFF_0000_0000 ~ 0xFFFF_FFFF_FFFF(内核区) |
常见陷阱: 在SA8155上,CPU物理地址(CPA)和GPU物理地址(GPA)在硬件上指向同一DRAM地址,但经过IOMMU映射后,GPU看到的“物理地址”实际上是经过SMMU转换后的中间物理地址(IPA)。驱动开发时,切勿将CPU的物理地址直接写入GPU页表,必须通过IOMMU API进行映射。
2.3 内存映射(MMIO)基础
MMIO(Memory-Mapped I/O)是GPU驱动与硬件交互的核心手段。SA8155的Adreno GPU将控制寄存器、状态寄存器、FIFO队列等暴露为一段连续的物理地址区域,CPU通过读写这些地址来操控GPU。
2.3.1 MMIO区域布局
在SA8155的硬件手册中,GPU的MMIO基地址通常位于系统总线的高地址区域(例如0x1C00_0000 ~ 0x1C0F_FFFF)。驱动通过ioremap将其映射到内核虚拟地址空间。
/* SA8155 Adreno GPU MMIO 基地址与偏移示例 */
#define GPU_MMIO_BASE 0x1C000000
#define GPU_MMIO_SIZE 0x00100000 /* 1MB */
/* 关键寄存器偏移 */
#define REG_GPU_STATUS 0x0004 /* GPU运行状态 */
#define REG_GPU_CTRL 0x0008 /* GPU软复位/时钟门控 */
#define REG_GPU_FAULT_ADDR 0x0010 /* 页错误地址 */
#define REG_GPU_FAULT_STATUS 0x0014 /* 页错误状态码 */
#define REG_GPU_IOMMU_BASE 0x0100 /* IOMMU页表基地址 */
2.3.2 MMIO访问流程
- 物理地址获取: 从设备树(DTS)或ACPI表中读取GPU MMIO的物理基地址。
- 内核映射: 使用
devm_ioremap_resource()将物理地址映射到内核虚拟地址空间。 - 寄存器读写: 通过
readl()/writel()访问映射后的虚拟地址。 - 内存屏障: 在关键操作前后插入
mb()/wmb()保证顺序。
/* 内核驱动中MMIO映射与访问示例 */
static int gpu_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *mmio_base;
/* 1. 获取MMIO资源 */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
/* 2. 映射到内核虚拟地址空间 */
mmio_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mmio_base))
return PTR_ERR(mmio_base);
/* 3. 读取GPU状态寄存器 */
u32 status = readl(mmio_base + REG_GPU_STATUS);
dev_info(&pdev->dev, "GPU status: 0x%08x\n", status);
/* 4. 写入控制寄存器启动GPU */
writel(0x1, mmio_base + REG_GPU_CTRL);
wmb(); /* 确保写入完成 */
return 0;
}
性能要点: MMIO访问比普通内存访问慢2~3个数量级。在SA8155的GPU驱动中,高频路径(如提交命令队列)应尽量减少MMIO读写次数,优先使用内存中的Ring Buffer与Doorbell机制。
2.4 地址空间关系总览
下面的SVG图展示了SA8155中CPU地址空间、GPU地址空间以及IOMMU映射之间的完整关系。
2.5 本章小结
- 物理 vs 虚拟: GPU驱动通过虚拟地址(GVA)管理显存,物理页框由IOMMU按需映射,实现碎片消除和隔离保护。
- CPA vs GPA: CPU和GPU拥有独立的地址空间,通过SMMU/IOMMU进行地址转换。驱动开发时必须使用IOMMU API,不能直接传递CPU物理地址。
- MMIO基础: GPU控制寄存器通过MMIO暴露,驱动使用
ioremap+readl/writel访问,注意内存屏障和性能开销。