2. ARMv8-A MMU 架构基础:页表层级、转换粒度、地址空间划分(TTBR0/TTBR1)

ARMv8-A 架构的 MMU(Memory Management Unit)是驱动内存隔离与设备兼容适配的核心硬件单元。它通过多级页表、可配置的转换粒度以及双地址空间机制,为操作系统提供了灵活的虚拟地址到物理地址的映射能力。理解这些基础概念,是后续实现驱动级内存保护与设备移植的前提。

2.1 页表层级与转换粒度

ARMv8-A 支持 4KB、16KB 和 64KB 三种页面粒度,并采用最多 4 级页表(Level 0 ~ Level 3)进行地址转换。页表层级数由虚拟地址宽度和页面粒度共同决定。下表总结了常见配置下的层级关系:

页面粒度 虚拟地址宽度 页表层级数 Level 0 覆盖范围 Level 3 页大小
4KB 48-bit 4 级 (L0~L3) 512GB 4KB
16KB 48-bit 4 级 (L0~L3) 512GB 16KB
64KB 48-bit 3 级 (L1~L3) 64TB (L1) 64KB
4KB 39-bit 3 级 (L1~L3) 1GB (L1) 4KB
实践要点: 在驱动开发中,4KB 粒度是最常用的配置,因为它与 Linux 内核的页框管理单元高度兼容。64KB 粒度常用于需要大块连续物理内存的场景(如 GPU 驱动),但会增大页表覆盖范围,减少页表层级。

下图展示了 4 级页表(4KB 粒度,48-bit 地址)的转换流程:

ARMv8-A 4级页表转换流程(4KB粒度,48-bit地址) 虚拟地址 [47:0] L0索引[47:39] L1索引[38:30] L2索引[29:21] L3索引[20:12] 页内偏移[11:0] L0 页表 L1 页表 L2 页表 L3 页表 物理地址 [47:0]
关键概念: 页表层级中的每个表项(PTE)包含物理地址基址和访问权限位。当 MMU 遍历页表时,如果某一级表项标记为“块”(Block),则直接形成物理地址,不再继续下一级遍历。这种机制允许大页映射(如 2MB 或 1GB),减少 TLB 压力。

2.2 地址空间划分:TTBR0 与 TTBR1

ARMv8-A 将虚拟地址空间划分为两个独立的区域,分别由两个页表基址寄存器控制:

  • TTBR0:用于低地址空间(通常为 0x0000_0000_0000_0000 起始),典型场景是用户空间。
  • TTBR1:用于高地址空间(通常为 0xFFFF_0000_0000_0000 起始),典型场景是内核空间。

这种划分使得操作系统可以在上下文切换时仅切换 TTBR0(用户空间页表),而 TTBR1(内核空间页表)保持不变,从而避免内核页表的重复刷新,提升性能。

寄存器 地址范围 典型用途 切换时机
TTBR0 0x0000_0000_0000_0000 ~ 0x0000_FFFF_FFFF_FFFF 用户进程地址空间 进程上下文切换
TTBR1 0xFFFF_0000_0000_0000 ~ 0xFFFF_FFFF_FFFF_FFFF 内核地址空间 仅初始化或内核升级时
驱动开发注意: 设备驱动通常运行在内核空间(TTBR1 区域),但访问用户空间缓冲区时,需要通过 copy_from_user / copy_to_user 等内核 API 进行安全拷贝,不能直接解引用用户空间指针。这是因为用户空间地址(TTBR0 区域)在当前上下文可能尚未映射或已被换出。

下图展示了 TTBR0 与 TTBR1 在 48-bit 地址空间中的划分关系:

ARMv8-A 虚拟地址空间划分(TTBR0 / TTBR1) 虚拟地址空间 [0x0000_0000_0000_0000 ~ 0xFFFF_FFFF_FFFF_FFFF] TTBR0 区域(低地址) 用户空间 / 进程私有 TTBR1 区域(高地址) 内核空间 / 全局共享 地址空间划分规则: • 虚拟地址的最高位(bit[47])决定使用 TTBR0 还是 TTBR1。 • 当最高位为 0 时,MMU 自动选择 TTBR0;为 1 时选择 TTBR1。 • 这种硬件自动选择机制无需软件干预,上下文切换效率极高。

2.3 转换粒度与块映射

ARMv8-A 的页表支持多种映射粒度,除了基础的页面粒度外,还支持“块”(Block)映射,用于减少页表层级和 TLB 占用:

  • 4KB 页面:L3 表项,粒度 4KB。
  • 2MB 块:L2 表项,粒度 2MB(对应 4KB 页面配置下的 512 个连续页面)。
  • 1GB 块:L1 表项,粒度 1GB(对应 4KB 页面配置下的 262144 个连续页面)。
性能优化: 在设备驱动中,如果设备需要映射大块连续的物理内存(如帧缓冲、DMA 缓冲区),应优先使用块映射(2MB 或 1GB)。这可以显著减少页表遍历次数和 TLB miss,提升内存访问性能。例如,在 ioremap 实现中,内核会尝试使用块映射来映射设备寄存器区域。

下表对比了不同粒度的适用场景:

粒度 页表级别 覆盖范围 典型应用
4KB L3 4KB 普通进程堆栈、小数据段
2MB L2 2MB 内核直接映射区、大块 DMA 缓冲区
1GB L1 1GB 帧缓冲、GPU 显存映射

2.4 页表描述符与属性控制

每个页表项(PTE)不仅包含物理地址,还包含丰富的属性位,用于控制内存访问权限、缓存策略和执行权限。以下是关键属性位:

  • AP[2:1]:访问权限控制(读/写/只读,EL0/EL1 权限分离)。
  • AF:访问标志位,硬件在首次访问时置位,用于页面回收算法。
  • SH:可共享性属性(非共享、内部共享、外部共享),用于多核一致性。
  • AttrIndx:指向 MAIR(Memory Attribute Indirection Register)的索引,定义缓存策略(如 Normal、Device、Strongly Ordered)。
  • XN / PXN:禁止执行标志(XN 用于 EL1/EL2,PXN 用于 EL0),是实现 W^X 保护的关键。
安全关键: 在驱动中映射设备内存时,必须正确设置 AttrIndx 为 Device 类型(通常为 MAIR 索引 0),并设置 XN 位禁止执行。如果错误地将设备内存映射为 Normal 可缓存类型,可能导致 DMA 一致性问题或安全漏洞。例如,网卡驱动中的描述符环必须使用 Device 或 Strongly Ordered 属性。