4. ARMv7-A L2页表项格式:二级页表描述符结构
在ARMv7-A的经典两级页表架构中,L2页表(二级页表)负责将L1页表项指向的1MB节段进一步细分为更小的内存粒度。L2页表包含4种描述符类型,分别对应不同的页面大小和属性编码。本章将详细解析L2描述符的通用结构,以及大页、小页、极小页三种数据页描述符的差异。
核心概念: L2页表描述符的格式由TTBCR(Translation Table Base Control Register)和SCTLR(System Control Register)中的配置位共同决定。在经典短描述符格式下,L2描述符始终为32位(4字节)。
4.1 L2页表描述符通用结构
每个L2描述符占用4字节,其最高2位(bit[1:0])用于区分描述符类型。ARMv7-A定义了以下四种类型:
| bit[1:0]值 | 描述符类型 | 页面大小 | 说明 |
|---|---|---|---|
0b00 |
无效描述符(Fault) | — | 访问该页表项将触发Translation Fault |
0b01 |
大页描述符(Large Page) | 64 KB | 需L1节描述符配合,支持子页权限 |
0b10 |
极小页描述符(Tiny Page) | 1 KB | 仅在SCTLR.TRE=1时可用,兼容性受限 |
0b11 |
小页描述符(Small Page) | 4 KB | 最常用的L2页表项,支持子页权限 |
兼容性注意: 极小页(Tiny Page)仅在使能TEX remap(SCTLR.TRE=1)时有效。在大多数现代ARMv7-A实现中,TRE通常为0,此时
0b10被保留为Fault,极小页不可用。建议新设计优先使用小页(4KB)以获得最佳兼容性。
4.2 小页(Small Page)描述符详解
小页(4KB)是ARMv7-A中最常用的L2页表项。其描述符格式如下:
| 位域 | 宽度 | 功能描述 |
|---|---|---|
| [31:12] | 20 bits | 物理页帧号(PFN):4KB对齐的物理地址高20位 |
| [11:9] | 3 bits | AP[2:0]:访问权限位(与SCTLR.AFE配合) |
| [8:6] | 3 bits | TEX[2:0]:内存类型与缓存属性编码 |
| [5] | 1 bit | APX:访问权限扩展位 |
| [4] | 1 bit | S:可共享(Shareable)位 |
| [3] | 1 bit | nG:非全局位(用于ASID匹配) |
| [2] | 1 bit | XN:不可执行位(Execute Never) |
| [1:0] | 2 bits | 类型标识:固定为0b11 |
子页权限(Subpage Permissions): 小页和大页支持将页面进一步划分为4个子页(每个子页1KB或16KB)。子页权限由L2描述符中的AP[2:0]和APX位联合编码,通过SCTLR.SPD(Subpage Permissions Disable)位控制启用。当SPD=0时,子页权限生效,允许对同一页内不同区域设置不同的读/写权限。
4.3 大页(Large Page)描述符
大页大小为64KB,用于减少TLB压力并提高大块连续内存的映射效率。其描述符格式与小页类似,但物理地址对齐要求不同:
- PFN位域: [31:16]共16位,物理地址必须64KB对齐(低16位为0)。
- 子页划分: 64KB大页被划分为4个16KB子页,每个子页拥有独立的访问权限(AP[2:0] + APX)。
- 类型标识: bit[1:0] =
0b01。 - 属性位: TEX、S、nG、XN等位域位置与小页相同。
性能权衡: 大页(64KB)在TLB覆盖范围上优于小页(4KB),但内存碎片风险更高。在嵌入式系统中,大页常用于帧缓冲(Frame Buffer)或大块DMA缓冲区映射。虚拟化场景中,大页可减少Stage-2页表的遍历开销。
4.4 极小页(Tiny Page)描述符
极小页大小为1KB,是ARMv7-A中最小的页面粒度。其描述符特点如下:
| 特性 | 说明 |
|---|---|
| 类型标识 | bit[1:0] = 0b10 |
| PFN位域 | [31:10]共22位,物理地址1KB对齐 |
| 可用条件 | 必须使能TEX remap(SCTLR.TRE=1) |
| 子页支持 | 不支持子页权限(SPD位无效) |
| 属性位 | AP、TEX、S、nG、XN位域位置与小页一致 |
| 兼容性 | ARMv7-A可选特性,Cortex-A系列多数实现不支持 |
弃用建议: 极小页(1KB)在ARMv7-A中属于可选特性,且ARMv8-A AArch64已完全移除该粒度。为了向前兼容和软件可移植性,强烈建议避免使用极小页。如果确实需要细粒度映射,优先考虑小页(4KB)配合子页权限。
4.5 三种数据页描述符对比总结
| 对比维度 | 大页(Large Page) | 小页(Small Page) | 极小页(Tiny Page) |
|---|---|---|---|
| 页面大小 | 64 KB | 4 KB | 1 KB |
| 类型标识 bit[1:0] | 0b01 |
0b11 |
0b10 |
| PFN位宽 | 16 bits [31:16] | 20 bits [31:12] | 22 bits [31:10] |
| 子页数量 | 4(每个16KB) | 4(每个1KB) | 无 |
| 子页权限控制 | 支持 | 支持 | 不支持 |
| 使能条件 | 始终可用 | 始终可用 | 需SCTLR.TRE=1 |
| TLB覆盖范围 | 高(64KB/项) | 中(4KB/项) | 低(1KB/项) |
| 典型用途 | 帧缓冲、大块DMA | 通用内存映射 | 极少使用 |
4.6 L2页表项编程示例
以下示例展示如何构造一个小页描述符,映射虚拟地址到物理地址0x80001000,并设置可读可写、不可执行、普通内存属性:
/* 构造小页描述符示例 */
uint32_t l2_entry = 0;
/* 物理页帧号:物理地址 0x80001000 右移12位 */
uint32_t pfn = (0x80001000 >> 12); /* 结果: 0x80001 */
/* 填充位域 */
l2_entry |= (pfn << 12); /* bit[31:12] = PFN */
l2_entry |= (0x3 << 9); /* AP[2:0] = 0b011: 全权限(读/写) */
l2_entry |= (0x1 << 6); /* TEX[2:0] = 0b001: 普通内存,外写回内写通 */
l2_entry |= (0x0 << 5); /* APX = 0 */
l2_entry |= (0x1 << 4); /* S = 1: 可共享 */
l2_entry |= (0x0 << 3); /* nG = 0: 全局映射 */
l2_entry |= (0x1 << 2); /* XN = 1: 不可执行 */
l2_entry |= 0x3; /* bit[1:0] = 0b11: 小页描述符 */
/* 写入L2页表基址偏移处 */
*(volatile uint32_t *)(l2_table_base + index) = l2_entry;
调试检查: 在写入L2页表项后,建议使用DSB(Data Synchronization Barrier)和ISB(Instruction Synchronization Barrier)指令确保页表更新对后续指令和观察点可见。在SMP系统中,还需执行TLB失效广播操作(如TLBIALL)。