bl31 引导部分
bl32 遵循 ATF启动框架, 自然而然,bl32 由bl31 启动, bl31 会 初始化bl32 img运行地址, 将pc指针指向改地址后, 初始化bl32 运行环境, 然后重新返回bl31
详细代码如下:services/spd/opteed/opteed_main.c
/*******************************************************************************
* OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type
* (aarch32/aarch64) if not already known and initialises the context for entry
* into OPTEE for its initialization.
******************************************************************************/
static int32_t opteed_setup(void)
{
entry_point_info_t *optee_ep_info;
uint32_t linear_id;
uint64_t opteed_pageable_part;
uint64_t opteed_mem_limit;
uint64_t dt_addr;
linear_id = plat_my_core_pos();
/*
* Get information about the Secure Payload (BL32) image. Its
* absence is a critical failure. TODO: Add support to
* conditionally include the SPD service
*/
optee_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
if (!optee_ep_info) {
WARN("No OPTEE provided by BL2 boot loader, Booting device"
" without OPTEE initialization. SMC`s destined for OPTEE"
" will return SMC_UNK\n");
return 1;
}
/*
* If there's no valid entry point for SP, we return a non-zero value
* signalling failure initializing the service. We bail out without
* registering any handlers
*/
if (!optee_ep_info->pc)
return 1;
#ifdef CONFIG_OPTEE_AARCH64
opteed_rw = OPTEE_AARCH64;
#else
opteed_rw = optee_ep_info->args.arg0;
#endif
opteed_pageable_part = optee_ep_info->args.arg1;
opteed_mem_limit = optee_ep_info->args.arg2;
dt_addr = optee_ep_info->args.arg3;
opteed_init_optee_ep_state(optee_ep_info,
opteed_rw,
optee_ep_info->pc,
opteed_pageable_part,
opteed_mem_limit,
dt_addr,
&opteed_sp_context[linear_id]);
/*
* All OPTEED initialization done. Now register our init function with
* BL31 for deferred invocation
*/
bl31_register_bl32_init(&opteed_init);
return 0;
}
在这里我只说明重要关键的部分, 注意看bl31_register_bl32_init(&opteed_init)
该函数注册了bl32 的启动函数地址指针,用于后续执行opteed_init
接下来看 该函数是如何实现的
void bl31_register_bl32_init(int32_t (*func)(void))
{
bl32_init = func;
}
注意看,这里bl32_init 函数被赋值, 那么后续调用类似 (*bl32_init)()
这样的形式
请看 bl31/bl31_main.c
bl31_main
函数, 这里我截取了关键部分
void bl31_main(void)
{
if (bl32_init != NULL)
{
INFO("BL31: Initializing BL32\n");
int32_t rc = (*bl32_init)();
if (rc == 0) {
WARN("BL31: BL32 initialization failed\n");
}
}
}
看到没有 bl31 的初始化过程会 进一步初始化bl32 , 不要以为bl31 和32 是两个不相干的img,其实他们密不可分,在启动后,依然bl31 和bl32 之间通过SMCCALL 形式 传递数据。
bl32 启动部分
下面介绍bl32 在调用 (*bl32_init)()
之后, 究竟干了哪些事情。
core/arch/arm/kernel/generic_entry_a64.S
文件是整个bl32 init的入口文件,
FUNC _start
, 函数是第一个执行的汇编函数
FUNC _start , :
mov x19, x0 /* Save pagable part address */
mov x20, x2 /* Save DT address */
adr x0, reset_vect_table
msr vbar_el1, x0
isb
set_sctlr_el1
isb
/*
* The binary is built as:
* [Core, rodata and data] : In correct location
* [struct boot_embdata + data] : Should be moved to __end, first
* uint32_t tells the length of the struct + data
*/
adr_l x0, __end /* dst */
adr_l x1, __data_end /* src */
ldr w2, [x1] /* struct boot_embdata::total_len */
/* Copy backwards (as memmove) in case we're overlapping */
add x0, x0, x2
add x1, x1, x2
adr x3, cached_mem_end
str x0, [x3]
adr_l x2, __end
copy_init:
ldp x3, x4, [x1, #-16]!
stp x3, x4, [x0, #-16]!
cmp x0, x2
b.gt copy_init
/*
* Clear .bss, this code obviously depends on the linker keeping
* start/end of .bss at least 8 byte aligned.
*/
adr_l x0, __bss_start
adr_l x1, __bss_end
clear_bss:
str xzr, [x0], #8
cmp x0, x1
b.lt clear_bss
/* Setup SP_EL0 and SP_EL1, SP will be set to SP_EL0 */
set_sp
bl thread_init_thread_core_local
/* Enable aborts now that we can receive exceptions */
msr daifclr, #DAIFBIT_ABT
/*
* Invalidate dcache for all memory used during initialization to
* avoid nasty surprices when the cache is turned on. We must not
* invalidate memory not used by OP-TEE since we may invalidate
* entries used by for instance ARM Trusted Firmware.
*/
adr_l x0, __text_start
ldr x1, cached_mem_end
sub x1, x1, x0
bl dcache_cleaninv_range
/* Enable Console */
bl console_init
mov x0, #0
adr x1, boot_mmu_config
bl core_init_mmu_map
bl __get_core_pos
bl enable_mmu
mov x0, x19 /* pagable part address */
mov x1, #-1
bl boot_init_primary_early
mov x0, x20 /* DT address */
bl boot_init_primary_late
/*
* In case we've touched memory that secondary CPUs will use before
* they have turned on their D-cache, clean and invalidate the
* D-cache before exiting to normal world.
*/
adr_l x0, __text_start
ldr x1, cached_mem_end
sub x1, x1, x0
bl dcache_cleaninv_range
/*
* Pass the vector address returned from main_init
* Compensate for the load offset since cpu_on_handler() is
* called with MMU off.
*/
ldr x0, boot_mmu_config + CORE_MMU_CONFIG_LOAD_OFFSET
adr x1, thread_vector_table
sub x1, x1, x0
mov x0, #TEESMC_OPTEED_RETURN_ENTRY_DONE
smc #0
/* SMC should not return */
panic_at_smc_return
END_FUNC _start
DECLARE_KEEP_INIT _start
这里我删除了大量 汇编code, 仅仅提取出来几个重要的关键执行步骤
大概做了如下操作
- 清除bss段
console_init
初始化串口core_init_mmu_map
配置mmu 页表enable_mmu
使能mmu 映射boot_init_primary_early
初始化硬件boot_init_primary_late
调用一些initcall 函数thread_vector_table
初始化向量表smc #0
返回bl31
由此可以明白,bl32 并不是bl31运行完之后,才去调用的,而是 由bl31 发起,初始化好bl32 的环境之后, 重新调用smc 指令
回到bl31,继续bl31的后续的流程。
所以bl32 的环境都是在这次 bl32_init
函数一次性初始化完毕 。