历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE技术详细阐述,读者可从用户空间到TEE内核一步一步了解系统安全的所有内容,同时书中也提供了相关的示例代码,读者可根据自身实际需求开发TA。目前该书已在天猫、京东、当当同步上线,链接如下(麻烦书友购书时能给予评论,多谢多谢):
京东购买地址
当当购买地址
天猫购买地址
非常感谢在此期间大家的支持以及各位友人的支持和帮助!!!。
为方便和及时的回复读者对书中或者TEE相关的问题的疑惑,也为了大家能有一个统一的交流平台。我搭建了一个简单的论坛,网址如下:
https://www.huangtengxq.com/discuz/forum.php
关于您的疑问可在“相关技术讨论“”中发帖,我会逐一回复。也欢迎大家发帖,一起讨论TEE相关的一些有意思的feature。共同交流。同时该论坛中也会添加关于移动端虚拟化的相关技术的板块,欢迎各位共同交流学习
启动过程中entry.S文件通过汇报调用main_init_sec函数将optee-os image. kernel image和rootfs加载到RAM中,并定位device tree地址信息,以备kernel和OP-TEE启动使用,这些操作是由main_init_sec函数,该函数定义在bios_qemu_tz_arm/bios/main.c文件中,本文将介绍main_init_sec函数的执行流程和具体操作。
main_init_sec的完整的流程图如下:
main_init_sec函数内容和代码注释如下
void main_init_sec(struct sec_entry_arg *arg)
{
void *fdt;
int r;
const uint8_t *sblob_start = &__linker_secure_blob_start; //定义OP-TEE OS image的存放的起始地址
const uint8_t *sblob_end = &__linker_secure_blob_end; //定义OP-TEE OS image的存放的末端地址
struct optee_header hdr; //存放OP-TEE OS image头的信息
size_t pg_part_size; //OP-TEE OS image除去初始化头部的信息的大小
uint32_t pg_part_dst; //OP-TEE OS image除去初始化头部信息后在RAM中的起始地址
msg_init(); //初始化uart
/* Find DTB */
/* 加载device tree 信息,在qemu工程中,并未将device tree信息编译到Bios.bin中,而默认存放在DTB_START地址中 */
fdt = open_fdt(DTB_START, &__linker_nsec_dtb_start,
&__linker_nsec_dtb_end);
r = fdt_pack(fdt);
CHECK(r < 0);
/* Look for a header first */
/* 判定OP-TEE OS image的大小是否大于image header的大小 */
CHECK(((intptr_t)sblob_end - (intptr_t)sblob_start) <
(ssize_t)sizeof(hdr));
/* 将OP-TEE OS image header信息拷贝到hdr变量中 */
copy_bios_image("secure header", (uint32_t)&hdr, sblob_start,
sblob_start + sizeof(hdr));
/* 校验OP-TEE OS image header中的magic和版本信息是否合法 */
CHECK(hdr.magic != OPTEE_MAGIC || hdr.version != OPTEE_VERSION);
msg("found secure header\n");
sblob_start += sizeof(hdr); //将sblob_start的值后移到除去image header的位置
CHECK(hdr.init_load_addr_hi != 0); //检查OP-TEE OS的初始化加载地址是否为零
/* 获取OP-TEE OS除去 image header和ini操作部分代码的大小 */
pg_part_size = sblob_end - sblob_start - hdr.init_size;
/* 确定存放OP-TEE OS除去image header和init操作部分代码后存放在RAM中的地址 */
pg_part_dst = (size_t)TZ_RES_MEM_START + TZ_RES_MEM_SIZE - pg_part_size;
/* 将存放OP-TEE OS除去image header和init操作部分后的内容拷贝到RAM中 */
copy_bios_image("secure paged part",
pg_part_dst, sblob_start + hdr.init_size, sblob_end);
sblob_end -= pg_part_size; //重新计算sblo_end的地址,剔除page part
arg->paged_part = pg_part_dst; //将pg_part_dst赋值给arg中的paged_part以备跳转执行OP-TEE OS使用
arg->entry = hdr.init_load_addr_lo; //将hdr.init_load_addr_lo赋值给arg中的entry,该地址为op-TEE OS的入口地址
/* Copy secure image in place */
/* 将OP-TEE OS的实际image拷贝到其实地址为hdr.init_load_addr_l的RAM地址中 */
copy_bios_image("secure blob", hdr.init_load_addr_lo, sblob_start,
sblob_end);
/*
* Copy NS images as while we can read the secure flash from where
* we load them.
*/
/* 拷贝kernel image, rootfs到RAM,并拷贝device tree到对应地址,以备被kernel使用 */
copy_ns_images();、
/* 将device tree的地址赋值给arg->fdt变量,以备OP-TEE OS启动使用 */
arg->fdt = dtb_addr;
msg("Initializing secure world\n");
}
Note:在qemu.mk工程中,OP-TEE image中是没有paged part部分的,这点从启动log就而已看出
该函数执行完成之后,将会返回结构体为sec_entry_arg的变量,该变量在接下来启动OP-TEE OS的时候很重要,该变量将会告诉CPU OP-TEE OS的入口地址,device tree的地址以及paged_part的地址。
main_init_sec函数执行完成之后会返回到entry.S中继续执行,接下来所执行的汇编代码如下:
pop {r0, r1, r2}
mov ip, r0 /* entry address */
mov r0, r1 /* argument (address of pagable part if != 0) */
blx ip
在执行完main_init_sec函数自后, OP-TEE OS的entry地址将会被存放在r0寄存器中,而paged part部分的起始地址将会被存放咋r1寄存器中。使用pop指令执行出栈操作,然后使用mov指令,将存放了OP-TEE OS image的entry address的值赋值给ip寄存器,将paged part的起始地址赋值给r0寄存器,最后调用blx ip指令,进入OP-TEE OS的启动操作。等OP-TEE OS启动完成之后,则会再次跳转会entry.s文件中继续执行,接下来会通过调用main_init_ns函数去启动Linux kernel。