MTK安全启动分析8:MTK MicroTrust BL32 ATF跳转到LK流程

MT8766 MicroTrust BL32 初始化完成后返回、跳转LK完整流程

结合Preloader汇编jumparch64、TEE编译Makefile、ARMv8 TF-A标准架构,完整拆解,区分硬件机制、ATF代码逻辑、MTK定制链路

前置架构基础

ARMv8 TrustZone硬件铁律:
  1. EL3(ATF BL31):唯一拥有跨世界切换权限,只有EL3能修改SCR_EL3安全位、执行ERET切换安全/非安全世界;
  2. S-EL1(MicroTrust BL32 TEE):安全世界内核,无权直接跳LK,TEE初始化完成必须通过SMC同步异常陷回EL3 ATF;
  3. EL1(LK BL33):普通世界Bootloader,只能通过SMC调用安全服务,无法主动切安全世界;
  4. 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流程中:
  1. 加载tee_a → 拼接好的atf_teeid.img + microtrust_teeid.img(BL31+BL32整体tee.img),存入CFG_ATF_ROM_MEMADDR;
  2. 加载lk_a/lk_b,存入CFG_UBOOT_MEMADDR;
  3. 两块镜像都完成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
动作总结:
  1. 把BL31入口写入芯片复位向量寄存器;
  2. 配置复位后CPU切AArch64;
  3. 发送热复位信号,CPU暂停进入WFI等待复位;
  4. 热复位触发后,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;
}

  1. ATF读取tee.img中BL32镜像的GFH头部,校验独立RSA签名;
  2. 配置SCR_EL3.NS=0(标记接下来进入安全世界);
  3. 填充S-EL1上下文(栈、异常向量、BL32入口);
  4. 执行ERET,CPU从EL3下降到S-EL1,开始运行MicroTrust BL32。

阶段3:MicroTrust BL32 TEE 完整初始化 + SMC返回EL3(关键:TEE回到ATF的核心动作)

3.1 BL32内部完整初始化流程

MicroTrust内核执行顺序:
  1. 安全堆、TZ内存、硬件加密引擎初始化;
  2. RPMB、eFuse安全接口初始化;
  3. 批量加载所有内置TA(secstore/指纹/DRM/防克隆TA);
  4. 初始化安全中断、TZASC外设隔离;
  5. 完成整机安全环境就绪,此时TEE进入常驻服务状态,等待普通世界SMC请求。

3.2 TEE主动发送SMC,陷回EL3 BL31(TEE没有权限直接跳LK)

TEE初始化收尾执行一条标准安全监控SMC指令:
SMC #0x32000000 // MT MicroTrust专用SPD同步返回FID
硬件行为:
  1. CPU从S-EL1安全世界触发SMC同步异常,自动提升到EL3
  2. 异常向量进入BL31的smc_handler64;
  3. ATF匹配SMC FID,识别为「BL32初始化完成、归还控制权」;
  4. 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硬件原子操作(一步完成权限切换):
  1. 把ELR_EL3的值加载到PC(跳LK入口);
  2. 恢复SPSR到PSTATE,CPU降级到EL1;
  3. SCR_EL3.NS=1 永久开启普通世界模式;
  4. 完全退出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:
  1. 前半段atf_teeid.img = BL31 ATF,复位向量指向它;
  2. 后半段microtrust_teeid.img = BL32 MicroTrust;
  3. 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 安卓二级引导)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值