optee中User TA的加载和运行

文章目录

        • 1、optee中的TA简介
        • 2、TA的调用
        • 2、tee_entry_std :std smc的调用
        • 3、open_session

思考:

  • User TA是怎样编译的?
  • User TA是怎样签名的?
  • User TA是怎样被load到内存的?
  • 怎样验证TA签名的?
  • 如何解析TA header,如何给TA分配内存,分配栈地址,分配堆地址,设置栈地址、设置堆地址?
  • TA是怎样执行的?
  • CA/TA的initilization、openssion、inovke、closession的流程?

1、optee中的TA简介

在optee环境中,TA分为

  • PTA : psudo TA, 属于secure EL1, 不能调用GP Internal Core API,可以调用secure drivers等
  • TA : User TA,属于secure EL0
    (1) early TA : 在TEE启动的时候就需要加载到内存中的TA,或者说是打包在tee.img中的TA
    (2) ree_fs TA : 最常用的一种TA,TA Binary存在与REE的磁盘中
    (3) secstor TA : TA binary存在于安全磁盘中

CA/TA/PTA之间的调用模型如下所示
optee中User TA的加载和运行_第1张图片

2、TA的调用

optee中User TA的加载和运行_第2张图片

2、tee_entry_std :std smc的调用

在linux kernel中,通过GP标准调用的与TA通信的命令(opensession\invoke\closession)其实都是std smc call。
该smc调用后,会进入到TEE中的tee_entry_std中:

/*
 * Note: this function is weak just to make it possible to exclude it from
 * the unpaged area.
 */
void __weak tee_entry_std(struct thread_smc_args *smc_args)
{
     
	paddr_t parg;
	struct optee_msg_arg *arg = NULL;	/* fix gcc warning */
	uint32_t num_params = 0;		/* fix gcc warning */
	struct mobj *mobj;

	if (smc_args->a0 != OPTEE_SMC_CALL_WITH_ARG) {
     
		EMSG("Unknown SMC 0x%" PRIx64, (uint64_t)smc_args->a0);
		DMSG("Expected 0x%x\n", OPTEE_SMC_CALL_WITH_ARG);
		smc_args->a0 = OPTEE_SMC_RETURN_EBADCMD;
		return;
	}
	parg = (uint64_t)smc_args->a1 << 32 | smc_args->a2;

	/* Check if this region is in static shared space */
	if (core_pbuf_is(CORE_MEM_NSEC_SHM, parg,
			  sizeof(struct optee_msg_arg))) {
     
		mobj = get_cmd_buffer(parg, &num_params);
	} else {
     
		if (parg & SMALL_PAGE_MASK) {
     
			smc_args->a0 = OPTEE_SMC_RETURN_EBADADDR;
			return;
		}
		mobj = map_cmd_buffer(parg, &num_params);
	}

	if (!mobj || !ALIGNMENT_IS_OK(parg, struct optee_msg_arg)) {
     
		EMSG("Bad arg address 0x%" PRIxPA, parg);
		smc_args->a0 = OPTEE_SMC_RETURN_EBADADDR;
		mobj_free(mobj);
		return;
	}

	arg = mobj_get_va(mobj, 0);
	assert(arg && mobj_is_nonsec(mobj));

	/* Enable foreign interrupts for STD calls */
	thread_set_foreign_intr(true);
	switch (arg->cmd) {
     
	case OPTEE_MSG_CMD_OPEN_SESSION:
		entry_open_session(smc_args, arg, num_params); --------------------------open_session
		break;
	case OPTEE_MSG_CMD_CLOSE_SESSION:
		entry_close_session(smc_args, arg, num_params); --------------------------close_session
		break;
	case OPTEE_MSG_CMD_INVOKE_COMMAND:
		entry_invoke_command(smc_args, arg, num_params); --------------------------invoke cmd
		break;
	case OPTEE_MSG_CMD_CANCEL:
		entry_cancel(smc_args, arg, num_params);
		break;
	case OPTEE_MSG_CMD_REGISTER_SHM:
		register_shm(smc_args, arg, num_params);
		break;
	case OPTEE_MSG_CMD_UNREGISTER_SHM:
		unregister_shm(smc_args, arg, num_params);
		break;

	default:
		EMSG("Unknown cmd 0x%x\n", arg->cmd);
		smc_args->a0 = OPTEE_SMC_RETURN_EBADCMD;
	}
	mobj_free(mobj);
}

3、open_session

open_session---->entry_open_session
optee中User TA的加载和运行_第3张图片
tee_ta_init_user_ta_sessionoptee中User TA的加载和运行_第4张图片
load_elf_from_store

static TEE_Result load_elf_from_store(const TEE_UUID *uuid,
				      const struct user_ta_store_ops *ta_store,
				      struct user_ta_ctx *utc)
{
     
	struct user_ta_store_handle *handle = NULL;
	struct elf_load_state *elf_state = NULL;
	struct ta_head *ta_head;
	struct user_ta_elf *exe;
	struct user_ta_elf *elf;
	struct user_ta_elf *prev;
	TEE_Result res;
	size_t vasize;
	void *p;
	size_t n;
	size_t num_segs = 0;
	struct load_seg *segs = NULL;

	res = ta_store->open(uuid, &handle);
	if (res)
	{
     
		if (res != TEE_ERROR_ITEM_NOT_FOUND)
			EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
		return res;
	}

	elf = ta_elf(uuid, utc);
	if (!elf) {
     
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto out;
	}

	exe = TAILQ_FIRST(&utc->elfs);
	prev = TAILQ_PREV(elf, user_ta_elf_head, link);

	res = elf_load_init(ta_store, handle, elf == exe, &utc->elfs,
			    resolve_symbol, &elf_state);
	if (res)
	{
     
		EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
		goto out;
	}
	elf->elf_state = elf_state;

	res = elf_load_head(elf_state,---------------------------load header, header中包含vasize和stack_size
			    elf == exe ? sizeof(struct ta_head) : 0,
			    &p, &vasize, &utc->is_32bit);
	if (res)
	{
     
		EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
		goto out;
	}
	ta_head = p;


	elf->mobj_code = alloc_ta_mem(vasize);--------------------------在TA RAM中分配内存,给TA的代码段使用
	if (!elf->mobj_code) {
     
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto out;
	}

	if (elf == exe) {
     
		/* Ensure proper alignment of stack */
		size_t stack_sz = ROUNDUP(ta_head->stack_size,
					  STACK_ALIGNMENT);
		utc->mobj_stack = alloc_ta_mem(stack_sz);-------------------在TA RAM中分配内存,给TA的栈使用
		if (!utc->mobj_stack) {
     
			res = TEE_ERROR_OUT_OF_MEMORY;
			goto out;
		}
	}

	/*
	 * Map physical memory into TA virtual memory
	 */
	if (elf == exe) {
     

		res = vm_info_init(utc);---------------------------------map code
		if (res != TEE_SUCCESS)
		{
     
			EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
			goto out;
		}

		/* Add stack segment */
		utc->stack_addr = 0;
		res = vm_map(utc, &utc->stack_addr, utc->mobj_stack->size,--------------------------------map stack
			     TEE_MATTR_URW | TEE_MATTR_PRW, utc->mobj_stack,
			     0);
		if (res)
		{
     
			EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
			goto out;
		}
	}

	res = get_elf_segments(elf, &segs, &num_segs);
	if (res != TEE_SUCCESS)
	{
     
		EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
		goto out;
	}

	if (prev) {
     
		elf->load_addr = prev->load_addr + prev->mobj_code->size;
		elf->load_addr = ROUNDUP(elf->load_addr,
					 CORE_MMU_USER_CODE_SIZE);
	}

	for (n = 0; n < num_segs; n++) {
     
		uint32_t prot = elf_flags_to_mattr(segs[n].flags) |
				TEE_MATTR_PRW;

		segs[n].va = elf->load_addr - segs[0].offs + segs[n].offs;
		segs[n].size = segs[n].oend - segs[n].offs;
		res = vm_map(utc, &segs[n].va, segs[n].size, prot,
			     elf->mobj_code, segs[n].offs);
		if (res)
		{
     
			EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
			goto out;
		}
		if (!n) {
     
			elf->load_addr = segs[0].va;
			DMSG("ELF load address %#" PRIxVA, elf->load_addr);
		}
	}

	tee_mmu_set_ctx(&utc->ctx);

	res = elf_load_body(elf_state, elf->load_addr);
	if (res)
	{
     
		EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
		goto out;
	}

	/* Find any external dependency (dynamically linked libraries) */
	res = add_deps(utc, elf_state, elf->load_addr);
out:
	if (res) {
     
		free(segs);
		EMSG("[%s %d] Error res=0x%x",__func__, __LINE__, res);
	} else {
     
		elf->segs = segs;
		elf->num_segs = num_segs;
	}
	ta_store->close(handle);
	/* utc is cleaned by caller on error */
	return res;
}

elf_load_head其实就是从TA binary中读取ta_head结构体,里面包含uuid、stack_size、ta_entry

struct ta_head {
     
	TEE_UUID uuid;
	uint32_t stack_size;
	uint32_t flags;
	union ta_head_func_ptr entry;
};

我们打开一个TA的反汇编文件查看,

ta_head占用0x20字节,.txt从0x20处开始,ta_entry应该就等于0x20

architecture: aarch64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000000020

Program Header:
    LOAD off    0x0000000000010000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**16
         filesz 0x000000000000777c memsz 0x000000000000777c flags r-x
    LOAD off    0x0000000000017780 vaddr 0x0000000000007780 paddr 0x0000000000007780 align 2**16
         filesz 0x0000000000001c34 memsz 0x0000000000001c34 flags r--
    LOAD off    0x000000000001a000 vaddr 0x000000000000a000 paddr 0x000000000000a000 align 2**16
         filesz 0x0000000000001cfc memsz 0x000000000000c740 flags rw-
 DYNAMIC off    0x0000000000019040 vaddr 0x0000000000009040 paddr 0x0000000000009040 align 2**3
         filesz 0x00000000000000f0 memsz 0x00000000000000f0 flags rw-

Dynamic Section:
  HASH                 0x0000000000009360
  STRTAB               0x00000000000092b0
  SYMTAB               0x0000000000009130
  STRSZ                0x00000000000000ac
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  RELA                 0x0000000000008d38
  RELASZ               0x00000000000002a0
  RELAENT              0x0000000000000018
  RELACOUNT            0x0000000000000013


Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .ta_head      00000020  0000000000000000  0000000000000000  00010000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         0000775c  0000000000000020  0000000000000020  00010020  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .rodata       000015b4  0000000000007780  0000000000007780  00017780  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynsym       00000180  0000000000009130  0000000000009130  00019130  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .rela.dyn     000001c8  0000000000008d38  0000000000008d38  00018d38  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .got          00000068  0000000000008f00  0000000000008f00  00018f00  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  6 .rela.got     000000d8  0000000000008f68  0000000000008f68  00018f68  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .dynamic      000000f0  0000000000009040  0000000000009040  00019040  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  8 .dynstr       000000ac  00000000000092b0  00000000000092b0  000192b0  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .hash         00000054  0000000000009360  0000000000009360  00019360  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .data         00001cfc  000000000000a000  000000000000a000  0001a000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 11 .bss          0000aa40  000000000000bd00  000000000000bd00  0001bcfc  2**3
                  ALLOC
 12 .debug_info   000103be  0000000000000000  0000000000000000  0001bcfc  2**0
                  CONTENTS, READONLY, DEBUGGING
 13 .debug_abbrev 00003fbb  0000000000000000  0000000000000000  0002c0ba  2**0
                  CONTENTS, READONLY, DEBUGGING
 14 .debug_loc    00015e83  0000000000000000  0000000000000000  00030075  2**0
                  CONTENTS, READONLY, DEBUGGING
 15 .debug_aranges 00000b70  0000000000000000  0000000000000000  00045f00  2**4
                  CONTENTS, READONLY, DEBUGGING
 16 .debug_ranges 00000ea0  0000000000000000  0000000000000000  00046a70  2**4
                  CONTENTS, READONLY, DEBUGGING
 17 .debug_line   00003bde  0000000000000000  0000000000000000  00047910  2**0
                  CONTENTS, READONLY, DEBUGGING
 18 .debug_str    0000267d  0000000000000000  0000000000000000  0004b4ee  2**0
                  CONTENTS, READONLY, DEBUGGING
 19 .comment      0000003c  0000000000000000  0000000000000000  0004db6b  2**0
                  CONTENTS, READONLY
 20 .debug_frame  00002220  0000000000000000  0000000000000000  0004dba8  2**3
                  CONTENTS, READONLY, DEBUGGING

alloc_ta_mem就是从tee_mm_sec_ddr的pool中分配内存(tee_mm_sec_ddr的pool其实就是MEM_AREA_TA_RAM类型的内存,也就是TA RAM)

static struct mobj *alloc_ta_mem(size_t size)
{
     
#ifdef CFG_PAGED_USER_TA
	return mobj_paged_alloc(size);
#else
	struct mobj *mobj = mobj_mm_alloc(mobj_sec_ddr, size, &tee_mm_sec_ddr);

	if (mobj)
		memset(mobj_get_va(mobj, 0), 0, size);
	return mobj;
#endif
}

tee_mm_sec_ddr的pool就是MEM_AREA_TA_RAM类型的内存,也就是TA RAM

void teecore_init_ta_ram(void)
{
     
	vaddr_t s;
	vaddr_t e;
	paddr_t ps;
	paddr_t pe;

	/* get virtual addr/size of RAM where TA are loaded/executedNSec
	 * shared mem allcated from teecore */
	core_mmu_get_mem_by_type(MEM_AREA_TA_RAM, &s, &e);
	ps = virt_to_phys((void *)s);
	pe = virt_to_phys((void *)(e - 1)) + 1;

	if (!ps || (ps & CORE_MMU_USER_CODE_MASK) ||
	    !pe || (pe & CORE_MMU_USER_CODE_MASK))
		panic("invalid TA RAM");

	/* extra check: we could rely on  core_mmu_get_mem_by_type() */
	if (!tee_pbuf_is_sec(ps, pe - ps))
		panic("TA RAM is not secure");

	if (!tee_mm_is_empty(&tee_mm_sec_ddr))
		panic("TA RAM pool is not empty");

	/* remove previous config and init TA ddr memory pool */
	tee_mm_final(&tee_mm_sec_ddr);
	tee_mm_init(&tee_mm_sec_ddr, ps, pe, CORE_MMU_USER_CODE_SHIFT,
		    TEE_MM_POOL_NO_FLAGS);
}

vm_info_init会调用到vm_map,在map物理内存到TA的虚拟内存之后,然后又会调用到core_mmu_set_user_map,创建页表,讲页表写入到MMU寄存器.
有下列代码可值,User TA程序也是使用的TTBR0. 页表也是使用的l1_xlation_table,其中user_va_idx宏=-1,也就是数组中的最后一个。

void core_mmu_set_user_map(struct core_mmu_user_map *map)
{
     
	uint64_t ttbr;
	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);

	assert(user_va_idx != -1);

	ttbr = read_ttbr0_64bit();
	/* Clear ASID */
	ttbr &= ~((uint64_t)TTBR_ASID_MASK << TTBR_ASID_SHIFT);
	write_ttbr0_64bit(ttbr);
	isb();

	/* Set the new map */
	if (map && map->user_map) {
     
		l1_xlation_table[0][get_core_pos()][user_va_idx] =
			map->user_map;
#ifdef CFG_CORE_UNMAP_CORE_AT_EL0
		l1_xlation_table[1][get_core_pos()][user_va_idx] =
			map->user_map;
#endif
		dsb();	/* Make sure the write above is visible */
		ttbr |= ((uint64_t)map->asid << TTBR_ASID_SHIFT);
		write_ttbr0_64bit(ttbr);
		isb();
	} else {
     
		l1_xlation_table[0][get_core_pos()][user_va_idx] = 0;
#ifdef CFG_CORE_UNMAP_CORE_AT_EL0
		l1_xlation_table[1][get_core_pos()][user_va_idx] = 0;
#endif
		dsb();	/* Make sure the write above is visible */
	}

	tlbi_all();

	thread_unmask_exceptions(exceptions);
}

你可能感兴趣的:(optee,optee,ATF,TA,trustzone)