2. ARM64架构基础:AArch64运行模式、异常级别(EL0-EL3)、MMU使能流程

ARMv8-A架构引入了两种执行状态:AArch64(64位)和AArch32(32位)。在Linux内核页表机制中,我们主要关注AArch64状态,因为它提供了64位虚拟地址空间、更大的物理地址范围以及全新的页表格式。本章将深入剖析AArch64的运行模式、异常级别模型以及MMU的初始化使能流程,为后续理解页表遍历和地址转换奠定基础。

2.1 AArch64运行模式与寄存器模型

AArch64运行模式摒弃了传统ARM的“处理器模式”(如SVC、IRQ、FIQ等),转而采用基于异常级别(Exception Levels, EL)的层次化权限模型。每个异常级别拥有独立的栈指针、页表基地址寄存器以及系统控制寄存器。

关键概念: AArch64中,SP_ELx(栈指针)和TTBRx_ELx(页表基地址)都是每个异常级别私有的,这为虚拟化安全和隔离提供了硬件级支持。

2.1.1 异常级别(EL0 - EL3)

ARM64定义了4个异常级别,数字越大,特权越高:

异常级别 名称 典型用途 页表选择
EL0 用户态(User) 运行普通应用程序 TTBR0_EL0(用户页表)
EL1 内核态(Kernel) 运行操作系统内核 TTBR0_EL1 / TTBR1_EL1
EL2 虚拟机监视器(Hypervisor) 运行Type-1/Type-2 Hypervisor(如KVM) TTBR0_EL2
EL3 安全监视器(Secure Monitor) 运行安全固件(如ATF、TrustZone) TTBR0_EL3
Linux内核视角: 内核通常运行在EL1,用户空间运行在EL0。当启用KVM虚拟化时,Host内核会利用EL2进行硬件加速的虚拟地址翻译。

2.1.2 异常级别切换与栈指针

异常级别之间的切换通过异常(Exception)或中断触发。当从低级别(如EL0)进入高级别(如EL1)时,硬件自动保存返回地址和PSTATE到高级别的SPSR_ELx和ELR_ELx寄存器。每个异常级别可以选择使用独立的栈指针(SP_ELx)或共享当前栈指针(SP_EL0)。

// 示例:从EL0进入EL1时的硬件自动行为(伪代码)
// 1. 保存EL0的返回地址到 ELR_EL1
// 2. 保存EL0的PSTATE到 SPSR_EL1
// 3. 自动切换到 SP_EL1(如果配置了使用独立栈)
// 4. 跳转到异常向量表中的对应入口

2.2 MMU使能流程:从复位到页表激活

ARM64 MMU的使能并非简单的“打开/关闭”开关,而是一个严谨的、分步骤的初始化过程。错误的使能顺序会导致系统立即崩溃(如页表未就绪就开启MMU)。

2.2.1 使能前的硬件准备

在设置SCTLR_EL1.M(MMU使能位)之前,必须完成以下关键配置:

  1. 建立页表:在内存中分配并填充页表(至少包含一级页表)。
  2. 设置页表基地址:将页表物理地址写入TTBR0_EL1(或TTBR1_EL1)。
  3. 配置翻译控制寄存器:设置TCR_EL1,包括页粒度(4K/16K/64K)、虚拟地址宽度、缓存属性等。
  4. 配置内存属性:通过MAIR_EL1定义内存类型(如Normal、Device)的索引。
  5. 执行ISB指令:确保上述配置在流水线中已提交。
常见陷阱: 在使能MMU之前,必须确保当前执行的代码地址(PC)与页表中的虚拟地址映射一致。通常的做法是:先建立恒等映射(Identity Mapping),使能MMU,然后通过长跳转切换到最终虚拟地址空间。

2.2.2 使能流程步骤

以下是一个典型的ARM64 MMU使能序列(以EL1为例):

// 伪代码:ARM64 MMU使能流程
1. 初始化页表(在内存中构建页表结构)
2. 设置 TTBR0_EL1 = 页表基地址(物理地址)
3. 设置 TCR_EL1 = 配置值(如:4K页、48位虚拟地址、ASID启用)
4. 设置 MAIR_EL1 = 内存属性索引(如:0x44 表示 Normal Memory)
5. 执行 ISB(指令同步屏障)
6. 读取 SCTLR_EL1,设置 M 位(MMU使能)和 C 位(数据缓存使能)
7. 写入 SCTLR_EL1
8. 执行 ISB
9. (可选)执行 DSB(数据同步屏障)
10. 此时MMU已激活,后续所有地址访问均经过页表翻译

2.2.3 使能过程中的地址转换状态

下图展示了MMU使能前后,CPU访问地址的路径变化:

MMU使能前后地址转换路径 MMU 关闭(Stage: Disabled) CPU 虚拟地址 物理地址 直接透传:VA == PA 无权限检查、无缓存控制 MMU 开启(Stage: Enabled) CPU 虚拟地址 MMU PA 页表遍历:VA → 多级页表 → PA 权限检查、缓存策略、ASID隔离

2.3 关键系统寄存器详解

MMU使能流程中涉及的核心寄存器及其作用如下:

寄存器 全称 关键字段/作用
SCTLR_EL1 系统控制寄存器 M(MMU使能)、C(数据缓存使能)、I(指令缓存使能)、WXN(写不可执行)
TCR_EL1 翻译控制寄存器 T0SZ(TTBR0地址空间大小)、TG0(页粒度)、IPS(中间物理地址大小)、SH0(可共享性)
TTBR0_EL1 页表基地址寄存器0 存放用户空间(低地址)页表的物理基地址;支持ASID(地址空间标识符)
TTBR1_EL1 页表基地址寄存器1 存放内核空间(高地址)页表的物理基地址
MAIR_EL1 内存属性间接寄存器 定义8个内存属性索引(如:0x44=Normal, 0x00=Device-nGnRnE)

2.4 使能后的页表切换与TLB管理

MMU使能后,内核在运行时可能需要切换页表(例如进程上下文切换)。此时需要遵循严格的TLB失效协议:

  • 全局页表切换(如内核页表更新):执行TLBI VMALLE1(失效所有EL1的TLB条目)。
  • 进程切换(ASID机制):写入新进程的ASID到TTBR0_EL1,然后执行TLBI ASIDE1(失效非全局条目)。
  • 单页失效:使用TLBI VAE1 + 虚拟地址,精确失效特定页的TLB。
性能要点: ARM64的TLB是VIPT(虚拟索引物理标记)或PIPT(物理索引物理标记)的。使用ASID可以避免进程切换时完全清空TLB,大幅降低TLB缺失率。

2.5 本章小结

ARM64的AArch64运行模式通过异常级别(EL0-EL3)实现了严格的权限分层,每个级别拥有独立的页表配置。MMU使能是一个多步骤的硬件初始化过程,必须在页表就绪、寄存器配置正确、屏障指令执行完毕后才能安全开启。理解这些基础是后续学习四级页表遍历、页表缓存(TLB)以及虚拟化地址翻译的必备前提。