2.3 异常级别与运行模式


2.3 异常级别与运行模式

本节摘要:AArch64 用四级异常级别(EL0 应用、EL1 内核、EL2 虚拟机监督、EL3 安全监视器)划分特权,异常发生时级别只升不降、eret 返回时才降回;AArch32 则延续七种运行模式的老命名。本节讲清台阶怎么上、怎么下、影子寄存器怎么换,并把虚拟化扩展安放在 EL2 的位置上。

寄存器名册里我们留了一个悬念:sp 按异常级别有影子副本、系统寄存器多数要 EL1 以上权限。本节把"异常级别"这个概念正式立起来——它是 ARMv8 以后整个权限体系的骨架,也是第 6 章中断处理的地基。

一次系统调用的视角

从你在手机上点一下按钮说起:应用代码运行在 EL0,它想读文件,但 EL0 无权碰磁盘控制器,也无权改页表。于是它执行一条 svc 指令——这是一个"请求升级"的信号。处理器立刻完成三件事:把返回点存进 elr_el1,把当前状态存进 spsr_el1,跳到 EL1 的异常向量表里系统调用对应的入口。内核代码开始跑,办完事执行 eret,状态从 spsr_el1 恢复、PC 跳回 elr_el1,应用继续。整个过程毫秒级,用户毫无察觉——但级别上去了又下来,权限门开了一次又关上。理解了这个往返,异常级别就不再抽象:它是处理器内置的、随事件自动升降的权限台阶

一、四级台阶与影子机制

四个级别权限递增:EL0 跑应用,无特权指令;EL1 跑操作系统内核,管页表与中断;EL2 跑系统管理程序,一台物理机在这里被切成多台虚拟机;EL3 是安全监视器,守着安全态与非安全态之间的唯一门。三条配套规则把台阶焊牢:

  • 异常只升不降:中断、系统调用、 faults 都把处理器带到"目标级别或更高",具体到哪一级由向量表与配置决定;想降级只有 eret 一条路。
  • 影子寄存器按级别切换sp_el0sp_el3elr_elxspsr_elx 成组存在,跨级时旧状态自动存档、新级别用自己的栈指针,内核因此不必先抢救上一级的现场。
  • 执行态独立于级别:每个异常级别都可以各自选择跑 AArch64 或 AArch32,所以一台 ARMv8 芯片上可以同时存在六十四位内核与三十二位应用。

图 2-3:异常级别权限台阶与一次系统调用的往返

图 2-3:异常级别权限台阶与一次系统调用的往返

二、AArch32 的老命名:七种运行模式

历史视角不能少,因为大量旧代码与旧教材用"模式"说话。AArch32 延续 ARMv7 的七种运行模式:User、FIQ、IRQ、Supervisor、Abort、Undefined、System。它与新台阶的对应关系是一条简化映射:User 对 EL0,其余特权模式归入 EL1;FIQ 与 IRQ 是两种中断的入口别名,Abort 与 Undefined 是异常类型的遗留划分。读旧代码时看到 cps #0x12 之类切换模式的指令,翻译过来就是"换到 IRQ 模式",在 ARMv8 语境里等价于"进入 EL1 的中断处理"。两套词汇都认识,手册与老代码才能通吃。

三、EL2 的日常:虚拟化如何落地

EL2 不是摆设,它是云厂商每天在用的层。系统管理程序跑在 EL2,把物理 CPU、内存、外设抽象成虚拟资源分给多个客户机:客户机内核以为自己跑在 EL1、拥有真页表,实际上 EL2 有一套"第二阶段地址翻译"盯着——客户机的物理地址还要再查一张 EL2 控制的映射表才落到真内存。两段翻译叠加的结果是:客户机之间内存天然隔离,迁移虚拟机时只需搬第二阶段表。对汇编工程师的直接影响是:at 类地址翻译指令、esr_el2 之类的异常综合寄存器,在读虚拟化相关内核日志时会高频出现;调嵌入式虚拟化平台时,"异常发生在 EL1 还是 EL2"是定位问题的第一问。

常见坑与易错点

三个高频误区值得点名。其一,以为应用代码"稍微越界"就能拿到 EL1——不可能,EL0 到 EL1 只能靠异常进入,没有直接指令可走,这条收紧正是安全模型的核心。其二,在 EL0 里执行 msr 写系统寄存器,得到的不是数据错误而是非法指令异常——权限问题的症状经常伪装成指令问题。其三,混淆"异常级别"与"安全态":TrustZone 的安全/非安全世界是另一条正交的轴,EL3 只是两个世界之间的摆渡人,第六章 6.3 节展开。

延伸:亲手摸一下自己的异常级别

CurrentEL 系统寄存器可以直接查身处的级别,这是裸机与内核代码的第一句"自报家门":

mrs x0, CurrentEL // 读当前异常级别,编码在 bits 3 到 2 lsr x0, x0, #2 // 右移对齐:0 是 EL0,1 是 EL1,2 是 EL2,3 是 EL3 and x0, x0, #3

这段小代码在启动诊断里极其常用:固件厂商给你的镜像"理论上"跑在 EL2 或 EL3,实际跳到你的入口时级别可能不符预期——页表操作、中断配置全都取决于它。把级别打出来再动手,能省掉一大类"配置写了却不生效"的悬案。延伸一条纪律:任何 msr 写系统寄存器的代码,先写一句注释声明它预期跑在哪一级——第 2 章说"权限问题常伪装成指令问题",这句注释就是提前拆弹。

常见问答

问:svc 与 smc 都会陷进来,差别在哪? 答:目标级别不同。svc 把执行送进"比当前高一级"的内核(通常是 EL1 接住 EL0 的请求),是系统调用的载体;smc 专门送进 EL3,是请求安全监视器切换世界的载体;夹在中间还有 hvc,落在 EL2,是客户机内核叫系统管理程序办事的按钮。三条指令、三级电梯,记成"svc 找内核、hvc 找监督、smc 找安全门"。

问:异常级别会不会在异常返回时算错层级? 答:不会算错,但会被读错——eret 回到哪一级由 spsr 里保存的级别字段决定,不由"感觉"决定。手写异常返回代码时若手动改过 spsr,返回级别跟着改;这是上下文切换代码故意利用的特性,也是新手意外降权事故的来源。

本节要点回顾

  • 四级台阶:EL0 应用、EL1 内核、EL2 虚拟化、EL3 安全监视,权限随级别递增。
  • 只升不降:异常使级别上升,eret 是唯一的下楼梯,状态经 elrspsr 存取。
  • 影子成组:每级独立栈指针、返回存档对与向量基址,跨级现场自动隔离。
  • 双词汇对照:AArch32 七模式是旧词汇,User 对 EL0、特权模式归 EL1。
  • EL2 两段翻译:虚拟机的地址要过两道页表,这是云上 ARM 的日常。

台阶搭好了。下一章我们开始真正"打牌":指令集怎么分类,四字节编码里藏着什么规律。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U