MT8766 MicroTrust BL32 初始化完成后返回、跳转LK完整流程
结合Preloader汇编jumparch64、TEE编译Makefile、ARMv8 TF-A标准架构,完整拆解,区分硬件机制、ATF代码逻辑、MTK定制链路
前置架构基础
ARMv8 TrustZone硬件铁律:
- EL3(ATF BL31):唯一拥有跨世界切换权限,只有EL3能修改SCR_EL3安全位、执行ERET切换安全/非安全世界;
- S-EL1(MicroTrust BL32 TEE):安全世界内核,无权直接跳LK,TEE初始化完成必须通过SMC同步异常陷回EL3 ATF;
- EL1(LK BL33):普通世界Bootloader,只能通过SMC调用安全服务,无法主动切安全世界;
- MT8766链路分工:
- Preloader(BL2):一次性把 tee.img(BL31+BL32)、lk_a/lk_b 全部加载到DRAM,永久保存在内存(热复位不清DRAM);
- 汇编jumparch64:触发CPU暖复位,强制进入AArch64 EL3,从BL31入口执行;
- BL31 ATF:先启动BL32,等TEE全部初始化完毕,切换到ATF,再切换非安全世界,跳转预加载好的LK。
阶段1:Preloader侧前置准备
1.1 固件全加载(bldr_load_images)
Preloader在bldr_pre_process流程中:
- 加载tee_a → 拼接好的atf_teeid.img + microtrust_teeid.img(BL31+BL32整体tee.img),存入CFG_ATF_ROM_MEMADDR;
- 加载lk_a/lk_b,存入CFG_UBOOT_MEMADDR;
- 两块镜像都完成RSA验签,常驻DRAM,暖复位不会清空。
1.2 jumparch64 汇编配置暖复位
jumparch64:
LDR r5, =bl31_base_addr
LDR r5,[r5] ; 读取BL31 ATF入口地址
LDR r6, =rst_vector_base_addr
str r5,[r6] ; 写入复位向量:暖复位后PC直接指向BL31
MRC p15,0,r6,c12,c0,2
orr r6, #1 ; 复位后启用AArch64 64位模式
MCR p15,0,r6,c12,c0,2
DSB;ISB
orr r6,#2 ; 发起warm热复位请求
MCR p15,0,r6,c12,c0,2
WFI_LOOP: WFI; B WFI_LOOP
动作总结:
- 把BL31入口写入芯片复位向量寄存器;
- 配置复位后CPU切AArch64;
- 发送热复位信号,CPU暂停进入WFI等待复位;
- 热复位触发后,DRAM数据完整保留,CPU自动从BL31地址启动EL3 ATF。
阶段2:ATF BL31 启动,加载并运行MicroTrust BL32
2.1 BL31主流程 bl31_main(TF-A标准入口)
bl31_main()
{
// 1. 平台、GIC、PSCI、SMC调度初始化
bl31_early_platform_setup();
bl31_plat_arch_setup();
runtime_svc_init(); // SMC服务注册(MicroTrust SPD安全分发器)
// 2. 注册BL32 SPD驱动(MT MicroTrust适配层)
microtrust_spd_register();
// 3. 进入安全世界,执行BL32 TEE初始化
bl32_init();
// ↓ 此处阻塞,直到BL32完整初始化、SMC返回BL31
// 4. TEE返回后,准备非安全世界上下文,跳转LK
/* Determine which image to execute next */
image_type = bl31_get_next_image_type();
/* Program EL3 registers to enable entry into the next EL */
next_image_info = bl31_plat_get_next_image_ep_info(image_type);
assert(next_image_info != NULL);
assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
INFO("BL31: Preparing for EL3 exit to %s world\n",
(image_type == SECURE) ? "secure" : "normal");
print_entry_point_info(next_image_info);
cm_init_my_context(next_image_info);
cm_prepare_el3_exit(image_type);// ERET切非安全世界,跳BL33 LK
}
2.2 bl32_init 执行流程(进入S-EL1运行TEE)
tf-a-2.4\services\spd\teeid\450\teei_fastcall.c
DECLARE_RT_SVC(
teei_fastcall,
OEN_TOS_START,
OEN_TOS_END,
SMC_TYPE_FAST,
teei_fastcall_setup,
teei_fastcall_handler
);
tf-a-2.4\services\spd\teeid\450\teei_main.c
int teei_fastcall_setup(void)
{
if (is_abnormal_boot()) {
ERROR("abnormal boot, return\n");
return 0;
}
entry_point_info_t *image_info;
image_info = bl31_plat_get_next_image_ep_info(SECURE);
assert(image_info);
uint32_t linear_id = plat_core_pos_by_mpidr(read_mpidr());
teeiBootCoreMpidr = read_mpidr();
teei_gic_setup();
teei_init_secure_context(&secure_context[linear_id]);
if (teei_is_aarch64())
teei_init_eret(image_info->pc, TEEI_AARCH64);
else
teei_init_eret(image_info->pc, TEEI_AARCH32);
bl31_register_bl32_init(&teei_init_entry);
return 0;
}
- ATF读取tee.img中BL32镜像的GFH头部,校验独立RSA签名;
- 配置SCR_EL3.NS=0(标记接下来进入安全世界);
- 填充S-EL1上下文(栈、异常向量、BL32入口);
- 执行ERET,CPU从EL3下降到S-EL1,开始运行MicroTrust BL32。
阶段3:MicroTrust BL32 TEE 完整初始化 + SMC返回EL3(关键:TEE回到ATF的核心动作)
3.1 BL32内部完整初始化流程
MicroTrust内核执行顺序:
- 安全堆、TZ内存、硬件加密引擎初始化;
- RPMB、eFuse安全接口初始化;
- 批量加载所有内置TA(secstore/指纹/DRM/防克隆TA);
- 初始化安全中断、TZASC外设隔离;
- 完成整机安全环境就绪,此时TEE进入常驻服务状态,等待普通世界SMC请求。
3.2 TEE主动发送SMC,陷回EL3 BL31(TEE没有权限直接跳LK)
TEE初始化收尾执行一条标准安全监控SMC指令:
SMC #0x32000000 // MT MicroTrust专用SPD同步返回FID
硬件行为:
- CPU从S-EL1安全世界触发SMC同步异常,自动提升到EL3;
- 异常向量进入BL31的smc_handler64;
- ATF匹配SMC FID,识别为「BL32初始化完成、归还控制权」;
- SPD分发器microtrust_spd_handler处理完返回,回到bl31_main阻塞点,继续向下执行跳转LK逻辑。
重点:BL32绝对不能直接访问非世界内存、修改EL3寄存器,必须靠SMC把执行权还给ATF,由EL3统一切换到LK。
阶段4:BL31 ATF 切换非安全世界,跳转LK BL33
TEE通过SMC返回后,BL31执行两套上下文配置,最终ERET跳LK:
4.1 读取LK加载信息(Preloader提前备好)
ATF从全局启动参数区读取Preloader传递的:
- LK镜像物理加载地址 CFG_UBOOT_MEMADDR;
- LK入口、栈、异常等级(EL1非安全)。
4.2 配置非安全世界CPU上下文
初始化时设置了每个镜像的运行地址
func bl31_entrypoint
/* ---------------------------------------------------------------
* Stash the previous bootloader arguments x0 - x3 for later use.
* ---------------------------------------------------------------
*/
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
#if !RESET_TO_BL31
/* ---------------------------------------------------------------------
* For !RESET_TO_BL31 systems, only the primary CPU ever reaches
* bl31_entrypoint() during the cold boot flow, so the cold/warm boot
* and primary/secondary CPU logic should not be executed in this case.
*
* Also, assume that the previous bootloader has already initialised the
* SCTLR_EL3, including the endianness, and has initialised the memory.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=0 \
_warm_boot_mailbox=0 \
_secondary_cold_boot=0 \
_init_memory=0 \
_init_c_runtime=1 \
_exception_vectors=runtime_exceptions \
_pie_fixup_size=BL31_LIMIT - BL31_BASE
#else
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems which have a programmable reset address,
* bl31_entrypoint() is executed only on the cold boot path so we can
* skip the warm boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=runtime_exceptions \
_pie_fixup_size=BL31_LIMIT - BL31_BASE
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
* there's no argument to relay from a previous bootloader. Zero the
* arguments passed to the platform layer to reflect that.
* ---------------------------------------------------------------------
*/
mov x20, 0
mov x21, 0
mov x22, 0
mov x23, 0
#endif /* RESET_TO_BL31 */
/* --------------------------------------------------------------------
* Perform BL31 setup
* --------------------------------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x22
mov x3, x23
bl bl31_setup
/*******************************************************************************
* Setup function for BL31.
******************************************************************************/
void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
u_register_t arg3)
{
/* Perform early platform-specific setup */
bl31_early_platform_setup2(arg0, arg1, arg2, arg3);
/* Perform late platform-specific setup */
bl31_plat_arch_setup();
#if CTX_INCLUDE_PAUTH_REGS
/*
* Assert that the ARMv8.3-PAuth registers are present or an access
* fault will be triggered when they are being saved or restored.
*/
assert(is_armv8_3_pauth_present());
#endif /* CTX_INCLUDE_PAUTH_REGS */
}
static entry_point_info_t bl32_ep_info;
static entry_point_info_t bl33_ep_info;
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
static console_t console;
params_early_setup(arg1);
#if COREBOOT
if (coreboot_serial.type)
console_16550_register(coreboot_serial.baseaddr,
coreboot_serial.input_hertz,
coreboot_serial.baud,
&console);
#else
console_16550_register(UART0_BASE, UART_CLOCK, UART_BAUDRATE, &console);
#endif
NOTICE("MT8183 bl31_setup\n");
bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info);
}
4.3 el3_exit() + ERET 硬件跳转
adrp x0, __DATA_START__
add x0, x0, :lo12:__DATA_START__
adrp x1, __DATA_END__
add x1, x1, :lo12:__DATA_END__
sub x1, x1, x0
bl clean_dcache_range
adrp x0, __BSS_START__
add x0, x0, :lo12:__BSS_START__
adrp x1, __BSS_END__
add x1, x1, :lo12:__BSS_END__
sub x1, x1, x0
bl clean_dcache_range
b el3_exit
func el3_exit
#if ENABLE_ASSERTIONS
/* el3_exit assumes SP_EL0 on entry */
mrs x17, spsel
cmp x17, #MODE_SP_EL0
ASM_ASSERT(eq)
#endif
/* ----------------------------------------------------------
* Save the current SP_EL0 i.e. the EL3 runtime stack which
* will be used for handling the next SMC.
* Then switch to SP_EL3.
* ----------------------------------------------------------
*/
mov x17, sp
msr spsel, #MODE_SP_ELX
str x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
/* ----------------------------------------------------------
* Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET
* ----------------------------------------------------------
*/
ldr x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
ldp x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
msr scr_el3, x18
msr spsr_el3, x16
msr elr_el3, x17
#if IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639
/* ----------------------------------------------------------
* Restore mitigation state as it was on entry to EL3
* ----------------------------------------------------------
*/
ldr x17, [sp, #CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_DISABLE]
cbz x17, 1f
blr x17
1:
#endif
restore_ptw_el1_sys_regs
/* ----------------------------------------------------------
* Restore general purpose (including x30), PMCR_EL0 and
* ARMv8.3-PAuth registers.
* Exit EL3 via ERET to a lower exception level.
* ----------------------------------------------------------
*/
bl restore_gp_pmcr_pauth_regs
ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
#if IMAGE_BL31 && RAS_EXTENSION
/* ----------------------------------------------------------
* Issue Error Synchronization Barrier to synchronize SErrors
* before exiting EL3. We're running with EAs unmasked, so
* any synchronized errors would be taken immediately;
* therefore no need to inspect DISR_EL1 register.
* ----------------------------------------------------------
*/
esb
#endif
exception_return
endfunc el3_exit
ERET硬件原子操作(一步完成权限切换):
- 把ELR_EL3的值加载到PC(跳LK入口);
- 恢复SPSR到PSTATE,CPU降级到EL1;
- SCR_EL3.NS=1 永久开启普通世界模式;
- 完全退出EL3 ATF监控,进入LK运行。
阶段5:完整全局时序串联(所有代码联动)
1. BootROM BL1 → 验签、启动Preloader BL2(AArch32 EL1)
2. Preloader bldr_pre_process()
a. 初始化DDR、存储、安全库sec_lib_init()
b. bldr_load_images() 一次性加载 tee_a(BL31+BL32)、lk_a到DRAM
c. 执行jumparch64汇编:配置复位向量、发起warm热复位
3. CPU热复位,AArch64 EL3,自动执行BL31 ATF
a. ATF初始化PSCI/SMC/SPD
b. bl32_init() → ERET进入S-EL1 MicroTrust BL32
4. BL32 TEE完整初始化全部安全硬件+TA
→ 执行SMC指令,异常陷回EL3 BL31
5. BL31收到TEE返回,配置非安全世界上下文
→ ERET原子跳转,进入LK BL33(普通世界EL1)
6. LK初始化安卓外设,加载boot.img内核
3个核心约束与MTK定制特性
1. 为什么TEE不能直接跳LK?ARMv8硬件强制隔离
- S-EL1(安全世界)没有权限修改SCR_EL3安全位,无法关闭TrustZone隔离;
- 只有EL3能控制安全/非世界切换;
- TEE一旦允许直接跳转,会破坏硬件信任根隔离,存在安全逃逸漏洞。
2. DRAM常驻设计(Preloader提前加载所有固件)
MT8766方案特殊点:
Preloader一次性把ATF+TEE+LK全部载入内存,热复位不清DRAM;
ATF不需要再读写eMMC加载LK,直接使用Preloader准备好的镜像,大幅缩短启动时间。
3 和tee.img编译Makefile对应关系
编译生成的combined.img=atf_teeid.img+microtrust_teeid.img:
- 前半段atf_teeid.img = BL31 ATF,复位向量指向它;
- 后半段microtrust_teeid.img = BL32 MicroTrust;
- ATF运行时向后偏移内存找到BL32镜像,校验自身独立RSA签名后启动TEE。
Preloader(AArch32 EL1)
↓(jumparch64 暖复位)
CPU切换AArch64 EL3 → BL31 ATF
↓ ERET 切S-EL1
BL32 MicroTrust TEE 完整初始化
↓ SMC 异常陷回EL3
BL31 ATF 配置普通世界上下文
↓ ERET 原子跳转
LK BL33(EL1 安卓二级引导)

356

被折叠的 条评论
为什么被折叠?



