启动过程中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。