el3_exit 退出后跳转 8 种不同的目标场景
el3_exit 本质上是一个 "世界切换引擎",它从 context 结构中取出 ELR_EL3(目标地址)和 SPSR_EL3(目标异常级别和 PSTATE),然后用 ERET 跳过去。跳到哪里完全取决于之前谁填了 context。
核心数据结构
在函数cm_setup_context(ctx, ep)中
write_ctx_reg(state, CTX_ELR_EL3, ep->pc); // ← 目标 PC write_ctx_reg(state, CTX_SPSR_EL3, ep->spsr); // ← 目标 EL + PSTATE write_ctx_reg(state, CTX_SCR_EL3, scr_el3); // ← 安全状态 (S/NS/Realm)场景 1:BL1 冷启动 → BL2(正常启动路径)
调用点: bl1_entrypoint.S
bl1_main() → bl1_prepare_next_image(BL2_IMAGE_ID) ↓ cm_init_my_context(next_bl_ep); ↓ cm_get_context(GET_SECURITY_STATE(ep->h.attr)); ↓ cm_setup_context(ctx, ep); ↓ write_ctx_reg(reg_ctx, CTX_SCR, scr); write_ctx_reg(reg_ctx, CTX_LR, ep->pc); write_ctx_reg(reg_ctx, CTX_SPSR, ep->spsr); ep->pc = BL2 入口地址 (从 FIP 加载的镜像头中读取) ep->spsr = BL2 目标异常级 (S-EL1 或 EL2) ↓ cm_prepare_el3_exit(security_state);编译选项 | SPSR_EL3 目标 EL | ERET 后 | BL2 所在位置 |
!BL2_RUNS_AT_EL3 且BL32不存在 | S-EL1 | 降级到 Secure-EL1 | Secure RAM |
!BL2_RUNS_AT_EL3 且BL32存在 | EL2(NS) | 降级到 Non-Secure EL2 | Secure RAM |
BL2_RUNS_AT_EL3 | EL3(不走 el3_exit) | 不降级(走bl1_run_bl2_in_el3) | Trusted SRAM |
关键: bl1_prepare_next_image() 在 bl1/bl1_main.c被调用,它调用 cm_init_context() 把 BL2 的入口信息写入 context,然后 el3_exit 取出做 ERET。
场景 2:BL1 SMC 异常处理 → 返回调用者或跳转新镜像
调用点: bl1_exceptions.S
SMC 进入 → prepare_el3_entry (保存现场) → bl1_smc_wrapper_aarch64 → bl1_smc_handler → 处理完后 b el3_exitSMC 类型 | 行为 | ELR_EL3 目标 |
BL1_SMC_CALL_COUNT / BL1_SMC_UID / BL1_SMC_VERSION | 直接返回 | 回到 SMC 发起者(ELR 未改) |
FWU SMC(固件更新) | 可能触发跳转下一阶段 | 下一阶段 BL 入口 |
典型场景: BL1 在 Firmware Update 模式下收到 SMC,处理完可能需要加载并跳转到新的 BL 镜像,此时 SMC handler 内部会调用 bl1_prepare_next_image() 改写 context,然后 el3_exit 跳转到新镜像。
场景 3:BL31 次 CPU 热启动 → 回到操作系统
调用点: bl31_entrypoint.S
PSCI CPU_ON 唤醒次 CPU → bl31_entrypoint → el3_entrypoint_common → 恢复 context → b el3_exitELR_EL3:之前 cm_setup_context_by_index() 设置的 NS 世界入口(即 OS 指定的启动地址)SPSR_EL3:= Non-Secure EL1 或 EL2(AArch64)SCR_EL3.NS:= 1(Non-Secure)→ 结果:退到 OS,CPU 从 OS 指定的入口开始执行
场景 4:BL31 SMC 处理完成 → 返回 Non-Secure 世界
调用点: runtime_exceptions.S
NS 世界发 SMC → trap 到 EL3 → handle_sync_exception → prepare_el3_entry (保存 NS 上下文) → handler_sync_exception (路由到 PSCI/SIP/SPD 等) → no_ret el3_exit这是 最常见的路径。根据 SMC 功能号不同:
SMC 类型 | 目标 | 说明 |
PSCI_VERSION/PSCI_FEATURES | 返回 NS 世界 | ELR_EL3 = SMC 下一条指令,SPSR = NS-EL1/EL2 |
PSCI_CPU_SUSPEND | 返回 NS 世界 不同入口 | ELR_EL3 被改写为 OS 的唤醒入口地址 |
PSCI_SYSTEM_OFF | 不返回 | 关机循环 |
SIP/SiP SMC | 返回 NS 世界 | ELR 未改 → 回到 SMC 发起者 |
场景 5:BL31 IRQ/FIQ 中断处理完成 → 返回低权限级
调用点: runtime_exceptions.S
中断类型 | 目标世界 | 说明 |
NS 中断(在 NS 世界触发) | 返回 NS 世界 | 正常返回,ELR 不变 |
S-EL1 中断(在 Secure 世界触发) | 返回 Secure 世界 | 可能触发世界切换 |
EL3 中断 | EL3 自身处理 | 不走 el3_exit |
场景 6:SPD 安全世界切换 → 跳入 Secure Partition
调用点: 各 SPD helper 文件末尾
SPD名称 文件 目标 ────── ────────────── ───────────── OP-TEE services/spd/opteed/opteed_helpers.S:42 OP-TEE OS (S-EL1) TSP services/spd/tspd/tspd_helpers.S:42 TSP (S-EL1) TLK services/spd/tlkd/tlkd_helpers.S:44 Trusted Little Kernel (S-EL1) PNC services/spd/pncd/pncd_helpers.S:42 PNC Secure Partition (S-EL1) Trusty services/spd/trusty/trusty_helpers.S:65 Trusty OS (S-EL1) SPM services/std_svc/spm/.../spm_helpers.S:41 S-EL0 Secure Partition SPMD services/std_svc/spmd/.../spmd_helpers.S:41 S-EL2 Secure Partition RMMD services/std_svc/rmmd/.../rmmd_helpers.S:41 Realm World (R-EL2)ELR_EL3 = Secure Partition 的入口点(或恢复点)
SPSR_EL3 = S-EL1 / S-EL2 / R-EL2
SCR_EL3 = Secure 或 Realm 状态
场景 7:SDEI 事件分发 → 跳入 SDEI 处理函数
调用点: sdei_dispatch.S
SDEI 事件 → EL3 异常处理 → setjmp 保存现场 → 修改 ELR_EL3 为 SDEI handler → el3_exitELR_EL3 = SDEI 事件处理函数地址(在 NS-EL1/EL2 的虚拟地址空间)SPSR_EL3 = NS-EL1 或 NS-EL2 SCR_EL3.NS = 1→ 结果:CPU 退到 NS 世界,跳入注册的 SDEI handler
场景 8:PSCI CPU 电源管理 → 返回 OS 唤醒入口
调用点: 各平台 plat_pm.c 通过 C 函数调用 cm_prepare_el3_exit → el3_exit
例如 plat/arm/css/common/css_pm.c 等:
PSCI CPU_SUSPEND → 平台电源管理 → 改写 context 中的 ELR_EL3 为唤醒地址 → el3_exitELR_EL3 = psci_entrypoint(OS 指定的 CPU 唤醒入口)SPSR_EL3 = OS 的异常级别→ 结果:CPU 从电源管理状态恢复后直接进入 OS
全景图:所有 el3_exit 跳转目标汇总
el3_exit (ERET) │ ┌────────────────┼─────────────────────────┐ │ │ │ BL1 场景 BL31 场景 SPD/SECURE 场景 │ │ │ ┌─────┴────┐ ┌─────┴──────┐ ┌──────────────┴──────────────┐ │ │ │ │ │ │ │ BL2入口 SMC返回 NS世界 同步SMC 中断返回 S-EL1分区 Realm/R-EL2 (S-EL1/ (调用者 (OS 返回NS (IRQ/FIQ/ (OP-TEE, (RMMD) EL2) ) 唤醒入口) 世界 SError) TSP等)- el3_exit 只是一个"上下文恢复 + ERET"的机械执行器——跳到哪里完全取决于 之前谁往 context 的 CTX_ELR_EL3 和 CTX_SPSR_EL3 填了什么值
- 它可以降级(EL3→EL2/EL1),也可以同级(SPSR 指向 EL3 时实为在同一级跳转)
- 安全状态由 SCR_EL3 的 NS/NSE 位决定:0=Secure、1=Non-Secure、2=Realm