ATF启动(三):BL2

发布于:2023-01-03 ⋅ 阅读:(380) ⋅ 点赞:(0)

ATF启动(三):BL2

在这里插入图片描述

在这里插入图片描述
前面BL1跳转到了BL2

BL2位于SRAM中,运行在Secure EL1主要工作有:

  • 架构初始化:EL1/EL0使能浮点单元和ASMID。
  • 平台初始化:控制台初始化、相关存储设备初始化、MMU、相关设备安全配置、
  • SCP_BL2:系统控制核镜像加载,单独核处理系统功耗、时钟、复位等控制。
  • 加载BL31镜像:BL2将控制权交给BL1;BL1关闭MMU并关cache;BL1将控制权交给BL31。
  • 加载BL32镜像:BL32运行在安全世界,BL2依赖BL31将控制权交给BL32。SPSR通过Secure-EL1 Payload Dispatcher进行初始化。
  • 加载BL33镜像:BL2依赖BL31将控制权交给BL33。

BL2 image将会为后续image的加载执行相关的初始化操作。

主要是内存,MMU,串口以及EL3软件运行环境的设置,并且加载bl3x的image到RAM中。

BL2的主要工作就是加载BL3x系列镜像,然后通过SMC进入BL1进而跳转到BL31运行。

bl2_entrypoint()是BL2的入口:

  • 前半部分主要进行一系列初始化工作,
  • 然后通过bl2_main()加载BL3x镜像到RAM中,
  • 最后通过SMC调用执行BL1中指定的smc handler将CPU执行权交给BL31。

通过查看bl2.ld.S文件就可以发现,bl2 image的入口函数是bl2_entrypoint。该函数定义在bl2/aarch64/bl2_entrypoint.S文件中。

1、bl2_entrypoint()是BL2的入口初始化+通过bl2_main加载BL3x镜像,bl1中将CPU的控制权转交给bl31:bl2_entrypoint—>

2、bl2_main()主要实现将bl3x的image加载RAM中,并通过smc调用执行bl1中指定的smc handle将CPU的执行权交给bl31。:bl2_main—>

3、bl2_load_images是bl2_main中具体实现加载bl3x的image到RAM中,返回一个具有image入口信息的变量。smc handle根据该变量跳转到bl31进行执行:bl2_load_images—>

4、bl2_mem_params_descs该宏的执行将会初始化组成bl2加载bl3x image的列表使用到的重要全局变量:—>REGISTER_BL_IMAGE_DESCS

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----------------------------------配置cache、内存对齐等属性。
    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-------------------------------将BL2的__RW_START__和__RW_END__之间的内存刷回DDR中。

    /* ---------------------------------------------
     * 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    zeromem16--------------------------------------初始化__BSS_START__开始,大小为__BSS_SIZE__内存为0。

#if USE_COHERENT_MEM
    ldr    x0, =__COHERENT_RAM_START__
    ldr    x1, =__COHERENT_RAM_UNALIGNED_SIZE__
    bl    zeromem16
#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

    /* ---------------------------------------------
     * 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主函数执行,该函数加载BL3x镜像,并通过SMC调用BL1指定SMC函数将CPU执行权交给BL31。

    /* ---------------------------------------------
     * Should never reach this point.
     * ---------------------------------------------
     */
    no_ret    plat_panic_handler

endfunc bl2_entrypoint

2.bl2_main()


bl2_main()主要加载BL3x镜像并验证,然后获取下一个要运行的镜像信息,通过SMC调用让BL1去启动。

该函数主要实现将bl3x的image加载RAM中,并通过smc调用执行bl1中指定的smc handle将CPU的使用权交给bl31。

/*******************************************************************************
 * The only thing to do in BL2 is to load further images and pass control to
 * next BL. The memory occupied by BL2 will be reclaimed by BL3x stages. BL2
 * runs entirely in S-EL1.
 ******************************************************************************/
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();
#endif /* TRUSTED_BOARD_BOOT */

    /* Load the subsequent bootloader images. */
    next_bl_ep_info = bl2_load_images();

#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 */

    /*
     * 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_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0);----------发起SMC异常启动BL31镜像,交给BL1 bl1_aarch32_smc_handler处理。
}

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;
}

3.REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)

bl2_mem_params_descs定义了BL2需要加载镜像的信息,通过REGISTER_BL_IMAGE_DESCS()将其和bl_mem_params_desc_ptr关联,并获取需要加载镜像数目bl_mem_params_desc_num。

该宏的执行将会初始化组成bl2加载bl3x image的列表使用到的重要全局变量,其中bl2_mem_params_descs变量的定义如下:

在该变量中规定了SCP_BL2, EL3_payload, bl32, bl33 image的相关信息,例如:

 

image的入口地址信息:ep_info

image在RAM中的基地址:image_base

image的基本信息:image_info

image的ID值:image_id

**bl2_mem_params_descs定义了BL2需要加载镜像的信息,**通过REGISTER_BL_IMAGE_DESCS()将其和bl_mem_params_desc_ptr关联,并获取需要加载镜像数目bl_mem_params_desc_num。

#define REGISTER_BL_IMAGE_DESCS(_img_desc)                \
    bl_mem_params_node_t *bl_mem_params_desc_ptr = &_img_desc[0];    \
    unsigned int bl_mem_params_desc_num = ARRAY_SIZE(_img_desc);

static bl_mem_params_node_t bl2_mem_params_descs[] = {
...
#ifdef EL3_PAYLOAD_BASE
...
#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 */
};

REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)


/*******************************************************************************
 * This function loads SCP_BL2/BL3x images and returns the ep_info for
 * the next executable image.
 ******************************************************************************/
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.
     */
    bl2_load_info = plat_get_bl_image_load_info();-----------------获取待加载镜像BL3x或SCP_EL2信息,然后遍历处理。
    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_node_info = bl2_load_info->head;---------------------------bl2_node_info指向镜像第一个对象。

    while (bl2_node_info) {----------------------------------------循环遍历bl2_mem_params_descs成员并加载处理。
        /*
         * Perform platform setup before loading the image,
         * if indicated in the image attributes AND if NOT
         * already done before.
         */
        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;
            }
        }

        if (!(bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) {----确定是否需要跳过加载到RAM步骤;如否,则进行验证并加载。
            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);----------------------------------------将镜像加载到RAM,然后进行验证。
            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. */
        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.
     */
    bl2_to_next_bl_params = plat_get_next_bl_params();------------------------------获取下一个执行镜像入口信息,属性为EXECUTABLE和EP_FIRST_EXE,也即BL31。
    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();----------------------------------------------------将bl_mem_params_desc_ptr数据刷到DDR中,后面即将通过SMC跳转到BL1启动BL31,保持数据一致性。

    return bl2_to_next_bl_params->head->ep_info;
}

参考资料:
https://www.cnblogs.com/arnoldlu/p/14175126.html#REGISTER_BL_IMAGE_DESCS
https://icyshuai.blog.csdn.net/article/details/72470044

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到