3. 页表基础概念:页表层级、页大小、虚拟地址与物理地址
在 ARM64 架构中,MMU(内存管理单元)通过页表完成虚拟地址到物理地址的转换。页表是一个多级查找结构,其设计直接影响系统性能、内存开销和启动稳定性。本章深入剖析页表的层级结构、支持的页大小以及地址转换的核心机制,为后续 head.S 中的页表构建与故障排查奠定基础。
3.1 页表层级结构(L0/L1/L2/L3)
ARM64 使用最多 4 级页表:L0、L1、L2、L3。每一级页表包含若干页表项(PTE),每个 PTE 指向下一级页表的基地址或直接映射为一个大页(块)。页表级数由虚拟地址宽度和页大小共同决定。
关键概念: 页表级数并非固定为 4 级。当使用 4KB 页且地址宽度为 48 位时,启用完整的 L0→L1→L2→L3 四级结构;若使用 64KB 页,则只需 L0→L1→L2 三级。
3.2 页大小与页表级数的关系
ARM64 支持三种标准页大小:4KB、16KB、64KB。页大小决定了虚拟地址中页内偏移的位数,进而影响页表级数和每级索引的位数。
| 页大小 | 页内偏移位数 | 虚拟地址宽度 | 页表级数 | 每级索引位数 |
|---|---|---|---|---|
| 4KB | 12 位 [11:0] | 48 位 | 4 级 (L0-L3) | 9 位 × 4 |
| 16KB | 14 位 [13:0] | 48 位 | 4 级 (L0-L3) | 11 位 × 3 + 9 位 |
| 64KB | 16 位 [15:0] | 48 位 | 3 级 (L0-L2) | 13 位 × 2 + 12 位 |
启动阶段建议: 在 head.S 早期代码中,通常使用 4KB 页 + 4 级页表,因为这是最通用、兼容性最好的配置。如果后续需要减少 TLB 缺失或降低页表内存开销,可考虑切换到 64KB 页。
3.3 虚拟地址与物理地址的转换过程
ARM64 的地址转换核心是 多级页表查找。CPU 将虚拟地址分解为多个索引字段,依次遍历各级页表,最终得到物理页帧号(PFN),再与页内偏移拼接形成完整的物理地址。
3.4 页表项(PTE)的关键字段
每个页表项(PTE)是一个 64 位描述符,包含物理地址、访问权限、内存属性等关键信息。理解 PTE 的布局对于调试页表错误至关重要。
| 位域 | 宽度 | 描述 |
|---|---|---|
| [63:48] | 16 位 | 物理地址高位(扩展物理地址,取决于实现) |
| [47:12] | 36 位 | 物理页帧号(PFN),与页内偏移拼接形成物理地址 |
| [11:10] | 2 位 | 访问权限(AP) |
| [9:8] | 2 位 | 内存属性索引(AttrIndx) |
| [7] | 1 位 | 非安全(NS) |
| [6] | 1 位 | 访问标志(AF) |
| [5] | 1 位 | 共享性(SH) |
| [4:2] | 3 位 | 内存类型(MT) |
| [1] | 1 位 | 可写(W) |
| [0] | 1 位 | 有效位(V):1=有效,0=无效 |
常见故障点: 在 head.S 中构建页表时,最容易遗漏的是有效位(bit 0)未置 1,或物理地址高位(bits [63:48])未正确填充。这会导致 MMU 使能后立即触发同步异常(Data Abort 或 Translation Fault)。
3.5 页表对齐与内存布局要求
ARM64 要求页表基地址必须按页大小对齐。例如,4KB 页的页表基地址必须 4KB 对齐(低 12 位为 0)。此外,各级页表在内存中的布局必须连续,且不能跨越页边界。
- L0 页表: 必须 4KB 对齐,包含 512 个 PTE(4KB 页时)。
- L1 页表: 必须 4KB 对齐,包含 512 个 PTE。
- L2 页表: 必须 4KB 对齐,包含 512 个 PTE。
- L3 页表: 必须 4KB 对齐,包含 512 个 PTE。
启动代码实践: 在 head.S 中,通常使用
.align 12 或 .balign 4096 指令确保页表符号对齐。例如:.balign 4096
L0_page_table:
.space 4096 // 512 个 PTE,每个 8 字节
3.6 页表构建的典型流程
在 ARM64 启动早期,head.S 构建页表通常遵循以下步骤:
- 清零页表区域: 使用
dc zva或stp xzr, xzr, [x0], #16循环清零。 - 填充 L0 表项: 指向 L1 页表基地址,设置有效位和访问权限。
- 填充 L1 表项: 指向 L2 页表基地址,或直接映射为 2MB 块(如果使用块映射)。
- 填充 L2 表项: 指向 L3 页表基地址,或直接映射为 1GB 块。
- 填充 L3 表项: 映射 4KB 页,设置物理地址、权限和内存属性。
- 设置 TTBR0_EL1: 将 L0 页表基地址写入 TTBR0_EL1。
- 使能 MMU: 设置 SCTLR_EL1.M 位,执行 ISB 和 DSB 同步。
调试技巧: 如果 MMU 使能后系统崩溃,优先检查 TTBR0_EL1 的值是否与 L0 页表符号地址一致,以及 L0 页表第一个 PTE 的有效位是否为 1。使用 JTAG 或模拟器读取这些寄存器可以快速定位问题。