)
ARM异常等级到底怎么切换的?从EL0到EL3的完整旅程(附源码)前言搞过嵌入式或者系统底层的同学,一定见过各种异常——IRQ、FIQ、Data Abort、SMC……但你真的搞清楚ARM的异常等级是怎么切换的吗?EL0、EL1、EL2、EL3这四个等级之间跳来跳去,到底谁管谁?SMC指令发出去之后,系统经历了什么?我入坑ARM TrustZone的时候,被这套体系折磨得不轻。ARM ARM(Architecture Reference Manual)写了上千页,但光看手册太抽象,得配合源码才能真正理解。这篇文章就带你从异常向量表一路走到ATF BL31、走到OP-TEE,把整条链路啃下来。一、ARMv8 的四层世界ARMv8 把 CPU 的执行环境分了四个 Exception Level,堆栈式设计,数字越大权限越高。EL3 Secure Monitor —— 最高权限,TrustZone 的看门人 EL2 Hypervisor —— 虚拟化层,跑 KVM / Xen EL1 OS Kernel —— Linux / 各种 RTOS EL0 Applications —— 用户态 App直觉上就是:EL0 被 EL1 管,EL1 被 EL2 管,EL2 被 EL3 管。但实际上,如果你没开虚拟化(绝大多数嵌入式场景),EL2 压根就不存在,直接 EL0 ↔ EL1 ↔ EL3。等等,那 Secure World(安全世界)呢?ARMv8 的 TrustZone 并不是一个独立的异常等级——它是在每个等级上又切了一刀:Normal World 和 Secure World。EL3 是唯一的"跨世界"等级,也是 Secure Monitor 的老巢。所以真实的情况是:Secure World (安全世界)Normal World (非安全世界)EL0: User AppEL1: Linux KernelEL2: HypervisorEL0: TEE Client APIEL1: OP-TEE OS / Trusted OSEL3: Secure Monitor (ATF BL31)画重点:EL3 是唯一同时连接 Normal World 和 Secure World 的关口。任何跨世界的操作,都必须经过 EL3 的 Secure Monitor。这就是 SMC 指令存在的意义。二、异常等级怎么切?四种触发方式异常等级切换不会凭空发生,必须有明确的触发事件。ARMv8 定义了四种方式:1. 异常(Exceptions)这又分四类:异常类型典型场景Sync数据中止、指令中止、系统调用(SVC)、SMCIRQ普通外设中断(UART、Timer)FIQ快速中断(TrustZone 里常用,留给 Secure World)SError总线错误、ECC 错误等系统级错误当异常发生时,CPU 会:暂停当前执行提升(或保持)异常等级跳转到异常向量表对应的 entry2. SMC 指令SMC(Secure Monitor Call)是从低等级主动切换到 EL3的唯一指令。Normal World 发 SMC,就会陷入 EL3 的 Secure Monitor。smc #0 ; 触发 EL3 同步异常3. ERET 返回ERET(Exception Return)是从高等级降回低等级的指令。类似 x86 的 iret:eret ; 返回到原来的异常等级4. WFI / WFE (顺便提一嘴)WFI(Wait For Interrupt)本身不切换等级,但会让 CPU 等待中断——而中断来了就会触发异常,然后等级就变了。所以算是个间接触发。三、异常向量表:16个entry的布局哲学这是 ARMv8 最精妙的设计之一。不知道异常向量表怎么排的,后面的一切都白搭。异常向量表由VBAR_ELx寄存器指向(Vector Base Address Register)。每个异常等级都有自己的 VBAR:VBAR_EL1—— EL1 的向量表基址VBAR_EL2—— EL2 的向量表基址VBAR_EL3—— EL3 的向量表基址EL0 没有 VBAR——因为它不处理异常,异常由 EL1 及以上处理。16个entry的排布一个向量表共16个 entry,每个 entry 占0x80 byte(128字节)。布局如下:Offset异常类型描述0x000Sync(同等级 SP0)当前 EL,使用 SP_EL00x080IRQ(同等级 SP0)0x100FIQ(同等级 SP0)0x180SError(同等级 SP0)0x200Sync(同等级 SPx)当前 EL,使用 SP_ELx