jumparch64切换进入 ATF(BL31)完整原理
前置架构基础
- Preloader 运行环境:AArch32(ARM32)、EL1 非安全世界(Normal World)
- ATF BL31 运行环境:AArch64(ARM64)、EL3 最高安全特权级(Monitor 世界)
- 硬件限制:ARMv8 芯片无法直接在 AArch32 EL1 跳转到 AArch64 EL3,必须通过「软热复位 + 复位向量重定向」机制切换架构与异常级别;
- 核心寄存器:c12,c0,2 是 MTK 定制系统控制寄存器,专门控制复位后 CPU 架构、复位请求、复位向量基址。
全局变量前置说明
- bl31_base_addr:全局变量,内存中存储 ATF BL31 镜像入口物理地址(由 bldr_load_tee_part 加载完成后赋值);
- rst_vector_base_addr:复位向量寄存器映射地址,写入该地址的值 = CPU 热复位后第一条执行指令的地址。
执行流程分析
步骤1:读取 ATF BL31 入口地址,准备写入复位向量
#define ATF_BOOT_ARG_ADDR (0x00100000) //MEMBASE + 70MB, Size: 64KB #define ATF_HEADER_SIG_SIZE (0x240) #define BL31_VECTOR_SIZE (0x800) #define BL31_BASE (CFG_ATF_ROM_MEMADDR + BL31_VECTOR_SIZE + ATF_HEADER_SIG_SIZE) struct mem_info item[] = { [PL_SRAM] = { .start = 0x100000, .size = 0x12000, .name = "sram" }, [PL_CACHE_SHARE] = { .start = 0x200000, .size = 0x40000, .name = "cache share" }, [PL_DRAMBUF] = { .start = PL_BOOTARG_BASE, .size = PL_BOOTARG_MAX_SIZE, /* include 1MB boottags */ .name = "boottags" }, [LK] = { .start = CFG_UBOOT_MEMADDR, .size = 0x400000, .name = "LK" }, [ATF] = { .start = PL_ATF_BASE, .size = PL_ATF_MAX_SIZE, .name = "ATF" }, [SSPM] = { .start = 0, .size = 0, .name = "SSPM-reserved" } }; //for init.s u32 bl31_base_addr = BL31_BASE; u32 rst_vector_base_addr = RVBADDRESS_CPU0; //直接从汇编就跳转到ATF了 LDR r5, =bl31_base_addr ; r5 = bl31_base_addr 变量自身地址 LDR r5,[r5] ; 从变量中取出 ATF 真实运行物理地址存入 r5
- 前面 bldr_load_tee_part 加载 tee 分区时,已经把 ATF 镜像拷贝到 DRAM 固定地址,并将入口写入 bl31_base_addr;
- 现在 r5 保存的值 = ATF BL31 程序入口。
步骤2:把 ATF 入口写入热复位向量基址
LDR r6, =rst_vector_base_addr ; r6 = 复位向量寄存器地址 LDR r6,[r6] ; 读取寄存器基址 str r5,[r6] ; 将 ATF 入口写入复位向量
核心作用:
CPU 发生热复位(warm reset)时,不会回到上电原始 BootROM,而是从 rst_vector_base_addr 存放的地址取指执行;
此时我们提前把 ATF 入口塞进去,复位后 CPU 直接跑 ATF。
步骤3:配置复位后 CPU 运行架构为 AArch64
MRC p15,0,r6,c12,c0,2 ; 读取定制复位控制寄存器到 r6 orr r6, r6, #1 ; bit0置1:复位后启用AArch64模式 MCR p15,0,r6,c12,c0,2 ; 写回寄存器 DSB ; 数据同步屏障,确保寄存器配置落地 ISB ; 指令同步屏障,刷新流水线
寄存器bit定义:
- bit0:1 = AArch64、0 = AArch32Preloader 当前是32位,必须在复位前标记下次启动用64位,否则复位后依旧是32位,无法执行64位ATF。
步骤4:发起硬件热复位请求
MRC p15,0,r6,c12,c0,2 ; 再次读取复位控制寄存器 orr r6, r6, #2 ; bit1置1:触发warm热复位标记 MCR p15,0,r6,c12,c0,2 ; 写回寄存器 DSB ISB
bit1=1 代表向芯片电源/复位控制器发送热复位请求:
- 热复位:只重置CPU内核、流水线、寄存器,不会清空DRAM内存;
- 已经加载在DRAM中的ATF镜像完整保留,不会被擦除;
- 区别于冷复位(上电复位),冷复位会清空内存,丢失加载的ATF。
步骤5:WFI 循环等待复位触发
WFI_LOOP: WFI ; Wait For Interrupt,CPU进入低功耗暂停状态 B WFI_LOOP
- 执行WFI后CPU停止执行当前32位Preloader代码,等待硬件复位中断;
- 芯片复位控制器收到复位标记后,立刻触发CPU热复位;
- CPU流水线、通用寄存器全部清零,但DRAM中ATF镜像完好保留;
复位后完整跳转过程
- CPU 完成热复位,读取 rst_vector_base_addr 中预先存入的 ATF 入口地址;
- 读取架构配置bit0=1,CPU自动切换到AArch64 64位执行状态;
- 硬件自动提升异常级别到EL3(Monitor模式,ATF专属最高权限);
- 从ATF BL31入口地址开始执行64位ATF代码。
核心切换关键点
- 不能直接跳转:AArch32 EL1 无法分支/跳转到 AArch64 EL3,架构与异常级别双重隔离,只能靠复位切换;
- 热复位的优势:DRAM数据不丢失,Preloader提前加载好的ATF镜像不会被清空,无需重新加载固件;
- 三层切换同步完成:
- 指令集:AArch32 → AArch64
- 异常级别:EL1(Preloader) → EL3(ATF)
- 安全世界:普通世界 → Monitor安全监控世界
安全设计意义
- EL3 是ARMv8硬件最高特权,只有ATF能运行,Preloader(BL2)无权操作TEE、安全寄存器;
- 通过复位机制强制切换特权级,形成硬件隔离边界,Preloader漏洞无法直接篡改EL3安全逻辑;
- 复位向量由Preloader可控,但ATF镜像本身经过之前 bldr_load_tee_part RSA验签,即便向量被篡改,非法ATF镜像也无法加载执行。