Linux内核MMU设备DMA映射与SMMU配置实战工程 - 第1节

1.1 虚拟地址与物理地址:CPU视角的两层世界

在嵌入式Linux系统中,CPU执行指令时访问的地址并非直接对应硬件内存条上的物理位置。现代处理器通过内存管理单元(MMU)在程序与物理内存之间插入了一层抽象:程序看到的是虚拟地址(VA),而硬件最终访问的是物理地址(PA)。

概念 定义 特点
虚拟地址(VA) CPU内核发出的地址,由指令指针或访存指令产生 每个进程拥有独立的虚拟地址空间,大小由处理器位宽决定(如32位=4GB,64位可达16EB)
物理地址(PA) 内存控制器看到的实际硬件地址,对应DRAM芯片的存储单元 系统全局唯一,由物理内存容量决定(如2GB DDR4)
MMU 硬件单元,负责将VA转换为PA 位于CPU核心与内存总线之间,每个时钟周期完成一次转换
实战要点:在DMA编程中,设备直接使用物理地址访问内存,而CPU通常通过虚拟地址操作缓冲区。理解这两套地址体系的映射关系,是配置DMA引擎和SMMU的前提。

1.2 页表:地址转换的“翻译手册”

MMU将虚拟地址空间划分为固定大小的页(Page),物理地址空间划分为同样大小的页框(Page Frame)。页表就是记录虚拟页到物理页框映射关系的数据结构,存储在系统内存中。

1.2.1 页表项结构

每个页表项(PTE)包含物理页框号(PFN)和权限位(读/写/执行/用户/特权)。以ARMv8-A 4KB页为例,页表项格式如下:

// ARMv8-A 4KB页表项(64位)关键字段示意
// Bit [47:12] : 物理页框号(PFN)
// Bit [11]    : nG(非全局页)
// Bit [10]    : AF(访问标志)
// Bit [7:6]   : AP[2:1](访问权限)
// Bit [5]     : NS(非安全)
// Bit [4]     : XN(禁止执行)
// Bit [3]     : PXN(特权禁止执行)
// Bit [2]     : C(缓存属性)
// Bit [1]     : B(缓冲属性)
// Bit [0]     : Valid(有效位)

1.2.2 多级页表结构

现代64位处理器使用多级页表(通常为3~4级)来节省内存。以ARMv8-A的4级页表为例:

  1. PGD(页全局目录):顶级表,覆盖整个地址空间。
  2. PUD(页上级目录):第二级,细分PGD条目。
  3. PMD(页中间目录):第三级,进一步细分。
  4. PTE(页表项):末级表,直接指向物理页框。
关键指标:以4KB页、48位虚拟地址为例,4级页表共需4次内存访问才能完成一次地址转换。TLB的存在正是为了消除这4次访问的开销。

1.3 TLB:地址转换的“高速缓存”

TLB(Translation Lookaside Buffer)是MMU内部的一个硬件缓存,专门存储最近使用的虚拟地址到物理地址的映射关系。当CPU发出虚拟地址时,MMU首先在TLB中查找:

  • TLB命中:直接获得物理地址,零额外延迟。
  • TLB缺失:硬件遍历页表(或由软件填充),更新TLB后重试。
特性 TLB命中 TLB缺失
延迟 1~2个CPU周期 数十到数百个周期(取决于页表遍历深度)
功耗 极低 显著增加(需多次内存访问)
对DMA影响 CPU访问DMA缓冲区快 CPU访问DMA缓冲区慢,可能触发页表遍历
DMA陷阱:当DMA设备在物理内存中写入数据后,如果CPU对应的TLB条目尚未失效,CPU可能读到过时的缓存数据。必须使用dma_sync_single_for_cpu()等API确保一致性。

1.4 地址转换原理:从VA到PA的完整路径

下面通过一个具体的ARMv8-A 4KB页、4级页表示例,展示虚拟地址0x7F00_1234如何转换为物理地址。

  1. 拆分虚拟地址:0x7F00_1234 = 0x7F0_0_1_234(按9位索引拆分)。
  2. PGD索引:取[47:39]位,从TTBR0_EL1指向的PGD表中找到PUD基地址。
  3. PUD索引:取[38:30]位,从PUD表中找到PMD基地址。
  4. PMD索引:取[29:21]位,从PMD表中找到PTE基地址。
  5. PTE索引:取[20:12]位,从PTE表中找到物理页框号(PFN)。
  6. 组合物理地址:PFN + 页内偏移[11:0] = 最终物理地址。
性能优化:Linux内核支持大页(2MB/1GB),可以减少页表级数、提高TLB覆盖范围。对于DMA大缓冲区,建议使用大页映射以降低TLB缺失率。

1.5 地址转换全流程SVG图

下图展示了从CPU发出虚拟地址到MMU完成物理地址转换的完整数据流,包含TLB命中与缺失两条路径:

MMU地址转换全流程 MMU地址转换全流程(TLB命中/缺失) CPU核心 虚拟地址 VA TLB 查找 TLB 命中 TLB 缺失 页表遍历 物理地址 PA 内存控制器 说明: 1. 绿色路径(TLB命中):仅需1~2个CPU周期即可获得物理地址。 2. 橙色路径(TLB缺失):需遍历4级页表(4次内存访问),延迟增加数十倍。 3. 页表遍历完成后,新映射会写入TLB,后续相同地址的访问将命中。

1.6 地址转换与DMA的关联

在DMA操作中,设备直接使用物理地址访问内存,而CPU通过虚拟地址操作缓冲区。这种差异带来了两个核心问题:

问题 描述 解决方案
地址一致性 CPU看到的虚拟地址与DMA设备使用的物理地址不同 使用dma_map_single()将虚拟地址转换为物理地址,并返回给设备
缓存一致性 CPU缓存中的数据可能与DMA写入的物理内存不一致 使用dma_sync_single_for_device()/dma_sync_single_for_cpu()维护一致性
页表锁定 DMA操作期间,物理页框不能被换出 使用get_user_pages()锁定用户态页面,或使用DMA API自动处理
核心原则:在DMA传输完成前,CPU不得修改DMA缓冲区的虚拟地址映射;在DMA传输完成后,CPU必须通过缓存一致性API刷新缓存,才能安全访问数据。

1.7 本章小结

  • 虚拟地址是CPU编程视角的地址,物理地址是硬件访问内存的真实地址。
  • 页表是多级映射结构,记录VA到PA的转换关系,存储在系统内存中。
  • TLB是MMU内部的硬件缓存,加速地址转换,命中时仅需1~2周期。
  • 地址转换通过TLB命中/缺失两条路径完成,缺失时需遍历多级页表。
  • DMA编程必须处理地址一致性、缓存一致性和页表锁定三个关键问题。