BL31 完整执行链分析BL31 是整个 ATF 的运行时核心功能横跨三个层面角色说明监控器Monitor处于 EL3是安全世界和非安全世界之间的门户异常向量宿主所有 SMC 从 NS 世界 trap 到 EL3由 BL31 分发运行时服务框架管理 PSCI电源管理、SPD安全负载、SDEI异常委派等世界切换器最终通过el3_exit的 ERET跳转到 BL33或回到 NS 世界全景图BL2 (S-EL1/EL3) BL31 (EL3) ────────────── ────────── │ ├─ SMC(BL1_SMC_RUN_IMAGE) ──▶ BL1 handler │ │ el3_exit │ ▼ │ ★ bl31_entrypoint.S:25 │ │ │ ├─ el3_entrypoint_common ← VBAR_EL3、栈、BSS │ │ │ ▼ │ bl bl31_main │ │ │ ┌──────────────┼──────────────────┐ │ ▼ ▼ ▼ │ runtime_svc_init bl32_init() bl31_prepare_next_image_entry() │ (PSCI, SPD, SDEI) (进入 BL32 (设置 BL33 上下文) │ S-EL1 并返回) │ │ │ │ │ └──────────────┴──────────────────┘ │ │ │ bl31_main 返回 │ │ │ ├─ clean_dcache(DATA/BSS/PER_CPU) │ │ │ ▼ │ b el3_exit │ │ │ ├─ ELR_EL3 BL33 入口 │ ├─ SPSR_EL3 NS.EL1/EL2 │ ├─ SCR_EL3.NS 1 │ │ ▼ ▼ BL33 (UBOOT/UEFI/Linux) exception_return (ERET)一、入口bl31_entrypointbl31_entrypoint.S25 func bl31_entrypoint │ ├─ 保存参数 (line 30-33) │ mov x20, x0 ← BL2 传过来的参数bl31_ep_info 等 │ mov x21, x1 │ mov x22, x2 │ mov x23, x3 │ ├─ el3_entrypoint_common 宏 (line 45-52!RESET_TO_BL31 情况) │ _init_sctlr0 ← BL1 已初始化 SCTLR_EL3 │ _warm_boot_mailbox0 ← 冷启动不检查 mailbox │ _secondary_cold_boot0 ← 只有主 CPU 走此路径 │ _init_memory0 ← BL1 已初始化内存 │ _init_c_runtime1 ← ★ 设置 SP_EL3、清零 BSS │ _exception_vectors ← ★ VBAR_EL3 runtime_exceptions │ runtime_exceptions │ _pie_fixup_size... ← PIE 重定位 │ │ └─ 宏内部主要做 │ ① 设置 SCTLR_EL3如果 _init_sctlr1 │ ② 检查 warm boot mailbox如果 _warm_boot_mailbox1 │ ③ 区分主/次 CPU如果 _secondary_cold_boot1 │ ④ 初始化平台内存如果 _init_memory1 │ ⑤ ★ 设置栈 清零 BSS如果 _init_c_runtime1 │ ⑥ ★ 设置 VBAR_EL3 runtime_exceptions │ ├─ 恢复参数 (line 75-78) │ mov x0, x20 │ ... │ └─ ★ 调用 C 主函数 (line 84) bl bl31_main ← 进入 C 世界不会返回直到最后二、中间过程bl31_mainbl31_main.c这段 C 代码是整个 BL31 的核心按顺序分解为 4 个阶段阶段 A基础初始化void bl31_main(u_register_t arg0, arg1, arg2, arg3) { // ① 控制台 plat_setup_early_console(); // ② 早期平台初始化解析内存布局、IO 控制器 bl31_early_platform_setup2(arg0, arg1, arg2, arg3); // ③ ★ 开启 MMU 数据缓存建立页表 bl31_plat_arch_setup(); // ④ CPU 特性运行时检测 detect_arch_features(core_pos); // ⑤ EL3 扩展寄存器初始化PAuth、MPAM、AMU 等 cm_manage_extensions_el3(core_pos); cm_manage_extensions_per_world(); // ⑥ GIC 初始化中断控制器 gic_init(core_pos); gic_pcpu_init(core_pos); gic_cpuif_enable(core_pos); // ⑦ 平台设置 DSU 初始化 bl31_platform_setup(); // ⑧ 上下文管理初始化 bl31_lib_init(); → cm_init(); }阶段 B★ 运行时服务注册runtime_svc_init// ⑨ ★ 核心注册所有运行时服务 runtime_svc_init();这个函数遍历 .rt_svc_descs 链接段中所有 rt_svc_desc_t 描述符通过链接脚本自动收集逐个调用其 init().rt_svc_descs 段中的服务列表由 DECLARE_RT_SVC 宏注册 ┌─ PSCI (电源管理) ──────────────┐ │ std_svc_setup() │ │ → psci_setup() │ PSCI 版本协商、CPU拓扑、系统关机/重启 │ → pci_cpu_on/hibernate/... │ └────────────────────────────────┘ ┌─ SDEI (软件委派异常) ──────────┐ │ sdei_init() │ 注册 SDEI 事件、客户端 └────────────────────────────────┘ ┌─ SPD (安全负载分发器) ─────────┐ │ 如 opteed_init() │ ★ 注册 bl32_init 钩子 │ 或 tlkd_init() │ 配置 Secure Partition │ 或 trusty_init() │ └────────────────────────────────┘ ┌─ SPMD (SPM 分发器) ───────────┐ │ spmd_init() │ S-EL2 分区管理 └────────────────────────────────┘ ┌─ RMMD (Realm 管理) ───────────┐ │ rmmd_init() │ R-EL2 Realm 管理CCA └────────────────────────────────┘ ┌─ 标准服务 ─────────────────────┐ │ arm_std_svc_setup() │ SMCCC 功能查询、架构特性 └────────────────────────────────┘每个服务初始化时将自己的 SMC 函数分发到 rt_svc_descs_indices[] 查找表。以后每当 BL31 收到 SMC通过 smc_fid 的 OENOwning Entity Number字段即可 O(1) 找到对应 handler。阶段 C安全负载初始化// ⑩ 如果 SPD 注册了 BL32 初始化钩子 if (bl32_init ! NULL) { int32_t rc (*bl32_init)(); // → SPD 的 init 函数内部会 // ① 设置 BL32 (如 OP-TEE) 的 S-EL1 上下文 // ② 调用 el3_exit → ERET 进入 BL32 // ③ BL32 初始化完成后 SMC 返回 EL3 // ④ 控制回到 bl31_main } // ⑪ 如果 RME 启用且注册了 RMM 初始化钩子 if (rmm_init ! NULL) { int32_t rc (*rmm_init)(); // → 同上模式进入 RMM (R-EL2) 初始化再返回 }关键设计模式 BL32 初始化是一个 去又回 的过程bl31_main │ └── bl32_init() │ ├─ SPD 设置 BL32 上下文ELR_EL3 BL32入口, SPSR S.EL1 ├─ el3_exit → ERET ──▶ BL32 (S-EL1) 开始执行 │ │ │ ├─ 初始化自身 │ └─ SMC #0 返回 EL3 ──▶ BL31 SMC handler │ │ │ ◀─────────── el3_exit ──────────────┘ └── 返回 bl31_main阶段 D★ 准备退出到 BL33// ⑫ ★ 设置 BL33 上下文 bl31_prepare_next_image_entry();这是 bl31_main 最后的关键步骤见 bl31_main.cvoid bl31_prepare_next_image_entry(void) { // ① 决定目标镜像类型默认 NON_SECURE image_type bl31_get_next_image_type(); // ② 获取 BL33 的 entry point info // 包括 PC、SPSR、SCR_EL3 配置、启动参数 next_image_info bl31_plat_get_next_image_ep_info(image_type); // ③ ★ 用 BL33 信息填充 cpu_context // → setup_context_common() 中写入 // CTX_ELR_EL3 BL33 入口地址 // CTX_SPSR_EL3 MODE_EL2 或 MODE_EL1非安全 // CTX_SCR_EL3 NS1, HCE1, FIQ0, IRQ0, EA0, ... cm_init_my_context(next_image_info); // ④ 为 NS 退出做准备恢复 EL2 系统寄存器上下文 if (image_type NON_SECURE) { cm_prepare_el3_exit_ns(); // → 恢复 NS EL2 寄存器的保存值 // → 设置下一 ERET 的上下文目标 } }最后bl31_plat_runtime_setup(); // 平台运行时钩子 console_switch_state(...); // 控制台切换到运行时模式 } // ★ bl31_main 返回到 bl31_entrypoint.S三、出口bl31_entrypoint.Sbl31_main 返回后BL31 做了最后一件重要的事/* * bl31_main 返回后 * * 数据缓存清理 → 确保辅助 CPU 看到正确的全局数据 * */ // ① 将 .data 段刷到主存 adrp x0, __DATA_START__ ... bl clean_dcache_range // ② 将 .bss 段刷到主存 adrp x0, __BSS_START__ ← 已初始化的全局变量 ... bl clean_dcache_range // ③ 将 .percpu 段刷到主存 adrp x0, __PER_CPU_START__ ← 每个 CPU 的私有数据 ... bl clean_dcache_range // ④ 平台特定 per-cpu 缓存清理 bl plat_per_cpu_dcache_clean // ★ ⑤ ERET 到非安全世界 (BL33) b el3_exitel3_exit 最终执行 exception_return在 context.Sexception_return (ERET) │ ├─ PC ← ELR_EL3 BL33 入口地址Uboot/UEFI/Linux ├─ PSTATE ← SPSR_EL3 AArch64, SP_ELx, 所有异常屏蔽 │ 异常级别EL2有 hypervisor或 EL1 ├─ SCR_EL3.NS 1 ← 切到非安全世界 └─ 参数 ← x0..x7 BL31 传递给 BL33 的启动参数 含 DTB 地址、BL32 信息等Warm Boot 入口bl31_warm_entrypoint 的快速路径当 PSCI 唤醒 CPU如 CPU_ON、CPU_SUSPEND 恢复时走 bl31_entrypoint.S133 func bl31_warm_entrypoint │ ├─ el3_entrypoint_common (最小参数) │ _init_sctlrPROGRAMMABLE_RESET_ADDRESS │ _warm_boot_mailbox0 │ _init_memory0 ← 冷启动已初始化 │ _init_c_runtime0 ← 冷启动已做好 │ _exception_vectorsruntime_exceptions │ ├─ bl31_plat_enable_mmu() ← 开启 MMU │ ├─ bl31_warmboot() ← PSCI warm boot │ └─ psci_warmboot_entrypoint() │ ├─ 恢复此 CPU 的 PSCI 状态 │ ├─ 决定返回地址suspend 恢复或 CPU_ON │ └─ 设置上下文 │ └─ b el3_exit ← ERET 回到 NS 世界核心总结阶段代码位置关键动作入口bl31_entrypoint.S保存参数 →el3_entrypoint_common栈、VBAR_EL3、BSS→bl bl31_main基础初始化bl31_main.c控制台、MMU、GIC、平台、上下文管理★ 运行时服务runtime_svc.c遍历.rt_svc_descs段注册 PSCI/SPD/SDEI/RMMD 等服务SP 初始化bl31_main.cbl32_init()→ ERET 进入 BL32 → SMC 返回★ 退出准备bl31_main.c/context_mgmt.ccm_init_my_context()写 CTX_ELR_EL3 BL33 入口缓存清理bl31_entrypoint.Sdata/bss/percpu clean 到主存多核一致性出口context.Sexception_returnERET → BL33PCELR_EL3, SCR_EL3.NS1总结 BL31 先是初始化自己MMU、GIC、异常向量、然后注册运行时服务PSCI/SPD 等 SMC 分发器、接着进入安全负载初始化并返回BL32/RMM、最后设置 BL33 上下文 刷缓存 → el3_exit → ERET进入非安全世界。在这之后BL31 作为异常向量宿主常驻 EL3随时响应 SMC 中断。