ATF学习 - BL2

今天开始学习ARM Trusted Firmware相关的知识,继续学习BL2部分。BL1的学习在https://blog.csdn.net/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主要做了以下一些事情:

  1. 设中断向量
  2. 初始化中断控制寄存器,系统控制寄存器
  3. 清零BSS段,COHERENT段(或许我们暂时不用)
  4. 设置堆栈指针
  5. bl2_setup
  6. 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迁移到EL10x0000x0800x1000x180
同级exception level迁移,使用SP_ELx。例如EL1迁移到EL10x2000x2800x3000x380
ELx迁移到ELy,其中y>x并且ELx处于AArch64状态0x4000x4800x5000x580
ELx迁移到ELy,其中y>x并且ELx处于AArch32状态0x6000x6800x7000x780
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值