赞
踩
ATF(ARM Trusted Firmware)是一针对ARM芯片给出的底层的开源固件代码。固件将整个系统分成四种运行等级,分别为:EL0,EL1,EL2,EL3,并规定了每个安全等级中运行的Image名字。本文以ARCH64为示例,介绍冷启动时,ATF的运行过程。ATF的源代码可以从github上获取,具体地址如下:
系统上电之后首先会运行SCP boot ROM。之后会跳转到ATF的bl1中继续执行。bl1主要初始化CPU,设定异常向量,将bl2的image加载到安全RAM中,然后跳转到bl2中进行执行。
在bl2中将会去加载bl31和bl32以及bl33,其中的cpu状态切换以及跳转将在以下章节详细介绍。
bl1的主要代码存放在bl1目录中, bl1的连接脚本是bl1/bl1.ld.s文件,其中可以看到bl1的入口函数是:bl1_entrypoint。
该函数主要需要执行EL3环境的基本初始化,设定向量表,加载bl2 image并跳转到bl2等操作
- func bl1_entrypoint
- /* ---------------------------------------------------------------------
- * If the reset address is programmable then bl1_entrypoint() is
- * executed only on the cold boot path. Therefore, we can skip the warm
- * boot mailbox mechanism.
- * ---------------------------------------------------------------------
- */
- /* EL3级别运行环境的初始化,该函数定义在 include/common/aarch64/el3_common_macros.S文件中
- */
- el3_entrypoint_common \
- _set_endian=1 \
- _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
- _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
- _init_memory=1 \
- _init_c_runtime=1 \
- _exception_vectors=bl1_exceptions
-
- /* ---------------------------------------------
- * Architectural init. can be generic e.g.
- * enabling stack alignment and platform spec-
- * ific e.g. MMU & page table setup as per the
- * platform memory map. Perform the latter here
- * and the former in bl1_main.
- * ---------------------------------------------
- */
- bl bl1_early_platform_setup //调用bl1_early_platform_setup函数完成底层初始化
- bl bl1_plat_arch_setup //调用bl1_plat_arch_setup完成平台初始化
-
- /* --------------------------------------------------
- * Initialize platform and jump to our c-entry point
- * for this type of reset.
- * --------------------------------------------------
- */
- bl bl1_main //调用bl1_main函数,初始化验证模块,加载下一阶段的image到RAM中
-
- /* --------------------------------------------------
- * Do the transition to next boot image.
- * --------------------------------------------------
- */
- b el3_exit //调用el3_exit函数,跳转到下一个image(bl2)
- endfunc bl1_entrypoint
该函数是以宏的形式被定义的,主要完成el3基本设置和向量表注册
- .macro el3_entrypoint_common \
- _set_endian, _warm_boot_mailbox, _secondary_cold_boot, \
- _init_memory, _init_c_runtime, _exception_vectors
- /* 设定大小端 */
- .if \_set_endian
- /* -------------------------------------------------------------
- * Set the CPU endianness before doing anything that might
- * involve memory reads or writes.
- * -------------------------------------------------------------
- */
- mrs x0, sctlr_el3
- bic x0, x0, #SCTLR_EE_BIT
- msr sctlr_el3, x0
- isb
- .endif /* _set_endian */
-
- /* 判定是否需要调用do_cold_boot流程 */
- .if \_warm_boot_mailbox
- /* -------------------------------------------------------------
- * This code will be executed for both warm and cold resets.
- * Now is the time to distinguish between the two.
- * Query the platform entrypoint address and if it is not zero
- * then it means it is a warm boot so jump to this address.
- * -------------------------------------------------------------
- */
- bl plat_get_my_entrypoint
- cbz x0, do_cold_boot
- br x0
-
- do_cold_boot:
- .endif /* _warm_boot_mailbox */
-
- /* ---------------------------------------------------------------------
- * It is a cold boot.
- * Perform any processor specific actions upon reset e.g. cache, TLB
- * invalidations etc.
- * ---------------------------------------------------------------------
- */
- bl reset_handler //执行reset handle操作
-
- /* 初始化异常向量 */
- el3_arch_init_common \_exception_vectors
-
- /* 判定当前CPU是否是主CPU,如果是则做主CPU的初始化 */
- .if \_secondary_cold_boot
- /* -------------------------------------------------------------
- * Check if this is a primary or secondary CPU cold boot.
- * The primary CPU will set up the platform while the
- * secondaries are placed in a platform-specific state until the
- * primary CPU performs the necessary actions to bring them out
- * of that state and allows entry into the OS.
- * -------------------------------------------------------------
- */
- bl plat_is_my_cpu_primary
- cbnz w0, do_primary_cold_boot
-
- /* This is a cold boot on a secondary CPU */
- bl plat_secondary_cold_boot_setup
- /* plat_secondary_cold_boot_setup() is not supposed to return */
- bl el3_panic
-
- do_primary_cold_boot:
- .endif /* _secondary_cold_boot */
-
- /* ---------------------------------------------------------------------
- * Initialize memory now. Secondary CPU initialization won't get to this
- * point.
- * ---------------------------------------------------------------------
- */
- /* 初始化memory */
- .if \_init_memory
- bl platform_mem_init
- .endif /* _init_memory */
-
- /* ---------------------------------------------------------------------
- * Init C runtime environment:
- * - Zero-initialise the NOBITS sections. There are 2 of them:
- * - the .bss section;
- * - the coherent memory section (if any).
- * - Relocate the data section from ROM to RAM, if required.
- * ---------------------------------------------------------------------
- */
- /* 初始化C语言的运行环境 */
- .if \_init_c_runtime
- #ifdef IMAGE_BL31
- /* -------------------------------------------------------------
- * Invalidate the RW memory used by the BL31 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
- #endif /* IMAGE_BL31 */
-
- 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
-
- #ifdef IMAGE_BL1
- ldr x0, =__DATA_RAM_START__
- ldr x1, =__DATA_ROM_START__
- ldr x2, =__DATA_SIZE__
- bl memcpy16
- #endif
- .endif /* _init_c_runtime */
-
- /* ---------------------------------------------------------------------
- * Use SP_EL0 for the C runtime stack.
- * ---------------------------------------------------------------------
- */
- msr spsel, #0
-
- /* ---------------------------------------------------------------------
- * 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 //设定堆栈
-
- #if STACK_PROTECTOR_ENABLED
- .if \_init_c_runtime
- bl update_stack_protector_canary
- .endif /* _init_c_runtime */
- #endif
- .endm
-
- #endif /* __EL3_COMMON_MACROS_S__ */
该函数是需要带参数调用,参数说明如下:
_set_endian:设定大小端
_warm_boot_mailbox:检查当前是属于冷启动还是热启动(power on or reset)
_secondary_cold_boot: 确定当前的CPU是主CPU还是从属CPU
_init_memory:是否需要初始化memory
_init_c_runtime: 是否需要初始化C语言的执行环境
_exception_vectors: 异常向量表地址
该函数用来完成早期的初始化操作,主要包括memory, page table, 所需外围设备的初始化以及相关状态设定等;
- void bl1_early_platform_setup(void)
- {
- /* 使能看门狗,初始化console,初始化memory */
- arm_bl1_early_platform_setup();
-
- /*
- * Initialize Interconnect for this cluster during cold boot.
- * No need for locks as no other CPU is active.
- */
- plat_arm_interconnect_init();//初始化外围设备
- /*
- * Enable Interconnect coherency for the primary CPU's cluster.
- */
- plat_arm_interconnect_enter_coherency();//使能外围设备
- }
该函数完成bl2 image的加载和运行环境的设置,如果开启了trusted boot,则需要对image进行verify操作
- void bl1_main(void)
- {
- unsigned int image_id;
-
- /* Announce our arrival */
- NOTICE(FIRMWARE_WELCOME_STR);
- NOTICE("BL1: %s\n", version_string);
- NOTICE("BL1: %s\n", build_message);
-
- INFO("BL1: RAM %p - %p\n", (void *)BL1_RAM_BASE,
- (void *)BL1_RAM_LIMIT);
-
- print_errata_status();
-
- #if DEBUG
- u_register_t val;
- /*
- * Ensure that MMU/Caches and coherency are turned on
- */
- #ifdef AARCH32
- val = read_sctlr();
- #else
- val = read_sctlr_el3();
- #endif
- assert(val & SCTLR_M_BIT);
- assert(val & SCTLR_C_BIT);
- assert(val & SCTLR_I_BIT);
- /*
- * Check that Cache Writeback Granule (CWG) in CTR_EL0 matches the
- * provided platform value
- */
- val = (read_ctr_el0() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
- /*
- * If CWG is zero, then no CWG information is available but we can
- * at least check the platform value is less than the architectural
- * maximum.
- */
- if (val != 0)
- assert(CACHE_WRITEBACK_GRANULE == SIZE_FROM_LOG2_WORDS(val));
- else
- assert(CACHE_WRITEBACK_GRANULE <= MAX_CACHE_LINE_SIZE);
- #endif
-
- /* Perform remaining generic architectural setup from EL3 */
- bl1_arch_setup(); //设置下一个image的EL级别
-
- #if TRUSTED_BOARD_BOOT
- /* Initialize authentication module */
- auth_mod_init(); //初始化image的验证模块
- #endif /* TRUSTED_BOARD_BOOT */
-
- /* Perform platform setup in BL1. */
- bl1_platform_setup(); //平台相关设置,主要是IO的设置
-
- /* Get the image id of next image to load and run. */
- image_id = bl1_plat_get_next_image_id(); //获取下一个阶段image的ID值。默认返回值为BL2_IMAGE_ID
-
- /*
- * We currently interpret any image id other than
- * BL2_IMAGE_ID as the start of firmware update.
- */
- if (image_id == BL2_IMAGE_ID)
- bl1_load_bl2(); //将bl2 image加载到安全RAM中
- else
- NOTICE("BL1-FWU: *******FWU Process Started*******\n");
-
- bl1_prepare_next_image(image_id); //获取bl2 image的描述信息,包括名字,ID,entry potin info等,并将这些信息保存到bl1_cpu_context的上下文中
- console_flush();
- }
该函数用来获取bl2 image的描述信息,获取bl2的入口地址,这只下个阶段的CPU上下文,以备执行从bl1跳转到bl2的操作使用
- void bl1_prepare_next_image(unsigned int image_id)
- {
- unsigned int security_state;
- image_desc_t *image_desc;
- entry_point_info_t *next_bl_ep;
-
- #if CTX_INCLUDE_AARCH32_REGS
- /*
- * Ensure that the build flag to save AArch32 system registers in CPU
- * context is not set for AArch64-only platforms.
- */
- if (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL1_SHIFT)
- & ID_AA64PFR0_ELX_MASK) == 0x1) {
- ERROR("EL1 supports AArch64-only. Please set build flag "
- "CTX_INCLUDE_AARCH32_REGS = 0");
- panic();
- }
- #endif
-
- /* Get the image descriptor. */
- /* 获取bl2 image的描述信息,主要包括入口地址,名字等信息 */
- image_desc = bl1_plat_get_image_desc(image_id);
- assert(image_desc);
-
- /* Get the entry point info. */
- /* 获取image的入口地址信息 */
- next_bl_ep = &image_desc->ep_info;
-
- /* Get the image security state. */
- /* 获取bl2 image的安全状态(判定该image是属于安全态的image的还是非安全态的image) */
- security_state = GET_SECURITY_STATE(next_bl_ep->h.attr);
-
- /* Setup the Secure/Non-Secure context if not done already. */
- /* 设定用于存放CPU context的变量 */
- if (!cm_get_context(security_state))
- cm_set_context(&bl1_cpu_context[security_state], security_state);
-
- /* Prepare the SPSR for the next BL image. */
- /* 为下个阶段的image准备好SPSR数据 */
- if (security_state == SECURE) {
- next_bl_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
- DISABLE_ALL_EXCEPTIONS);
- } else {
- /* Use EL2 if supported else use EL1. */
- if (read_id_aa64pfr0_el1() &
- (ID_AA64PFR0_ELX_MASK << ID_AA64PFR0_EL2_SHIFT)) {
- next_bl_ep->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
- DISABLE_ALL_EXCEPTIONS);
- } else {
- next_bl_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
- DISABLE_ALL_EXCEPTIONS);
- }
- }
-
- /* Allow platform to make change */
- bl1_plat_set_ep_info(image_id, next_bl_ep);
-
- /* Prepare the context for the next BL image. */
- /* 使用获取到的bl2 image的entrypoint info数据来初始化cpu context */
- cm_init_my_context(next_bl_ep);
- /* 为进入到下个EL级别做准备 */
- cm_prepare_el3_exit(security_state);
-
- /* Indicate that image is in execution state. */
- /* 设定image的执行状态 */
- image_desc->state = IMAGE_STATE_EXECUTED;
-
- /* 打印出bl2 image的入口信息 */
- print_entry_point_info(next_bl_ep);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。