head S阶段异常向量表配置与ARM64启动调试 - 第2节

2.1 异常等级(Exception Levels, EL0–EL3)

ARMv8‑A 架构通过四个异常等级(Exception Level)实现特权分级,从最低权限的 EL0 到最高权限的 EL3。每个等级对应不同的执行环境与资源访问能力,是系统安全与隔离的基础。

核心原则:数值越大的异常等级,特权越高。低等级不能直接访问高等级的资源,必须通过异常切换等级。

2.1.1 异常等级定义与用途

异常等级执行状态典型用途特权范围
EL0AArch64 / AArch32用户态应用程序受限:无系统寄存器访问,仅可执行非特权指令
EL1AArch64 / AArch32操作系统内核(Linux、RTOS)系统寄存器、MMU、中断控制、虚拟内存管理
EL2AArch64 / AArch32虚拟机监视器(Hypervisor)虚拟化扩展、两阶段地址翻译、VM 切换
EL3AArch64 强制安全监控器(Secure Monitor)安全世界切换、电源管理、TrustZone 控制
启动阶段注意:ARM64 Linux 内核在 head.S 中从 EL2 或 EL3 降级到 EL1 后,才正式初始化内核页表与异常向量表。

2.1.2 异常等级切换关系图

异常等级切换关系 EL3 (Secure Monitor) EL2 (Hypervisor) EL1 (Kernel) EL0 (User) 切换方式 向下:异常触发 (SMC/HVC/SVC) 向上:异常返回 (ERET) 同级:IRQ/FIQ 不改变等级

2.2 异常类型(Exception Types)

ARMv8‑A 将异常分为四大类,每类对应不同的触发源与处理方式。理解这些类型是配置异常向量表的前提。

2.2.1 四种异常类型对比

异常类型缩写触发源典型场景向量表偏移
SynchronousSync指令执行直接导致系统调用(SVC)、数据中止、未定义指令、页故障0x000
IRQIRQ外部中断(普通)外设中断、定时器中断0x080
FIQFIQ外部中断(快速)高优先级外设、安全中断0x100
SErrorSError系统错误内存 ECC 错误、总线错误、异步外部中止0x180
关键区分:Synchronous 异常与当前指令同步,返回地址指向导致异常的指令;IRQ/FIQ/SError 是异步的,返回地址指向下一条未执行的指令。

2.2.2 异常类型触发关系图

异常类型与触发源 异常向量表 Synchronous IRQ FIQ SError 向量表偏移 Sync: 0x000 IRQ: 0x080 | FIQ: 0x100 SError: 0x180

2.3 异常路由机制(Routing Mechanism)

异常路由决定一个异常由哪个异常等级处理。ARMv8‑A 通过系统寄存器 SCR_EL3、HCR_EL2 以及 RVBAR_ELn 控制路由行为。

2.3.1 路由控制寄存器

寄存器所在等级控制位作用
SCR_EL3EL3IRQ, FIQ, EA, SMD决定 IRQ/FIQ/SError 是否路由到 EL3
HCR_EL2EL2IMO, FMO, AMO, TGE决定 IRQ/FIQ/SError 是否路由到 EL2
RVBAR_ELnEL1/2/3复位向量基地址指定各异常等级的复位入口地址

2.3.2 路由决策流程

  1. 异常触发:CPU 检测到异常事件(同步或异步)。
  2. 等级判定:根据异常类型,检查当前异常等级的路由控制位。
  3. 路由选择:
    • 若 SCR_EL3.IRQ=1,IRQ 路由到 EL3;否则由 EL2 或 EL1 处理。
    • 若 HCR_EL2.IMO=1,IRQ 路由到 EL2;否则由 EL1 处理。
    • FIQ 与 SError 类似,分别受 FMO/AMO 控制。
  4. 向量表查找:根据目标异常等级与异常类型,从 VBAR_ELn 指向的向量表中取出对应入口。
  5. 等级切换:硬件自动保存 PSTATE 到 SPSR_ELn,设置返回地址到 ELR_ELn,跳转到向量入口。

2.3.3 路由决策流程图

异常路由决策流程 异常触发 路由到 EL3? EL3 向量表 路由到 EL2? EL2 向量表 EL1 向量表 是 否 是 否 路由控制位 SCR_EL3.IRQ/FIQ/EA HCR_EL2.IMO/FMO/AMO 默认:EL1 处理
启动调试提示:在 head.S 早期阶段,EL2/EL3 的路由控制位通常被清零,确保所有异常直接路由到 EL1,简化向量表配置。

2.4 异常向量表结构(Vector Table Layout)

每个异常等级拥有独立的向量表,基地址由 VBAR_ELn 寄存器指定。每个表包含 16 个入口,每个入口占用 0x80 字节(128 字节)。

2.4.1 向量表布局

偏移异常类型触发条件说明
0x000Sync当前 EL,使用 SP_EL0EL0 模式下的同步异常
0x080IRQ当前 EL,使用 SP_EL0EL0 模式下的 IRQ
0x100FIQ当前 EL,使用 SP_EL0EL0 模式下的 FIQ
0x180SError当前 EL,使用 SP_EL0EL0 模式下的 SError
0x200Sync当前 EL,使用 SP_ELxEL1/2/3 模式下的同步异常
0x280IRQ当前 EL,使用 SP_ELxEL1/2/3 模式下的 IRQ
0x300FIQ当前 EL,使用 SP_ELxEL1/2/3 模式下的 FIQ
0x380SError当前 EL,使用 SP_ELxEL1/2/3 模式下的 SError
0x400Sync低等级 AArch64从 AArch64 低等级进入的同步异常
0x480IRQ低等级 AArch64从 AArch64 低等级进入的 IRQ
0x500FIQ低等级 AArch64从 AArch64 低等级进入的 FIQ
0x580SError低等级 AArch64从 AArch64 低等级进入的 SError
0x600Sync低等级 AArch32从 AArch32 低等级进入的同步异常
0x680IRQ低等级 AArch32从 AArch32 低等级进入的 IRQ
0x700FIQ低等级 AArch32从 AArch32 低等级进入的 FIQ
0x780SError低等级 AArch32从 AArch32 低等级进入的 SError

2.4.2 向量表结构图

异常向量表结构(VBAR_ELn 指向) 偏移 异常类型 触发条件 入口 0x000 Sync 当前 EL, SP_EL0 entry_el0_sync 0x080 IRQ 当前 EL, SP_EL0 entry_el0_irq 0x100 FIQ 当前 EL, SP_EL0 entry_el0_fiq 0x180 SError 当前 EL, SP_EL0 entry_el0_serror 0x200 Sync 当前 EL, SP_ELx entry_el1_sync 0x280 IRQ 当前 EL, SP_ELx entry_el1_irq 0x300 FIQ 当前 EL, SP_ELx entry_el1_fiq 0x380 SError 当前 EL, SP_ELx entry_el1_serror 每个入口占用 0x80 字节,共 16 个入口,总大小 0x800 字节
head.S 实践:Linux 内核在 __primary_switch 之前通过 __setup_vector_table 将 VBAR_EL1 设置为 _vectors 标签地址,确保异常向量表在 MMU 开启前生效。