ARM64 Trust Firmware [四]

news/2025/2/21 9:54:45

完成第二阶段 BL2 的操作后就加载并进入 BL31,BL31 位于 DRAM 中,EL3 模式。除了做架构初始化和平台初始化外,还做了如下工作:

  • 基本硬件初始化,比如 GIC,串口,timer 等;
  • PSCI 服务的初始化,后续提供 CPU 功耗管理操作;
  • BL32 镜像运行初始化,处于 Secure EL1 模式;
  • 初始化非安全 EL2 或 EL1,跳转到 BL33 执行;
  • 负责安全非安全世界切换;
  • 进行安全服务请求的分发;

通过 bl31.ld.S 文件,我们知道 bl31 的入口函数为bl31_entrypoint:

#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>

OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl31_entrypoint)

bl31_entrypoint:

func bl31_entrypoint
	/* ---------------------------------------------------------------
	 * Stash the previous bootloader arguments x0 - x3 for later use.
	 * ---------------------------------------------------------------
	 */
	mov	x20, x0
	mov	x21, x1
	mov	x22, x2
	mov	x23, x3

#if !RESET_TO_BL31
	/* ---------------------------------------------------------------------
	 * For !RESET_TO_BL31 systems, only the primary CPU ever reaches
	 * bl31_entrypoint() during the cold boot flow, so the cold/warm boot
	 * and primary/secondary CPU logic should not be executed in this case.
	 *
	 * Also, assume that the previous bootloader has already initialised the
	 * SCTLR_EL3, including the endianness, and has initialised the memory.
	 * ---------------------------------------------------------------------
	 */
	el3_entrypoint_common					\
		_init_sctlr=0					\
		_warm_boot_mailbox=0				\
		_secondary_cold_boot=0				\
		_init_memory=0					\
		_init_c_runtime=1				\
		_exception_vectors=runtime_exceptions		\
		_pie_fixup_size=BL31_LIMIT - BL31_BASE
#else

	/* ---------------------------------------------------------------------
	 * For RESET_TO_BL31 systems which have a programmable reset address,
	 * bl31_entrypoint() is executed only on the cold boot path so we can
	 * skip the warm boot mailbox mechanism.
	 * ---------------------------------------------------------------------
	 */
	el3_entrypoint_common					\
		_init_sctlr=1					\
		_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS	\
		_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU	\
		_init_memory=1					\
		_init_c_runtime=1				\
		_exception_vectors=runtime_exceptions		\
		_pie_fixup_size=BL31_LIMIT - BL31_BASE
#endif /* RESET_TO_BL31 */

	/* --------------------------------------------------------------------
	 * Perform BL31 setup
	 * --------------------------------------------------------------------
	 */
	mov	x0, x20
	mov	x1, x21
	mov	x2, x22
	mov	x3, x23
	bl	bl31_setup

	/* --------------------------------------------------------------------
	 * Jump to main function
	 * --------------------------------------------------------------------
	 */
	bl	bl31_main

	/* --------------------------------------------------------------------
	 * Clean the .data & .bss sections to main memory. This ensures
	 * that any global data which was initialised by the primary CPU
	 * is visible to secondary CPUs before they enable their data
	 * caches and participate in coherency.
	 * --------------------------------------------------------------------
	 */
	adrp	x0, __DATA_START__
	add	x0, x0, :lo12:__DATA_START__
	adrp	x1, __DATA_END__
	add	x1, x1, :lo12:__DATA_END__
	sub	x1, x1, x0
	bl	clean_dcache_range

	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	clean_dcache_range

	b	el3_exit
endfunc bl31_entrypoint

根据是否设置了 RESET_TO_BL31,bl31_entrypoint 函数有两种不同的启动方式:

  • ATF 的启动从 BL1 开始,由于 BL1 已经执行过了el3_entrypoint_common,所以在 BL31 中就跳过;
  • ARMv8 架构提供了 RVBAR(reset vector base address register),该寄存器用于设置 reset 时 cpu 的启动位置。由于 BL31 运行在 EL3 下,我们通过设置 RVBAR_EL3 寄存器就可以支持 CPU 从 BL31 开始,由于在上述情况下,BL31 是第一级启动镜像,因此el3_entrypoint_common 需要从头设置系统状态;

bl31_setup:

void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
		u_register_t arg3)
{
	/* Enable early console if EARLY_CONSOLE flag is enabled */
	plat_setup_early_console();
	/* Perform early platform-specific setup */
	bl31_early_platform_setup2(arg0, arg1, arg2, arg3);
	/* Perform late platform-specific setup */
	bl31_plat_arch_setup();
	/* Prints context_memory allocated for all the security states */
	report_ctx_memory_usage();
}
  • plat_setup_early_console:平台串口初始化;
  • bl31_early_platform_setup2:主要做的事情就是解析 BL2 传入的镜像描述符链表参数,并将解析到的 BL32 和 BL33 镜像 ep_info 保存到全局变量中。
  • bl31_plat_arch_setup:为 BL31 相关内存创建页表,使能 MMU 和 dcache;

bl31_main:

void bl31_main(void)
{
	/* Init registers that never change for the lifetime of TF-A */
	cm_manage_extensions_el3();

	/* Init per-world context registers for non-secure world */
	manage_extensions_nonsecure_per_world();

	NOTICE("BL31: %s\n", build_version_string);
	NOTICE("BL31: %s\n", build_message);

	/* Perform platform setup in BL31 */
	bl31_platform_setup();

	/* Initialise helper libraries */
	bl31_lib_init();

	/* Initialize the runtime services e.g. psci. */
	INFO("BL31: Initializing runtime services\n");
	runtime_svc_init();

	if (bl32_init != NULL) {
		INFO("BL31: Initializing BL32\n");

		console_flush();
		int32_t rc = (*bl32_init)();

		if (rc == 0) {
			WARN("BL31: BL32 initialization failed\n");
		}
	}

	bl31_prepare_next_image_entry();
	bl31_plat_runtime_setup();

	console_flush();
	console_switch_state(CONSOLE_FLAG_RUNTIME);
}
  • bl31_platform_setup:平台相关的初始化,比如初始化 gic,包括 gic 的 distributor,redistributor,cpu interface 等的初始化,初始化系统通用定时器,初始化电源控制器等;
  • runtime_svc_init:运行时服务的初始化(后面单独章节展开);
  • 启动 BL32;
  • 启动 BL32 返回后启动 BL33;

runtime_svc_init:

void __init runtime_svc_init(void)
{
	int rc = 0;
	uint8_t index, start_idx, end_idx;
	rt_svc_desc_t *rt_svc_descs;

	/* Assert the number of descriptors detected are less than maximum indices */
	assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
			(RT_SVC_DECS_NUM < MAX_RT_SVCS));

	/* If no runtime services are implemented then simply bail out */
	if (RT_SVC_DECS_NUM == 0U)
		return;

	/* Initialise internal variables to invalid state */
	(void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));

	rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
	for (index = 0U; index < RT_SVC_DECS_NUM; index++) {
		rt_svc_desc_t *service = &rt_svc_descs[index];

		/*
		 * An invalid descriptor is an error condition since it is
		 * difficult to predict the system behaviour in the absence
		 * of this service.
		 */
		rc = validate_rt_svc_desc(service);
		if (rc != 0) {
			ERROR("Invalid runtime service descriptor %p\n",
				(void *) service);
			panic();
		}

		/*
		 * The runtime service may have separate rt_svc_desc_t
		 * for its fast smc and yielding smc. Since the service itself
		 * need to be initialized only once, only one of them will have
		 * an initialisation routine defined. Call the initialisation
		 * routine for this runtime service, if it is defined.
		 */
		if (service->init != NULL) {
			rc = service->init();
			if (rc != 0) {
				ERROR("Error initializing runtime service %s\n",
						service->name);
				continue;
			}
		}

		/*
		 * Fill the indices corresponding to the start and end
		 * owning entity numbers with the index of the
		 * descriptor which will handle the SMCs for this owning
		 * entity range.
		 */
		start_idx = (uint8_t)get_unique_oen(service->start_oen,
						    service->call_type);
		end_idx = (uint8_t)get_unique_oen(service->end_oen,
						  service->call_type);
		assert(start_idx <= end_idx);
		assert(end_idx < MAX_RT_SVCS);
		for (; start_idx <= end_idx; start_idx++)
			rt_svc_descs_indices[start_idx] = index;
	}
}

运行时服务通过DECLARE_RT_SVC 注册:

#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)	\
	static const rt_svc_desc_t __svc_desc_ ## _name			\
		__section(".rt_svc_descs") __used = {			\
			.start_oen = (_start),				\
			.end_oen = (_end),				\
			.call_type = (_type),				\
			.name = #_name,					\
			.init = (_setup),				\
			.handle = (_smch)				\
		}

最终这些被注册的服务结构体都被保存到以__RT_SVC_DESCS_START__ 开头,__RT_SVC_DESCS_END__ 结尾的 rt_svc_descs 段中,具体后面单独章节再分析。

因此运行服务初始化时通过遍历以 RT_SVC_DESCS_START 开始的所有服务的结构体,然后调用其初始化函数就可以。

bl32_init:

BL32 就是 TEE OS 了,在 BL31 中启动 BL32 运行流程如下:

if (bl32_init != NULL) {
    INFO("BL31: Initializing BL32\n");

    console_flush();
    int32_t rc = (*bl32_init)();

    if (rc == 0) {
        WARN("BL31: BL32 initialization failed\n");
    }
}

这里的bl32_init 就是 opteed_init,是在 opteed_setup 中通过 bl31_register_bl32_init 来注册赋值给 bl32_init 的。

static int32_t opteed_setup(void)
{
    ...
	bl31_register_bl32_init(&opteed_init);
}

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

opteed_init 的启动流程如下:

static int32_t opteed_init(void)
{
	entry_point_info_t *optee_entry_point;
	/*
	 * Get information about the OP-TEE (BL32) image. Its
	 * absence is a critical failure.
	 */
	optee_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
	return opteed_init_with_entry_point(optee_entry_point);
}

static int32_t
opteed_init_with_entry_point(entry_point_info_t *optee_entry_point)
{
    cm_init_my_context(optee_entry_point);
	rc = opteed_synchronous_sp_entry(optee_ctx);
}

uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx)
{
    ...
	rc = opteed_enter_sp(&optee_ctx->c_rt_ctx);
	return rc;
}
  • 通过bl31_plat_get_next_image_ep_info 获取保存的 TEE OS 镜像的 ep 信息;
  • 初始化异常等级切换的上下文,设置 SPSR_EL3 和 ELR_EL3 寄存器等;
  • 调用 opteed_enter_sp 跳转到 BL32;

BL32 返回 BL31:

在 opteed_enter_sp 中我们将跳转前的 lr 寄存器值以及其他上下文保存到 opteed 的 ctx 中,当 opteed 初始化完成后调用 smc 进入 bl31,然后我们在 smc 的处理流程中恢复这些上下文就能够恢复到之前的断点处继续执行了。

跳转到 BL32 前保存上下文:

func opteed_enter_sp
	/* Make space for the registers that we're going to save */
	mov	x3, sp
	str	x3, [x0, #0]
	sub	sp, sp, #OPTEED_C_RT_CTX_SIZE

	stp	x19, x20, [sp, #OPTEED_C_RT_CTX_X19]
	stp	x21, x22, [sp, #OPTEED_C_RT_CTX_X21]
	stp	x23, x24, [sp, #OPTEED_C_RT_CTX_X23]
	stp	x25, x26, [sp, #OPTEED_C_RT_CTX_X25]
	stp	x27, x28, [sp, #OPTEED_C_RT_CTX_X27]
	stp	x29, x30, [sp, #OPTEED_C_RT_CTX_X29]

	b	el3_exit

返回 BL31 后恢复上下文:

func opteed_exit_sp
	/* Restore the previous stack */
	mov	sp, x0

	/* Restore callee-saved registers on to the stack */
	ldp	x19, x20, [x0, #(OPTEED_C_RT_CTX_X19 - OPTEED_C_RT_CTX_SIZE)]
	ldp	x21, x22, [x0, #(OPTEED_C_RT_CTX_X21 - OPTEED_C_RT_CTX_SIZE)]
	ldp	x23, x24, [x0, #(OPTEED_C_RT_CTX_X23 - OPTEED_C_RT_CTX_SIZE)]
	ldp	x25, x26, [x0, #(OPTEED_C_RT_CTX_X25 - OPTEED_C_RT_CTX_SIZE)]
	ldp	x27, x28, [x0, #(OPTEED_C_RT_CTX_X27 - OPTEED_C_RT_CTX_SIZE)]
	ldp	x29, x30, [x0, #(OPTEED_C_RT_CTX_X29 - OPTEED_C_RT_CTX_SIZE)]

	mov	x0, x1
	ret
endfunc opteed_exit_sp

启动 BL33:

OP_TEE 初始化完成后,继续返回 bl31_main 的断点处,然后跳转到 BL33 运行:

	/*
	 * We are ready to enter the next EL. Prepare entry into the image
	 * corresponding to the desired security state after the next ERET.
	 */
	bl31_prepare_next_image_entry();

	/*
	 * Perform any platform specific runtime setup prior to cold boot exit
	 * from BL31
	 */
	bl31_plat_runtime_setup();

到此,BL1 、BL2、BL31 ,BL32,BL33 的启动视图如下:


http://www.niftyadmin.cn/n/5860647.html

相关文章

js中常用方法整理

数据类型 typeOf()Number&#xff08;&#xff09;parseInt()parseFloat()- * / %检测数据类型转换为数字转换为整数类型转换为浮点类型非加法的数字运算toString()Boolean()String()转换为字符串&#xff0c;不能转换undefined/null字符串拼接转换为布尔类型转换为字符串、所有…

OpenCV二值化处理

1.1. 为什么需要二值化操作 二值化操作将灰度图像转换为黑白图像&#xff0c;即将图像中的像素值分为两类&#xff1a;前景&#xff08;通常为白色&#xff0c;值为 255&#xff09;和背景&#xff08;通常为黑色&#xff0c;值为 0&#xff09;。二值化的主要目的是简化图像&…

lab4 CSAPP:Cachelab

写在前面 最简单的一集 实验室分为两个部分。在A部分中&#xff0c;实现一个缓存模拟器。在B部分中&#xff0c;编写一个矩阵针对高速缓存性能优化的转置功能。 感觉是比较经典的问题&#xff0c;之前在体系结构的课程中接触过&#xff0c;终于能通过lab实操一下了。 实验目…

tomcat中如何配置,可以支持域名访问

tomcat中如何配置,可以支持域名访问 在Tomcat中配置以支持域名访问&#xff0c;主要涉及到两个方面&#xff1a;配置Tomcat的server.xml文件和在Tomcat的conf目录下的Catalina目录中为每个域名或上下文配置context.xml文件。下面将详细介绍如何进行这些配置。 修改server.xml…

基于契约理论的竞争性组织数据共享安全激励机制matlab模拟与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 参考论文《A Secure Incentive Mechanism for Competitive Organization Data Sharing: A Contract Theoretic Approach》。信息技术发展使数据驱动的智能服务兴起…

【MySQL】索引和视图

索引 索引定义 索引是在数据库表的字段上添加的&#xff0c;是为了提高查询效率存在的一种机制。一个字段可以添加一个索引&#xff0c;多个字段联合起来也可以添加索引。MySQL查询主要为两种方式&#xff1a;索引检索和全表扫描。如果条件中包含某个字段&#xff0c;而该字段…

android调用ffmpeg解析rtsp协议的视频流

文章目录 一、背景二、解析rtsp数据1、C层功能代码2、jni层的定义3、app层的调用 三、源码下载 一、背景 本demo主要介绍android调用ffmpeg中的接口解析rtsp协议的视频流&#xff08;不解析音频&#xff09;&#xff0c;得到yuv数据&#xff0c;把yuv转bitmap在android设备上显…

DeepSeek智能测试助手:分类+推理+导出一站式工具

前言 测试开发工程师在日常工作中需要处理大量测试文档&#xff0c;并且这些文档需要被高效分类、清洗和管理&#xff0c;同时结合强大的 AI 推理能力&#xff08;如 DeepSeek 模型&#xff09;进行智能化处理和分析。为此&#xff0c;我们开发了一款基于 PyQt5 的 GUI 工具&a…