今天开始学习ARM Trusted Firmware相关的知识,继续学习BL2部分。BL1的学习在https://blog.csdn/orlando19860122/article/details/93327289。有了BL1部分的学习,BL2部分就轻松很多。
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2_entrypoint
func bl2_entrypoint
/*---------------------------------------------
* Save arguments x0 - x3 from BL1 for future
* use.
* ---------------------------------------------
*/
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
/* ---------------------------------------------
* 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 and disable
* speculative loads.
* ---------------------------------------------
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el1
orr x0, x0, x1
bic x0, x0, #SCTLR_DSSBS_BIT
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.
* ---------------------------------------------
*/
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 zeromem
#if USE_COHERENT_MEM
adrp x0, __COHERENT_RAM_START__
add x0, x0, :lo12:__COHERENT_RAM_START__
adrp x1, __COHERENT_RAM_END_UNALIGNED__
add x1, x1, :lo12:__COHERENT_RAM_END_UNALIGNED__
sub x1, x1, x0
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
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform BL2 setup
* ---------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x22
mov x3, x23
bl bl2_setup
/* ---------------------------------------------
* Enable pointer authentication
* ---------------------------------------------
*/
#if ENABLE_PAUTH
mrs x0, sctlr_el1
orr x0, x0, #SCTLR_EnIA_BIT
#if ENABLE_BTI
/* ---------------------------------------------
* Enable PAC branch type compatibility
* ---------------------------------------------
*/
bic x0, x0, #(SCTLR_BT0_BIT | SCTLR_BT1_BIT)
#endif /* ENABLE_BTI */
msr sctlr_el1, x0
isb
#endif /* ENABLE_PAUTH */
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint
从上面的代码可以看到,entrypoint主要做了以下一些事情:
- 设中断向量
- 初始化中断控制寄存器,系统控制寄存器
- 清零BSS段,COHERENT段(或许我们暂时不用)
- 设置堆栈指针
- bl2_setup
- bl2_main跳转下一个BL
设置的寄存器如下:
因此我们可以看到,下面需要主要分析的是bl2_setup和bl2_main
void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
u_register_t arg3)
{
/* Perform early platform-specific setup */
bl2_early_platform_setup2(arg0, arg1, arg2, arg3);
#ifdef AARCH64
/*
* Update pointer authentication key before the MMU is enabled. It is
* saved in the rodata section, that can be writen before enabling the
* MMU. This function must be called after the console is initialized
* in the early platform setup.
*/
bl_handle_pauth();
#endif /* AARCH64 */
/* Perform late platform-specific setup */
bl2_plat_arch_setup();
}
void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
meminfo_t *mem_layout = (meminfo_t *) arg1;
/* Initialize the console to provide early debug support */
rpi3_console_init();
/* Enable arch timer */
generic_delay_timer_init();
/* Setup GPIO driver */
rpi3_gpio_setup();
/* Setup the BL2 memory layout */
bl2_tzram_layout = *mem_layout;
/* Setup SDHost driver */
rpi3_sdhost_setup();
plat_rpi3_io_setup();
}
void bl2_plat_arch_setup(void)
{
rpi3_setup_page_tables(bl2_tzram_layout.total_base,
bl2_tzram_layout.total_size,
BL_CODE_BASE, BL_CODE_END,
BL_RO_DATA_BASE, BL_RO_DATA_END
#if USE_COHERENT_MEM
, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
#endif
);
enable_mmu_el1(0);
}
bl2_setup处理的内容和BL1类似,下面看一下bl2_main做的事情
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(); /* Give access to FP/SIMD registers */
#if TRUSTED_BOARD_BOOT
#endif /* TRUSTED_BOARD_BOOT */
/* initialize boot source */
bl2_plat_preload_setup(); //rasp没做什么处理
/* Load the subsequent bootloader images. */
next_bl_ep_info = bl2_load_images(); /* 加载BL31 BL32 BL33 */
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.
*/
/* 返回到BL1 */
smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0);
}
void bl2_arch_setup(void)
{
/* Give access to FP/SIMD registers */
write_cpacr(CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
}
BL2j加载完BL31, BL32, BL33后通过smc指令跳转到BL1。smc指令会触发一个软中断,然后被BL1的中断向量处理函数捕捉后继续执行。
func smc_handler64
/* ----------------------------------------------
* Detect if this is a RUN_IMAGE or other SMC.
* ----------------------------------------------
*/
mov x30, #BL1_SMC_RUN_IMAGE
cmp x30, x0
b.ne smc_handler /* 处理普通的SMC中断,跳过,忽略 */
/* ------------------------------------------------
* Make sure only Secure world reaches here.
* ------------------------------------------------
*/
mrs x30, scr_el3
tst x30, #SCR_NS_BIT
b.ne unexpected_sync_exception
/* ----------------------------------------------
* Handling RUN_IMAGE SMC. First switch back to
* SP_EL0 for the C runtime stack.
* ----------------------------------------------
*/
ldr x30, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
msr spsel, #0
mov sp, x30
/* ---------------------------------------------------------------------
* Pass EL3 control to next BL image.
* Here it expects X1 with the address of a entry_point_info_t
* structure describing the next BL image entrypoint.
* ---------------------------------------------------------------------
*/
mov x20, x1
mov x0, x20
bl bl1_print_next_bl_ep_info
ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] /* 取出了pc和spsr到x0, x1 */
msr elr_el3, x0 /* 设定下一个BL的入口地址 */
msr spsr_el3, x1 /* 设定下一个BL的el等级 */
ubfx x0, x1, #MODE_EL_SHIFT, #2
cmp x0, #MODE_EL3
b.ne unexpected_sync_exception
bl disable_mmu_icache_el3
tlbi alle3
dsb ish /* ERET implies ISB, so it is not needed here */
#if SPIN_ON_BL1_EXIT
bl print_debug_loop_message
debug_loop:
b debug_loop
#endif
mov x0, x20
bl bl1_plat_prepare_exit
ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
eret
endfunc smc_handler64
最终通过eret跳出中断处理函数,执行下一个BL的入口函数,一般就是BL31。
后记:
如何定义exception handler?
系统有那么多异常,不同的异常有可以将处理器状态迁移到不同的exception level中,如何组织这些exception handler呢?第一阶是各个exception level的Vector Base Address Register (VBAR)寄存器,该寄存器保存了各个exception level的异常向量表的基地址。该寄存器有三个,分别是VBAR_EL1,VBAR_EL2,VBAR_EL3。
具体的exception handler是通过vector base address + offset得到,offset的定义如下表所示:
exception level迁移情况 | Synchronous exception的offset值 | IRQ和vIRQ exception的offset值 | FIQ和vFIQ exception的offset值 | SError和vSError exception的offset值 |
同级exception level迁移,使用SP_EL0。例如EL1迁移到EL1 | 0x000 | 0x080 | 0x100 | 0x180 |
同级exception level迁移,使用SP_ELx。例如EL1迁移到EL1 | 0x200 | 0x280 | 0x300 | 0x380 |
ELx迁移到ELy,其中y>x并且ELx处于AArch64状态 | 0x400 | 0x480 | 0x500 | 0x580 |
ELx迁移到ELy,其中y>x并且ELx处于AArch32状态 | 0x600 | 0x680 | 0x700 | 0x780 |
更多推荐
ATF学习 - BL2
发布评论