optee bl32 启动分析

bl31 引导部分

bl32 遵循 ATF启动框架, 自然而然,bl32 由bl31 启动, bl31 会 初始化bl32 img运行地址, 将pc指针指向改地址后, 初始化bl32 运行环境, 然后重新返回bl31

详细代码如下:services/spd/opteed/opteed_main.c

/*******************************************************************************
 * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type
 * (aarch32/aarch64) if not already known and initialises the context for entry
 * into OPTEE for its initialization.
 ******************************************************************************/
static int32_t opteed_setup(void)
{
        entry_point_info_t *optee_ep_info;
        uint32_t linear_id;
        uint64_t opteed_pageable_part;
        uint64_t opteed_mem_limit;
        uint64_t dt_addr;
        linear_id = plat_my_core_pos();

        /*
         * Get information about the Secure Payload (BL32) image. Its
         * absence is a critical failure.  TODO: Add support to
         * conditionally include the SPD service
         */
        optee_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
        if (!optee_ep_info) {
                WARN("No OPTEE provided by BL2 boot loader, Booting device"
                        " without OPTEE initialization. SMC`s destined for OPTEE"
                        " will return SMC_UNK\n");
                return 1;
        }

        /*
         * If there's no valid entry point for SP, we return a non-zero value
         * signalling failure initializing the service. We bail out without
         * registering any handlers
         */
        if (!optee_ep_info->pc)
                return 1;

		#ifdef CONFIG_OPTEE_AARCH64
		        opteed_rw = OPTEE_AARCH64;
		#else
		        opteed_rw = optee_ep_info->args.arg0;
		#endif
        opteed_pageable_part = optee_ep_info->args.arg1;
        opteed_mem_limit = optee_ep_info->args.arg2;
        dt_addr = optee_ep_info->args.arg3;

        opteed_init_optee_ep_state(optee_ep_info,
                                opteed_rw,
                                optee_ep_info->pc,
                                opteed_pageable_part,
                                opteed_mem_limit,
                                dt_addr,
                                &opteed_sp_context[linear_id]);
		/*
         * All OPTEED initialization done. Now register our init function with
         * BL31 for deferred invocation
         */
        bl31_register_bl32_init(&opteed_init);

		return  0;
}

在这里我只说明重要关键的部分, 注意看bl31_register_bl32_init(&opteed_init) 该函数注册了bl32 的启动函数地址指针,用于后续执行opteed_init
接下来看 该函数是如何实现的

void bl31_register_bl32_init(int32_t (*func)(void))
{
        bl32_init = func;
}

注意看,这里bl32_init 函数被赋值, 那么后续调用类似 (*bl32_init)()这样的形式

请看 bl31/bl31_main.c bl31_main 函数, 这里我截取了关键部分

void bl31_main(void)
{
	if (bl32_init != NULL)
	 {
		INFO("BL31: Initializing BL32\n");	
		int32_t rc = (*bl32_init)();
			
		if (rc == 0) {
			WARN("BL31: BL32 initialization failed\n");
		}
	  }
}

看到没有 bl31 的初始化过程会 进一步初始化bl32 , 不要以为bl31 和32 是两个不相干的img,其实他们密不可分,在启动后,依然bl31 和bl32 之间通过SMCCALL 形式 传递数据。


bl32 启动部分

下面介绍bl32 在调用 (*bl32_init)() 之后, 究竟干了哪些事情。

core/arch/arm/kernel/generic_entry_a64.S 文件是整个bl32 init的入口文件,
FUNC _start , 函数是第一个执行的汇编函数

FUNC _start , :

    mov x19, x0     /* Save pagable part address */
    mov x20, x2     /* Save DT address */
    adr x0, reset_vect_table
    msr vbar_el1, x0
    isb
 
    set_sctlr_el1
    isb
 
    /*
     * The binary is built as:
     * [Core, rodata and data] : In correct location
     * [struct boot_embdata + data] : Should be moved to __end, first
     * uint32_t tells the length of the struct + data
     */
    adr_l   x0, __end       /* dst */
    adr_l   x1, __data_end      /* src */
    ldr w2, [x1]        /* struct boot_embdata::total_len */
    /* Copy backwards (as memmove) in case we're overlapping */
    add x0, x0, x2
    add x1, x1, x2
    adr x3, cached_mem_end
    str x0, [x3]
    adr_l   x2, __end
 
copy_init:
    ldp x3, x4, [x1, #-16]!
    stp x3, x4, [x0, #-16]!
    cmp x0, x2
    b.gt    copy_init
 
    /*
     * Clear .bss, this code obviously depends on the linker keeping
     * start/end of .bss at least 8 byte aligned.
     */
    adr_l   x0, __bss_start
    adr_l   x1, __bss_end
clear_bss:
    str xzr, [x0], #8
    cmp x0, x1
    b.lt    clear_bss
 
 
    /* Setup SP_EL0 and SP_EL1, SP will be set to SP_EL0 */
    set_sp
 
    bl  thread_init_thread_core_local
 
    /* Enable aborts now that we can receive exceptions */
    msr daifclr, #DAIFBIT_ABT
 
    /*
     * Invalidate dcache for all memory used during initialization to
     * avoid nasty surprices when the cache is turned on. We must not
     * invalidate memory not used by OP-TEE since we may invalidate
     * entries used by for instance ARM Trusted Firmware.
     */
    adr_l   x0, __text_start
    ldr x1, cached_mem_end
    sub x1, x1, x0
    bl  dcache_cleaninv_range
 
    /* Enable Console */
    bl  console_init
    mov x0, #0

 
    adr x1, boot_mmu_config
    bl  core_init_mmu_map
    bl  __get_core_pos
    bl  enable_mmu
    mov x0, x19     /* pagable part address */
    mov x1, #-1
    bl  boot_init_primary_early
 
 
    mov x0, x20     /* DT address */
    bl  boot_init_primary_late
    /*
     * In case we've touched memory that secondary CPUs will use before
     * they have turned on their D-cache, clean and invalidate the
     * D-cache before exiting to normal world.
     */
    adr_l   x0, __text_start
    ldr x1, cached_mem_end
    sub x1, x1, x0
    bl  dcache_cleaninv_range
    /*
     * Pass the vector address returned from main_init
     * Compensate for the load offset since cpu_on_handler() is
     * called with MMU off.
     */
    ldr x0, boot_mmu_config + CORE_MMU_CONFIG_LOAD_OFFSET
    adr x1, thread_vector_table
    sub x1, x1, x0
    mov x0, #TEESMC_OPTEED_RETURN_ENTRY_DONE
    smc #0
    /* SMC should not return */
    panic_at_smc_return
 
END_FUNC _start
DECLARE_KEEP_INIT _start

这里我删除了大量 汇编code, 仅仅提取出来几个重要的关键执行步骤

大概做了如下操作

  • 清除bss段
  • console_init 初始化串口
  • core_init_mmu_map 配置mmu 页表
  • enable_mmu 使能mmu 映射
  • boot_init_primary_early 初始化硬件
  • boot_init_primary_late 调用一些initcall 函数
  • thread_vector_table 初始化向量表
  • smc #0 返回bl31

由此可以明白,bl32 并不是bl31运行完之后,才去调用的,而是 由bl31 发起,初始化好bl32 的环境之后, 重新调用smc 指令回到bl31,继续bl31的后续的流程。

所以bl32 的环境都是在这次 bl32_init 函数一次性初始化完毕 。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值