OP-TEE服务项的启动分为: service_init以及service_init_late ,需要被启动的服务项通过使用这两个宏,在编译时,相关服务的内容将会被保存到initcall1和initcall2中。
1. service_init宏
在OP-TEE使用中使用service_init宏定义的服务项如下:
service_init(register_supplicant_user_ta);
service_init(verify_pseudo_tas_conformance);
service_init(tee_cryp_init);
service_init(tee_se_manager_init);
如果开发者有实际需求,可以将自己希望添加的服务项功能按照相同的方式添加到系统中。
在当前的OP-TEE中默认是启动上述四个服务,分别定义在以下文件:
register_supplicant_user_ta: core/arch/arm/kernel/ree_fs_ta.c
verify_pseudo_tas_conformance: core/arch/arm/kernel/pseudo_ta
tee_cryp_init: core/tee/tee_cryp_utl.c
tee_se_manager_init: core/tee/se/manager.c
register_supplicant_user_ta部分:
该操作主要是注册OP-TEE加载REE侧的TA镜像时需要使用的操作接口 ,当REE侧执行open session操作时,TEE侧会根据UUID的值在REE侧的文件系统中查找该文件,然后通过RPC请求通知tee_supplicant从REE的文件系统中读取与UUID对应的TA镜像文件的内容并传递到TEE侧。
verify_pseudo_tas_conformance部分:
该函数主要是用来校验OP-TEE中静态TA的合法性,需要检查OP-TEE OS中静态TA的UUID、函数指针以及相关的flag。该段代码如下:
static TEE_Result verify_pseudo_tas_conformance(void)
{
//获取存放psedo TAs的head info的段起始地址
const struct pseudo_ta_head *start = &__start_ta_head_section;
//获取存放psedo TAs的head info的段末尾地址
const struct pseudo_ta_head *end = &__stop_ta_head_section;
const struct pseudo_ta_head *pta; //定义一个指向TA head的变量指针
for (pta = start; pta < end; pta++) {
const struct pseudo_ta_head *pta2;
/* 检查psedo TAs的head info中包含的UUID信息是否有相同的 */
for (pta2 = pta + 1; pta2 < end; pta2++)
if (! memcmp(&pta- >uuid, &pta2- >uuid, sizeof(TEE_UUID)))
goto err;
/* 检查invoke函数指针是否为空和相关的flag是否合法 */
if (! pta- >name ||
(pta- >flags & PTA_MANDATORY_FLAGS) ! = PTA_MANDATORY_FLAGS ||
pta- >flags & ~PTA_ALLOWED_FLAGS ||
!pta- >invoke_command_entry_point)
goto err;
}
return TEE_SUCCESS;
err:
DMSG("pseudo TA error at %p", (void *)pta);
panic("pta");
}
OP-TEE OS镜像文件中的__start_ta_head_section与__stop_ta_head_section之间保存的是OP-TEE所有静态TA的内容,其值的定义见core/arch/arm/kernel/kern.ld.S文件,分别表示ta_head_section段的起始地址和末端地址。
在编译OP-TEE的静态TA时,使用pseudo_ta_register宏来告知编译器将静态TA的内容保存到ta_head_section段中,该宏定义在core/arch/arm/include/kernel/pseudo_ta.h文件中,内容如下:
#define pseudo_ta_register(...) static const struct pseudo_ta_head __head
__used __section("ta_head_section") = { __VA_ARGS__ }
共有六个静态TA在OP-TEE编译时会被打包进OP-TEE的镜像文件中,分别如下:
gprof: core/arch/arm/pta/gprof.c
interrupt_tests.ta: core/arch/arm/pta/Iiterrupt_tests.c
stats.ta: core/arch/arm/pta/stats.c
se_api_self_tests.ta: core/arch/arm/pta/se_api_self_tests.c
socket: core/arch/arm/tee/pta_socket.c
invoke_tests.pta: core/arch/arm/pta/pta_invoke_test.c
tee_cryp_init部分:
该部分主要完成OP-TEE提供的密码学接口功能的初始化操作,调用crypto_ops结构体中的init进行初始化操作,该结构体变量定义在core/lib/libtomcrypt/src/tee_ltc_provider.c文件中,变量中定义了各种算法的操作函数指针。
完成注册后,TA就可以通过调用该变量中的对应函数指针来实现OP-TEE中各种密码学算法接口的调用。
tee_se_manager_init部分:
该部分主要完成对SE模块的管理,为上层提供对SE模块的操作接口。
2. service_init_late宏
service_init_late宏定义的内容将会在编译时被链接到OP-TEE镜像文件的initcall2段中 , OP-TEE中使用该宏来定义OP-TEE中使用的密钥管理操作 ,在core/tee/tee_fs_key_manager.c文件中,使用该宏来将tee_fs_key_manager函数保存到initcall2段中,
在OP-TEE启动时被调用,用来生成或读取OP-TEE在使用时会使用到的key,该函数内容如下:
static TEE_Result tee_fs_init_key_manager(void)
{
int res = TEE_SUCCESS;
struct tee_hw_unique_key huk;
uint8_t chip_id[TEE_FS_KM_CHIP_ID_LENGTH];
uint8_t message[sizeof(chip_id) + sizeof(string_for_ssk_gen)];
/* 获取机器唯一的key作为salt值 */
tee_otp_get_hw_unique_key(&huk);
/* 获取chip ID值 */
tee_otp_get_die_id(chip_id, sizeof(chip_id));
/* 将unique key和chip id存放到message变量中 */
memcpy(message, chip_id, sizeof(chip_id));
memcpy(message + sizeof(chip_id), string_for_ssk_gen,
sizeof(string_for_ssk_gen));
/* 调用HMAC算法,以获取到的message作为参数传入来计算出一串字符串作为key存放到tee_
fs_ssk变量中的key成员中 */
res = do_hmac(tee_fs_ssk, key, sizeof(tee_fs_ssk.key),
huk.data, sizeof(huk.data),
message, sizeof(message));
if (res == TEE_SUCCESS)
tee_fs_ssk.is_init = 1;
return res;
}
这些key将会在使用安全存储功能时用到,用于生成加密、解密安全文件的FEK,其中tee_otp_get_hw_unique_key函数可根据不同的平台进行修改 ,只要保证读取到的值的唯一性且安全即可,当前一般做法是读取一次性编程区域(One Time Programmable, OTP)或efuse中的值,该值将在芯片生产或者工厂整机生产时烧录到OTP中,当然也有其他的实现方式。
-
编译
+关注
关注
0文章
657浏览量
32852 -
宏定义
+关注
关注
0文章
50浏览量
9005
发布评论请先 登录
相关推荐
评论