optee userpace TA程式中的棧的設定

曾經再美好也只是曾經發表於2020-09-24


★★★ 友情連結 : 個人部落格導讀首頁—點選此處 ★★★

思考:

TA怎樣被裝載到記憶體?
TA如何執行的?
他的棧、堆如何分配的?
CA呼叫他的共享記憶體,在TA中如何map的?

1、openssession結構體

在opensession的時候,會將session註冊到TEE記憶體中,以連結串列方式存在

struct tee_ta_session {
	TAILQ_ENTRY(tee_ta_session) link;
	TAILQ_ENTRY(tee_ta_session) link_tsd;
	struct tee_ta_ctx *ctx;	/* TA context */
	TEE_Identity clnt_id;	/* Identify of client */
	bool cancel;		/* True if TAF is cancelled */
	bool cancel_mask;	/* True if cancel is masked */
	TEE_Time cancel_time;	/* Time when to cancel the TAF */
	void *user_ctx;		/* ??? */
	uint32_t ref_count;	/* reference counter */
	struct condvar refc_cv;	/* CV used to wait for ref_count to be 0 */
	struct condvar lock_cv;	/* CV used to wait for lock */
	int lock_thread;	/* Id of thread holding the lock */
	bool unlink;		/* True if session is to be unlinked */
#if defined(CFG_TA_GPROF_SUPPORT)
	struct sample_buf *sbuf; /* Profiling data (PC sampling) */
#endif
};

2、user TA棧的地址獲取

堆和棧的大小,都是在User_ta_header_defines.h檔案種定義的:

#define TA_STACK_SIZE		(2 * 1024)
#define TA_DATA_SIZE		(4 * 1024 * 1024 + 32 * 1024)

在opensession的時候,將棧的地址map到TA虛擬地址空間

		/* Add stack segment */
		utc->stack_addr = 0;
		res = vm_map(utc, &utc->stack_addr, utc->mobj_stack->size,
			     TEE_MATTR_URW | TEE_MATTR_PRW, utc->mobj_stack,
			     0);

3、invoke的流程:

先看一個列舉陣列,這是kernel mode與TA通訊的三個介面,僅此三個.
或者也可以說,這是CA和TA通訊的3個介面

enum utee_entry_func {
	UTEE_ENTRY_FUNC_OPEN_SESSION = 0,
	UTEE_ENTRY_FUNC_CLOSE_SESSION,
	UTEE_ENTRY_FUNC_INVOKE_COMMAND,
};

invoke的流程:
tee_entry_std -->tee_ta_invoke_command()---->user_ta_enter_invoke_cmd()—>user_ta_enter()

分析invoke函式:

static TEE_Result user_ta_enter_open_session(struct tee_ta_session *s,
			struct tee_ta_param *param, TEE_ErrorOrigin *eo)
{
	return user_ta_enter(eo, s, UTEE_ENTRY_FUNC_OPEN_SESSION, 0, param);   -------//這裡cmd是invoke
}

從下面函式可以看出, TA執行時的stack是從TA binray解析出來的

static TEE_Result user_ta_enter(TEE_ErrorOrigin *err,
			struct tee_ta_session *session,
			enum utee_entry_func func, uint32_t cmd,
			struct tee_ta_param *param)
{
	TEE_Result res;
	struct utee_params *usr_params;
	uaddr_t usr_stack;
	struct user_ta_ctx *utc = to_user_ta_ctx(session->ctx);
	TEE_ErrorOrigin serr = TEE_ORIGIN_TEE;
	struct tee_ta_session *s __maybe_unused;
	void *param_va[TEE_NUM_PARAMS] = { NULL };

	/* Map user space memory */
	res = tee_mmu_map_param(utc, param, param_va);  //---------------將param引數(共享記憶體)map到TEE中
	if (res != TEE_SUCCESS)
		goto cleanup_return;

	/* Switch to user ctx */
	tee_ta_push_current_session(session);

	/* Make room for usr_params at top of stack */
	usr_stack = utc->stack_addr + utc->mobj_stack->size;  //----------------解析棧地址
	usr_stack -= ROUNDUP(sizeof(struct utee_params), STACK_ALIGNMENT);
	usr_params = (struct utee_params *)usr_stack;
	init_utee_param(usr_params, param, param_va);

	res = thread_enter_user_mode(func, tee_svc_kaddr_to_uref(session),//----------------進入userspace,並跳轉到entry_func
				     (vaddr_t)usr_params, cmd, usr_stack,
				     utc->entry_func, utc->is_32bit,
				     &utc->ctx.panicked, &utc->ctx.panic_code);

	clear_vfp_state(utc);
	/*
	 * According to GP spec the origin should allways be set to the
	 * TA after TA execution
	 */
	serr = TEE_ORIGIN_TRUSTED_APP;

	if (utc->ctx.panicked) {
		DMSG("tee_user_ta_enter: TA panicked with code 0x%x\n",
		     utc->ctx.panic_code);
		serr = TEE_ORIGIN_TEE;
		res = TEE_ERROR_TARGET_DEAD;
	}

	/* Copy out value results */
	update_from_utee_param(param, usr_params);

	s = tee_ta_pop_current_session();
	assert(s == session);
cleanup_return:

	/*
	 * Clear the cancel state now that the user TA has returned. The next
	 * time the TA will be invoked will be with a new operation and should
	 * not have an old cancellation pending.
	 */
	session->cancel = false;

	/*
	 * Can't update *err until now since it may point to an address
	 * mapped for the user mode TA.
	 */
	*err = serr;

	return res;
}

4、thread_enter_user_mode中設定棧地址

uint32_t thread_enter_user_mode(unsigned long a0, unsigned long a1,
		unsigned long a2, unsigned long a3, unsigned long user_sp,
		unsigned long entry_func, bool is_32bit,
		uint32_t *exit_status0, uint32_t *exit_status1)
{
	uint32_t spsr;

	tee_ta_update_session_utime_resume();

	if (!get_spsr(is_32bit, entry_func, &spsr)) {
		*exit_status0 = 1; /* panic */
		*exit_status1 = 0xbadbadba;
		return 0;
	}
	return __thread_enter_user_mode(a0, a1, a2, a3, user_sp, entry_func,
					spsr, exit_status0, exit_status1);
}
/*
 * uint32_t __thread_enter_user_mode(unsigned long a0, unsigned long a1,
 *               unsigned long a2, unsigned long a3, unsigned long user_sp,
 *               unsigned long user_func, unsigned long spsr,
 *               uint32_t *exit_status0, uint32_t *exit_status1)
 *
 */
FUNC __thread_enter_user_mode , :
	ldr	x8, [sp]
	/*
	 * Create the and fill in the struct thread_user_mode_rec
	 */
	sub	sp, sp, #THREAD_USER_MODE_REC_SIZE
	store_xregs sp, THREAD_USER_MODE_REC_EXIT_STATUS0_PTR, 7, 8
	store_xregs sp, THREAD_USER_MODE_REC_X19, 19, 30

	/*
	 * Switch to SP_EL1
	 * Disable exceptions
	 * Save kern sp in x19
	 */
	msr	daifset, #DAIFBIT_ALL
	mov	x19, sp    ------------------------將kernel mode下的 sp(sp_el0)儲存到X19中
	msr	spsel, #1  ------------------------從此刻開始,kernel mode下sp使用sp_el1

	/*
	 * Save the kernel stack pointer in the thread context
	 */
	/* get pointer to current thread context */
	get_thread_ctx sp, 21, 20, 22
	/*
	 * Save kernel stack pointer to ensure that el0_svc() uses
	 * correct stack pointer
	 */
	str	x19, [x21, #THREAD_CTX_KERN_SP]  ---------- 將棧地址儲存到全域性變數中,因為userspace程式可能會主動呼叫kernel mode,然後使用kernel mode下的棧

	/*
	 * Initialize SPSR, ELR_EL1, and SP_EL0 to enter user mode
	 */
	msr	spsr_el1, x6
	/* Set user sp */
	mov	x13, x4		/* Used when running TA in Aarch32 */    --------------------將棧地址寫入到R13
	msr	sp_el0, x4	/* Used when running TA in Aarch64 */    --------------------將棧地址寫入到sp_el0
	/* Set user function */
	msr	elr_el1, x5
	/* Set frame pointer (user stack can't be unwound past this point) */
	mov x29, #0  --------------------------------------------------------- ELR清0

	/* Jump into user mode */
	store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 1
	b eret_to_el0
END_FUNC __thread_enter_user_mode

相關文章