BL2 image将会为后续image的加载执行相关的初始化操作。主要是内存,MMU,串口以及EL3软件运行环境的设置,并且加载bl3x的image到RAM中。通过查看bl2.ld.S文件就可以发现,bl2 image的入口函数是bl2_entrypoint。该函数定义在bl2/aarch64/bl2_entrypoint.S文件中。
1.bl2_entrypoint
该函数的内容如下,该函数最终会出发smc操作,从bl1中将CPU的控制权转交给bl31:
func bl2_entrypoint
/*---------------------------------------------
* Save from x1 the extents of the tzram
* available to BL2 for future use.
* x0 is not currently used.
* ---------------------------------------------
*/
mov x20, x1
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
adr x0, early_exceptions //设定异常向量
msr vbar_el1, x0
isb
/* ---------------------------------------------
* Enable the SError interrupt now that the
* exception vectors have been setup.
* ---------------------------------------------
*/
msr daifclr, #DAIF_ABT_BIT
/* ---------------------------------------------
* Enable the instruction cache, stack pointer
* and data access alignment checks
* ---------------------------------------------
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el1
orr x0, x0, x1
msr sctlr_el1, x0
isb
/* ---------------------------------------------
* Invalidate the RW memory used by the BL2
* image. This includes the data and NOBITS
* sections. This is done to safeguard against
* possible corruption of this memory by dirty
* cache lines in a system cache as a result of
* use by an earlier boot loader stage.
* ---------------------------------------------
*/
adr x0, __RW_START__
adr x1, __RW_END__
sub x1, x1, x0
bl inv_dcache_range
/* ---------------------------------------------
* Zero out NOBITS sections. There are 2 of them:
* - the .bss section;
* - the coherent memory section.
* ---------------------------------------------
*/
ldr x0, =__BSS_START__
ldr x1, =__BSS_SIZE__
bl zeromem
#if USE_COHERENT_MEM
ldr x0, =__COHERENT_RAM_START__
ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__
bl zeromem
#endif
/* --------------------------------------------
* Allocate a stack whose memory will be marked
* as Normal-IS-WBWA when the MMU is enabled.
* There is no risk of reading stale stack
* memory after enabling the MMU as only the
* primary cpu is running at the moment.
* --------------------------------------------
*/
bl plat_set_my_stack //初始化bl2运行的栈
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform early platform setup & platform
* specific early arch. setup e.g. mmu setup
* ---------------------------------------------
*/
mov x0, x20
bl bl2_early_platform_setup //设置平台相关
bl bl2_plat_arch_setup //设置架构相关
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main //跳转到BL2的主要函数执行,从该函数中跳转到bl31以及bl31,
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint
2. bl2_main
该函数主要实现将bl3x的image加载RAM中,并通过smc调用执行bl1中指定的smc handle将CPU的全向交给bl31。
void bl2_main(void)
{
entry_point_info_t *next_bl_ep_info;
NOTICE("BL2: %s\n", version_string);
NOTICE("BL2: %s\n", build_message);
/* Perform remaining generic architectural setup in S-EL1 */
bl2_arch_setup();
#if TRUSTED_BOARD_BOOT
/* Initialize authentication module */
auth_mod_init(); //初始化image验证模块
#endif /* TRUSTED_BOARD_BOOT */
/* Load the subsequent bootloader images. */
next_bl_ep_info = bl2_load_images(); //加载bl3x image到RAM中并返回bl31的入口地址
#ifdef AARCH32
/*
* For AArch32 state BL1 and BL2 share the MMU setup.
* Given that BL2 does not map BL1 regions, MMU needs
* to be disabled in order to go back to BL1.
*/
disable_mmu_icache_secure();
#endif /* AARCH32 */
console_flush();
/*
* Run next BL image via an SMC to BL1. Information on how to pass
* control to the BL32 (if present) and BL33 software images will
* be passed to next BL image as an argument.
*/
/* 调用smc指令,触发在bl1中设定的smc异常中断处理函数,跳转到bl31 */
smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0);
}
3. bl2_load_images
该函数用来加载bl3x的image到RAM中,返回一个具有image入口信息的变量。smc handle根据该变量跳转到bl31进行执行
entry_point_info_t *bl2_load_images(void)
{
bl_params_t *bl2_to_next_bl_params;
bl_load_info_t *bl2_load_info;
const bl_load_info_node_t *bl2_node_info;
int plat_setup_done = 0;
int err;
/*
* Get information about the images to load.
*/
/* 获取bl3x image的加载和入口信息 */
bl2_load_info = plat_get_bl_image_load_info();
/* 检查返回的bl2_load_info中的信息是否正确 */
assert(bl2_load_info);
assert(bl2_load_info->head);
assert(bl2_load_info->h.type == PARAM_BL_LOAD_INFO);
assert(bl2_load_info->h.version >= VERSION_2);
/* 将bl2_load_info中的head变量的值赋值为bl2_node_info,即将bl31 image的入口信息传递給bl2_node_info变量 */
bl2_node_info = bl2_load_info->head;
/* 进入loop循环, */
while (bl2_node_info) {
/*
* Perform platform setup before loading the image,
* if indicated in the image attributes AND if NOT
* already done before.
*/
/* 在加载特定的bl3x image到RAM之前先确定是否需要做平台的初始化 */
if (bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_PLAT_SETUP) {
if (plat_setup_done) {
WARN("BL2: Platform setup already done!!\n");
} else {
INFO("BL2: Doing platform setup\n");
bl2_platform_setup();
plat_setup_done = 1;
}
}
/* 对bl3x image进行电子验签,如果通过则执行加载操作 */
if (!(bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) {
INFO("BL2: Loading image id %d\n", bl2_node_info->image_id);
err = load_auth_image(bl2_node_info->image_id,
bl2_node_info->image_info);
if (err) {
ERROR("BL2: Failed to load image (%i)\n", err);
plat_error_handler(err);
}
} else {
INFO("BL2: Skip loading image id %d\n", bl2_node_info->image_id);
}
/* Allow platform to handle image information. */
/* 可以根据实际需要更改,通过给定image ID来更改image的加载信息 */
err = bl2_plat_handle_post_image_load(bl2_node_info->image_id);
if (err) {
ERROR("BL2: Failure in post image load handling (%i)\n", err);
plat_error_handler(err);
}
/* Go to next image */
bl2_node_info = bl2_node_info->next_load_info;
}
/*
* Get information to pass to the next image.
*/
/* 获取下一个执行的Image的入口信息,并且将以后会被执行的image的入口信息组合成链表 ,t通过判断image des中的ep_info.h.attr的值是否为(EXECUTABLE|EP_FIRST_EX)来确定接下来第一个被执行的image*/
bl2_to_next_bl_params = plat_get_next_bl_params();
assert(bl2_to_next_bl_params);
assert(bl2_to_next_bl_params->head);
assert(bl2_to_next_bl_params->h.type == PARAM_BL_PARAMS);
assert(bl2_to_next_bl_params->h.version >= VERSION_2);
/* Flush the parameters to be passed to next image */
plat_flush_next_bl_params();
/* 返回下一个进入的image的入口信息,即bl31的入口信息 */
return bl2_to_next_bl_params->head->ep_info;
}
4.REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
该宏的执行将会初始化组成bl2加载bl3x image的列表使用到的重要全局变量,其中bl2_mem_params_descs变量的定义如下:
static bl_mem_params_node_t bl2_mem_params_descs[] = {
#ifdef SCP_BL2_BASE
/* Fill SCP_BL2 related information if it exists */
{
.image_id = SCP_BL2_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
VERSION_2, image_info_t, 0),
.image_info.image_base = SCP_BL2_BASE,
.image_info.image_max_size = PLAT_CSS_MAX_SCP_BL2_SIZE,
.next_handoff_image_id = INVALID_IMAGE_ID,
},
#endif /* SCP_BL2_BASE */
#ifdef EL3_PAYLOAD_BASE
/* Fill EL3 payload related information (BL31 is EL3 payload)*/
{
.image_id = BL31_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE | EP_FIRST_EXE),
.ep_info.pc = EL3_PAYLOAD_BASE,
.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t,
IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
.next_handoff_image_id = INVALID_IMAGE_ID,
},
#else /* EL3_PAYLOAD_BASE */
/* Fill BL31 related information */
{
.image_id = BL31_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE | EP_FIRST_EXE),
.ep_info.pc = BL31_BASE,
.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS),
#if DEBUG
.ep_info.args.arg1 = ARM_BL31_PLAT_PARAM_VAL,
#endif
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
.image_info.image_base = BL31_BASE,
.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
# ifdef BL32_BASE
.next_handoff_image_id = BL32_IMAGE_ID,
# else
.next_handoff_image_id = BL33_IMAGE_ID,
# endif
},
# ifdef BL32_BASE
/* Fill BL32 related information */
{
.image_id = BL32_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
.ep_info.pc = BL32_BASE,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = BL32_BASE,
.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
.next_handoff_image_id = BL33_IMAGE_ID,
},
# endif /* BL32_BASE */
/* Fill BL33 related information */
{
.image_id = BL33_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
# ifdef PRELOADED_BL33_BASE
.ep_info.pc = PRELOADED_BL33_BASE,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
# else
.ep_info.pc = PLAT_ARM_NS_IMAGE_OFFSET,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = PLAT_ARM_NS_IMAGE_OFFSET,
.image_info.image_max_size = ARM_DRAM1_SIZE,
# endif /* PRELOADED_BL33_BASE */
.next_handoff_image_id = INVALID_IMAGE_ID,
}
#endif /* EL3_PAYLOAD_BASE */
};
在该变量中规定了SCP_BL2, EL3_payload, bl32, bl33 image的相关信息,例如:
image的入口地址信息:ep_info
image在RAM中的基地址:image_base
image的基本信息:image_info
image的ID值:image_id