当前位置: 首页 > news >正文

ATF启动(三):BL2

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

相关文章:

  • 论Orchestration和Choreography
  • JUC线程线程池和锁面试题
  • TypeScript 简介
  • css过渡效果
  • mysql中EXPLAIN命令解析
  • 【NodeJs-5天学习】第二天篇④ ——项目模块化
  • LeetCode 110.平衡二叉树 (C++)
  • 基于SpringBoot的校园闲置物品交易管理系统
  • 在线表格 循环替换 脚本
  • 量化投资学习——股指期货研究(二)
  • npm下载包速度慢-淘宝NPM镜像服务器--如何切换其他服务器下载
  • 基于elasticjob的入门maven项目搭建
  • 【校招VIP】产品项目分析之竞品分析
  • 服务端(后端)主动通知前端的实现:WebSocket(springboot中使用WebSocket案例)
  • 计算机毕业设计django基于python教学互动系统(源码+系统+mysql数据库+Lw文档)
  • [ JavaScript ] 数据结构与算法 —— 链表
  • [LeetCode] Wiggle Sort
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 【RocksDB】TransactionDB源码分析
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • CAP 一致性协议及应用解析
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • git 常用命令
  • Git 使用集
  • GitUp, 你不可错过的秀外慧中的git工具
  • MySQL-事务管理(基础)
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • springboot_database项目介绍
  • 初识MongoDB分片
  • 关于使用markdown的方法(引自CSDN教程)
  • 解决iview多表头动态更改列元素发生的错误
  • 判断客户端类型,Android,iOS,PC
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 译米田引理
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 自制字幕遮挡器
  • MPAndroidChart 教程:Y轴 YAxis
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​卜东波研究员:高观点下的少儿计算思维
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (4)(4.6) Triducer
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Python第六天)文件处理
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (算法)求1到1亿间的质数或素数
  • (转)winform之ListView
  • (转载)CentOS查看系统信息|CentOS查看命令
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .Net MVC4 上传大文件,并保存表单
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .net的socket示例
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .NET设计模式(2):单件模式(Singleton Pattern)