安全引导功能及ATF的启动过程(五)
ATF中bl32的启动
bl31中的runtime_svc_init函数会初始化OP-TEE对应的服务,通过调用该服务项的初始化函数来完成OP-TEE的启动。对于OP-TEE的服务项会通过DECLARE_RT_SVC宏在编译时被存放到rt_svc_des段中。该段中的init成员会被初始化成opteed_setup函数,由此开始进入到OP-TEE OS的启动。整个流程如图所示。
DECLARE_RT_SVC
DECLARE_RT_SVC分为两种类型:
/* Define an OPTEED runtime service descriptor for fast SMC calls */
//对于快速的SMCs中断,OP-TEE操作系统将在入口堆栈上执行,
// 期间屏蔽IRQ/FIQ中断,直至执行返回到正常世界。
DECLARE_RT_SVC(
opteed_fast,
OEN_TOS_START,
OEN_TOS_END,
SMC_TYPE_FAST,
opteed_setup,
opteed_smc_handler
);
/* Define an OPTEED runtime service descriptor for yielding SMC calls */
//对于让步型SMCs中断,OPTEE OS将会在
// 某个时刻解除对中断的屏蔽,执行所请求的服务。
DECLARE_RT_SVC(
opteed_std,
OEN_TOS_START,
OEN_TOS_END,
SMC_TYPE_YIELD,
NULL,
opteed_smc_handler
);
opteed_setup函数
该函数是ATF启动OP-TEE的入口函数,该函数会查找到OP-TEE镜像的信息、检查OP-TEE的入口函数指针是否有效、设置OP-TEE运行的上下文,然后调用OP-TEE的入口函数,开始执行OP-TEE的启动。该函数的内容如下:
/root/optee/trusted-firmware-a/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)
{
//延迟加载模式
#if OPTEE_ALLOW_SMC_LOAD
opteed_allow_load = true;
INFO("Delaying OP-TEE setup until we receive an SMC call to load it\n");
/*
* We must register the interrupt handler now so that the interrupt
* priorities are not changed after starting the linux kernel.
*/
//预先注册中断处理程序,确保在 Linux 内核启动后,
// 中断优先级不会被改变。
register_opteed_interrupt_handler();
return 0;
#else
entry_point_info_t *optee_ep_info;
uint32_t linear_id;
uint64_t arg0;
uint64_t arg1;
uint64_t arg2;
uint64_t arg3;
struct transfer_list_header *tl = NULL;
struct transfer_list_entry *te = NULL;
void *dt = NULL;
linear_id = plat_my_core_pos(); //获取当前核心的线性ID
/*
* Get information about the Secure Payload (BL32) image. Its
* absence is a critical failure. TODO: Add support to
* conditionally include the SPD service
*/
//SECURE:获取 BL32(即 OP-TEE)的入口信息。
// NON_SECURE: 获取 BL33(即 REE)的入口信息。
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
*/
//检查入口地址有效
//pc 是程序计数器(Program Counter),即 OP-TEE 的入口地址。
if (!optee_ep_info->pc)
return 1;
//optee_ep_info结构体定义在下方
tl = (void *)optee_ep_info->args.arg3;
// 解析 Transfer List(可选参数传递机制)
// Transfer List:一种链式结构,允许 BL2 向
// BL31 传递任意类型的数据(FDT、内存表、版本信息等)。
if (TRANSFER_LIST && transfer_list_check_header(tl)) {
//查找 FDT 条目, Flattened Device Tree(FDT)
te = transfer_list_find(tl, TL_TAG_FDT);
//提取设备树指针
dt = transfer_list_entry_data(te);
//获取 OP-TEE 的执行状态(AArch32 或 AArch64)
opteed_rw = GET_RW(optee_ep_info->spsr);
if (opteed_rw == OPTEE_AARCH64) {
if (optee_ep_info->args.arg1 !=
TRANSFER_LIST_HANDOFF_X1_VALUE(
REGISTER_CONVENTION_VERSION))
return 1;
//64位下为arg0赋值
arg0 = (uint64_t)dt;
arg2 = 0;
} else {
if (optee_ep_info->args.arg1 !=
TRANSFER_LIST_HANDOFF_R1_VALUE(
REGISTER_CONVENTION_VERSION))
return 1;
//32位下为arg1赋值
arg0 = 0;
arg2 = (uint64_t)dt;
}
//统一设置其余参数
arg1 = optee_ep_info->args.arg1;
arg3 = optee_ep_info->args.arg3;
} else {
/* Default handoff arguments */
opteed_rw = optee_ep_info->args.arg0;
arg0 = optee_ep_info->args.arg1; /* opteed_pageable_part */
arg1 = optee_ep_info->args.arg2; /* opteed_mem_limit */
arg2 = optee_ep_info->args.arg3; /* dt_addr */
arg3 = 0;
}
// 初始化 OP-TEE 执行上下文
opteed_init_optee_ep_state(optee_ep_info, opteed_rw, optee_ep_info->pc,
arg0, arg1, arg2, arg3,
&opteed_sp_context[linear_id]);
/*
* All OPTEED initialization done. Now register our init function with
* BL31 for deferred invocation
*/
//所有 OPTEED 初始化已完成。
// 现在将我们的初始化函数注册到 BL31,以便延迟调用。
bl31_register_bl32_init(&opteed_init);
return 0;
#endif /* OPTEE_ALLOW_SMC_LOAD */
}
entry_point_info_t结构体
定义如下:
/root/optee/trusted-firmware-a/include/export/common/ep_info_exp.h
typedef struct aapcs64_params {
uint64_t arg0;
uint64_t arg1;
uint64_t arg2;
uint64_t arg3;
uint64_t arg4;
uint64_t arg5;
uint64_t arg6;
uint64_t arg7;
} aapcs64_params_t;
typedef struct aapcs32_params {
uint32_t arg0;
uint32_t arg1;
uint32_t arg2;
uint32_t arg3;
} aapcs32_params_t;
/*****************************************************************************
* This structure represents the superset of information needed while
* switching exception levels. The only two mechanisms to do so are
* ERET & SMC. Security state is indicated using bit zero of header
* attribute
* NOTE: BL1 expects entrypoint followed by spsr at an offset from the start
* of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while
* processing SMC to jump to BL31.
*****************************************************************************/
typedef struct entry_point_info {
param_header_t h;
uintptr_t pc;
uint32_t spsr;
#ifdef __aarch64__
aapcs64_params_t args;
#else
uintptr_t lr_svc;
aapcs32_params_t args;
#endif
} entry_point_info_t;
opteed_init函数
该函数的地址会被赋值给bl32_init变量,在bl31_main函数中会被调用,主要用来完成启动OP-TEE的设置。该函数内容如下:
/root/optee/trusted-firmware-a/services/spd/opteed/opteed_main.c
#if !OPTEE_ALLOW_SMC_LOAD
//只有当 OPTEE_ALLOW_SMC_LOAD 未定义 时,这段代码才被编译进去。
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.
*/
//SECURE:获取 BL32(即 OP-TEE)的入口信息。
optee_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
//完成 上下文恢复 + 跳转到 OP-TEE
return opteed_init_with_entry_point(optee_entry_point);
}
#endif /* !OPTEE_ALLOW_SMC_LOAD */
opteed_init_with_entry_point函数
这个函数真正完成 上下文恢复 + 跳转到 OP-TEE 的逻辑。
/root/optee/trusted-firmware-a/services/spd/opteed/opteed_main.c
/*******************************************************************************
* This function passes control to the OPTEE image (BL32) for the first time
* on the primary cpu after a cold boot. It assumes that a valid secure
* context has already been created by opteed_setup() which can be directly
* used. It also assumes that a valid non-secure context has been
* initialised by PSCI so it does not need to save and restore any
* non-secure state. This function performs a synchronous entry into
* OPTEE. OPTEE passes control back to this routine through a SMC. This returns
* a non-zero value on success and zero on failure.
******************************************************************************/
static int32_t
opteed_init_with_entry_point(entry_point_info_t *optee_entry_point)
{
//获取当前核心 ID
uint32_t linear_id = plat_my_core_pos();
//获取当前核心的 OP-TEE 上下文
optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
uint64_t rc;
assert(optee_entry_point);
//初始化当前核心的上下文
//cm:Context Management
cm_init_my_context(optee_entry_point);
/*
* Arrange for an entry into OPTEE. It will be returned via
* OPTEE_ENTRY_DONE case
*/
//执行同步跳转
rc = opteed_synchronous_sp_entry(optee_ctx);
//如果返回了 0,说明异常,系统崩溃
assert(rc != 0);
return rc;
}
上下文管理职责划分:
安全上下文(Secure Context) | SPD (如opteed_setup() ) |
为 TEE(如 OP-TEE)准备 S-EL1/S-EL0 状态 |
---|---|---|
非安全上下文(Non-secure Context) | PSCI 模块 | 为 Normal World(如 Linux)准备 EL1/EL0 状态 |
ATF启动过程小结
ATF作为最底层固件,OP-TEE OS、BootLoader、Linux内核的加载都是由ATF来完成的,而且ATF实现了安全引导的功能。BL31运行于EL3,待系统启动完成后,在REE侧或TEE侧触发的安全监控模式调用(SMC)都会进入BL31中被处理。OP-TEE启动完成后会返回一个包含用于处理各种类型的安全监控模式调用的函数指针结构体变量,该变量会被添加到BL31的处理句柄中,用于处理REE侧触发的安全监控模式调用。BL2启动时通过触发安全监控模式调用通知BL1将CPU控制权限交给BL31。BL31通过解析特定段中是否存在OP-TEE的入口函数指针来确定是否需要加载OP-TEE。OP-TEE启动后会触发安全监控模式调用重新进入到BL31中继续执行。BL31通过查询链表的方式获取下一个需要被加载的REE侧镜像文件,并设定好REE侧运行时CPU的状态和运行环境,然后退出EL3进入REE侧镜像文件的启动。一般第一个REE侧镜像文件为BootLoader,BootLoader会加载Linux内核。
参考资料:
- 《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解》