平时天天看soc启动,但是一想启动的细节就不太清楚,今天准备针对性的梳理一下Arm 安全启动的部分流程,可能不是特别到位,但是需要一次一次梳理循序渐进。

  1. bl31初始化

  1. bl31_entrypoint.S

总体背景

  • BL31 运行在 EL3(最高特权级,Secure Monitor)

  • 它的作用:

    • 初始化 EL3 自身(寄存器、栈、C 运行环境)。

    • 初始化 MMU、内存、异常向量。

    • 为后续的 BL32 (OP-TEE, 可选) 和 BL33 (U-Boot/Linux kernel) 提供服务。

    • 负责 PSCI(CPU 上电/关机/休眠管理)

所以这份代码就是 BL31 的入口函数,CPU 从前一级 Bootloader 跳进来后执行。


bl31_entrypoint (冷启动入口)

func bl31_entrypoint

  • 这是冷启动入口,只有 primary CPU(通常是 CPU0) 执行。

保存传参

  • 把前级 Bootloader(BL2 或 BL1.5)传入的寄存器参数保存下来,后续会传给 bl31_setup()

公共初始化

el3_entrypoint_common ...

  • 调用一个宏,负责初始化 EL3 的基础环境(不同宏参数表示是否做某些动作):

    • _init_sctlr → 是否初始化 SCTLR_EL3(MMU/Cache控制寄存器)。

    • _warm_boot_mailbox → 是否设置热启动唤醒用的 mailbox。

    • _secondary_cold_boot → 是否允许次级 CPU 在冷启动参与启动。

    • _init_memory → 是否初始化内存。

    • _init_c_runtime → 是否初始化 C 环境(BSS 清零,全局变量准备)。

    • _exception_vectors → 设置异常向量表。

    • _pie_fixup_size → PIE 模式修正大小(位置无关代码支持)。

这里分两种情况:

  • !RESET_TO_BL31:说明从 BL2 跳进来,不需要重复初始化太多。

  • RESET_TO_BL31:说明 CPU 复位地址直接指到 BL31(不经过 BL2),那就要做更多初始化。

调用 bl31_setup

  • 把启动参数传给 C 语言的 bl31_setup(),做更复杂的初始化,比如:

    • 初始化控制台串口。

    • 初始化平台层(platform-specific init)。

    • 准备 Secure Payload Dispatcher(和 OP-TEE 交互)。

可选:启用 Pointer Authentication (PAC)

bl pauth_init_enable_el3

  • 如果启用了 ARMv8.3 的指针认证功能,则在 EL3 里设置 APIAKey_EL1。

调用 C 主函数

bl bl31_main

  • 进入 BL31 的主逻辑(C 实现),负责加载 BL32/BL33,设置上下文。

确保数据对次级 CPU 可见

  • 清理 .data.bss 段对应的缓存,保证 primary CPU 初始化的全局变量对 secondary CPU 可见。

退出 EL3

b el3_exit

  • 走统一的 el3_exit 路径,准备跳转到下一级世界。


bl31_warm_entrypoint (热启动入口)

func bl31_warm_entrypoint

  • 用于 次级 CPU 上电,或者 CPU 从 suspend 恢复

流程和 bl31_entrypoint 类似,但有区别:

runtime instrumentation(可选)

  • 如果启用了性能测量,会记录时间戳。

调用 el3_entrypoint_common

  • 和冷启动不同,热启动跳过了大部分初始化:

    • 不初始化内存。

    • 不初始化 C runtime。

    • 不区分 primary/secondary。

    • 只保证必要的寄存器和异常向量可用。

开启 MMU

bl bl31_plat_enable_mmu

  • 启动当前 CPU 的 MMU。

  • 注意这里有个条件:如果平台没有硬件缓存一致性,那么不能立刻打开 D-cache,否则可能破坏 coherency。

可选:GPT/RME 初始化

bl gpt_enable

  • 如果启用了 ARMv9 RME(Realm Management Extension),要设置 GPT 数据结构。

可选:启用 PAC

bl pauth_init_enable_el3

进入 PSCI 的热启动入口

bl psci_warmboot_entrypoint

  • 次级 CPU 调用 PSCI 初始化代码,加入 coherency,等待调度。

runtime instrumentation (退出时的时间戳)

mrs x0, cntpct_el0 str x0, [x19]

最终退出

b el3_exit


总结

  • bl31_entrypoint → 冷启动路径(primary CPU,初始化环境、调用 bl31_setup + bl31_main)。

  • bl31_warm_entrypoint → 热启动路径(secondary CPU / resume,快速进入 PSCI)。

  • 都会收敛到 el3_exit,从 EL3 跳到 BL32(OP-TEE)或 BL33(U-Boot/Linux)。

  1. bl31_main.c

bl31_setup()

初始化阶段:

  • 特性检测:确认编译启用的特性(Pointer Auth、SVE 等)是否 CPU 支持。

  • 早期串口plat_setup_early_console() 提供 early log。

  • 平台早期初始化bl31_early_platform_setup2()(芯片厂商平台定制)。

  • 架构初始化bl31_plat_arch_setup(),设置页表、MMU 等。

  • 上下文内存报告:打印 secure / non-secure context 内存占用。


bl31_main()

核心逻辑:

  • 扩展寄存器管理:初始化 EL3 扩展寄存器。

  • 平台初始化bl31_platform_setup(),加载 GIC/DSU 等外设驱动。

  • GIC 初始化gic_init + gic_cpuif_enable

  • 库初始化bl31_lib_init()(主要是上下文管理 cm_init)。

  • 异常框架ehf_init()(Exception Handling Framework)。

  • 运行时服务runtime_svc_init() 注册所有 service,如 PSCI

  • BL32 / RMM 初始化

    • 如果 bl32_init 已注册(SPD 调用 bl31_register_bl32_init()),调用 BL32 初始化。

    • 如果启用 RME,调用 rmm_init

  • 准备下一个镜像bl31_prepare_next_image_entry()

    • 决定进入 Secure World(BL32)还是 Normal World(BL33)。

    • 设置下一个世界的上下文(cm_init_my_context)。

    • 调用 cm_prepare_el3_exit[_ns]()

  • 平台 runtime setup

  • 等待 ERET 返回 → 跳入 Linux 或 OP-TEE。

  1. bl31跳转至optee

runtime_svc_init() 做了三件事:

  • 校验所有 Runtime Service 描述符 确保 OEN、handler 合法。

  • 调用服务初始化函数 让像 PSCI、OP-TEE 接口等做好准备。

  • 建立 OEN → Service 索引表 后续 SMC 调用时快速路由到正确的 service handler。

  1. optee初始化

_start 的整体职责

这是 OP-TEE 的 EL1 Secure Monitor 下的入口:

  • 保存 boot 参数(x0-x3)

  • 设置异常向量表 (VBAR_EL1 = reset_vect_table)

  • 初始化控制寄存器 SCTLR_EL1(打开 I-cache、SA、SPAN、可选 BTI/PAUTH/MEMTAG)

  • 清零 .bss,搬运 .init 段或 boot_embdata 数据

  • 建立 CPU 栈 (SP_EL0, SP_EL1)thread_core_local 结构

  • 启动 MMU 和 cache,初始化内存分布

  • 进入 C 世界 (boot_init_* 系列函数)

  • 最终通过 SMC 通知 ATF/BL31 “OP-TEE 初始化完成,可以切到 normal world”


栈初始化逻辑

在 OP-TEE 里,每个 CPU 有两套栈

  • SP_EL0 (线程栈) → 临时栈(stack_tmp),后面切换为 thread 里的 runtime 栈

  • SP_EL1 (core-local 栈)thread_core_local[cpu_id] 结构,用来保存 per-cpu 状态,比如 abort 栈、当前 thread id、flags

代码片段:

所以每个 core 启动时都有独立的 SP_EL0/EL1,保证并发安全。


MMU 启动 (enable_mmu)

OP-TEE 在 EL1 Secure 开启自己的 MMU,地址空间和 Linux (EL1 NS) 是隔离的。


Secondary CPU 上电 (cpu_on_handler)

这对应 PSCI 的 CPU_ON,当 Linux 想 bring-up 一个核时,通过 ATF → SMC → OP-TEE:

每个新核起来后,走一遍和 primary 类似的初始化:设置异常向量表、打开 MMU、设置 per-core 栈,然后交给 C 代码 (boot_cpu_on_handler)。


最终返回 BL31

当 primary core 完成初始化,会:

这就是通过 SMC 返回到 BL31,告诉 ATF “OP-TEE 已初始化完成,可以调度 Linux”。

  1. bl31跳转至bl33

准备bl33的镜像,等下一个eret去跳过去

查看一下el3 exit都干了那些事情,在哪里eret的

el3_exit 的任务是:

在 EL3(BL31)处理完初始化/调度逻辑后,把 EL3 的运行时上下文保存好、从 per-world 上下文里恢复到进入时的寄存器状态(包括 SCR_EL3、SPSR_EL3、ELR_EL3 等),然后执行 ERET,把控制权交给 lower EL(通常是 EL1 非安全的 BL33,或 EL1/EL2 的 BL32/secure payload)。

它不是简单的 eret — 必须先把 EL3 自己临时使用的状态(stack、控制寄存器、补丁、workaround 状态等)恢复到“入口时”的样子,保证返回后的环境一致且安全。


  1. 入口断言(可选)

  • 断言:进入 el3_exit必须处于 SP_EL0(EL3 runtime 使用 SP_EL0 模式)。这是函数对调用约定的假设,便于后面统一操作栈指针和存放上下文的位置。


  1. 保存当前 SP_EL0(EL3 runtime stack),切换到 SP_EL3

  • 把当前 sp(此时是 SP_EL0)保存到内存(EL3 上下文结构的 CTX_RUNTIME_SP 字段)。保存它的目的是:这个 runtime stack 在将来再次进入 EL3(处理 SMC)时要恢复。

  • 然后通过 msr spsel, #MODE_SP_ELX 切换到 SP_EL3,因为从现在起要使用 EL3 的栈框架去恢复更多寄存器(EL3 专用的存放区通常在 SP_EL3 所指向的栈上)。

注:ARMv8 有两个栈选择(SP_EL0 与 SP_ELx),在 EL3 内部可切换以访问不同的栈/上下文布局。


  1. 恢复 CPTR_EL3(协处理器访问控制)

  • get_per_world_context x9:加载指向当前 security-world 的 per-world context 的指针到 x9

  • 从该上下文读取 CPTR_EL3(保存在两个寄存器对里),写回 cptr_el3。这把协处理器访问控制恢复到进入 EL3 前的状态(比如对浮点/Neon/其他架构扩展的访问控制)。


  1. 恢复平台/实现相关寄存器(MPAM 等)与漏洞缓解状态

  • restore_mpam3_el3:若平台使用 MPAM(Memory Partitioning And Monitoring),在 EL3 需要恢复 MPAM 的寄存器状态。

  • CVE-2018-3639(Spectre v4)相关动态缓解:如果当初进入 EL3 时做了某个动态 workaround(比如安装了一个小函数),返回时需要按栈中记录的函数指针去调用以恢复/撤销状态。这里通过读取早先保存的位置并 blr x17 来执行恢复函数。


  1. 同步错误(platform-specific)

#if IMAGE_BL31 synchronize_errors #endif

  • 做实现/平台相关的错误同步(确保系统错误状态在返回前一致),通常是架构/平台上的清理或同步步骤。


  1. 从 EL3 上下文恢复关键系统寄存器(SPSR_EL3/ELR_EL3/SCR_EL3/MDCR_EL3)

  • 这些是返回最关键的寄存器:

    • SPSR_EL3:保存目标异常等级的 PSTATE(中断屏蔽、标志、模式位等)。写入后 ERET 会用它来确定返回到哪个 EL/哪种栈与中断屏蔽状态。

    • ELR_EL3:异常返回时的目标 PC(lower EL 的入口地址)。

    • SCR_EL3:Secure Configuration Register,包含 NS(non-secure)位、HCE、SMD、RES1/RES0、中断映射等,必须在返回前恢复到进入 EL3 前的值,否则会进入错误的安全世界/属性。

    • MDCR_EL3:Monitor Debug/PMU control(和性能监测/调试相关),恢复它以使 lower EL 的 PMU/monitor 行为一致。

恢复顺序重要:先把寄存器值加载到通用寄存器,再一次性写回系统寄存器,保证恢复恢复成进入 EL3 的精确状态。


  1. 恢复与页表相关的系统寄存器(PTW / translation walker regs)

restore_ptw_el1_sys_regs

  • 还原 page-table walker 相关的 EL1 系统寄存器(例如 TCR/TTBR/MAIR 等,具体实现里可能只还原 Walker 用到的部分),确保 lower EL 的地址转换行为正确。

  • 这一步对 MMU/页表一致性至关重要,特别是当 BL31 在 EL3 时临时改变了这些寄存器。


  1. 恢复通用寄存器、PMCR_EL0、PAUTH 等(并恢复 LR)

bl restore_gp_pmcr_pauth_regs ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]

  • restore_gp_pmcr_pauth_regs(一个子例程):

    • 恢复一批通用寄存器(x0..x??,按上下文保存的顺序),

    • 恢复 PMCR_EL0(Performance Monitor Control Register)等非 EL3 专属的系统寄存器,

    • 恢复 Pointer Authentication 的 key 寄存器(如果启用),即 APIAKey/ AUTH registers。

  • 之后显式从栈里加载 saved LR(x30)到 x30,以恢复返回地址。


  1. 清 EL3 标志(IMAGE_BL31 特殊)

#ifdef IMAGE_BL31 str xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG] #endif

  • 如果是 BL31 镜像,清除记录的“在 EL3 嵌套异常激活(EA)”标志,表明正要退出 EL3。


  1. exception_return 宏 —— 执行最终的返回(ERET

exception_return

  • 这个宏最终会展开为设置必要的寄存器(已经准备好 SPSR_EL3、ELR_EL3、并配置好要传给 lower EL 的通用寄存器 x0..x3),然后执行 ERET

  • ERET 的效果:

    • 根据 SPSR_EL3 恢复 PSTATE(包含目标 EL、中断屏蔽位等),

    • 将 PC 设置为 ELR_EL3,从而跳转到 lower EL(BL33/BL32 的入口)。

最后终于看到eret的汇编指令了

ARM 在 Spectre 攻击之后发现:

  • eret 之后,CPU 可能会 错误推测继续执行后续的指令(即使这些指令本不该执行)。

  • 如果攻击者能通过 cache side-channel 观测到这些推测执行的痕迹,就可能泄露敏感数据。

  • 所以在 eret 之后需要一个 speculation barrier(推测屏障) 来保证安全。

  • FEAT_SB 是 ARMv8.5-A 引入的 Speculation Barrier 特性。

    • 如果 CPU 支持这个 feature,ATF 就用 SB 指令(在这里宏替代成 sb_barrier_insn)。

    • SB 指令作用:阻止 所有可能错误路径的推测,比 DSB/ISB 更彻底。

  • 如果 CPU 不支持 FEAT_SB

    • 退而求其次,用:

      • dsb nsh (Data Synchronization Barrier, Non-shareable):保证之前的所有内存访问完成。

      • isb (Instruction Synchronization Barrier):清空 pipeline,保证之后的指令不会受之前推测的影响。

这样确保 eret 之后不会再去推测执行 EL3 后面的代码,避免敏感信息外泄。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐