optee userpace TA程式中的棧的設定
思考:
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
相關文章
- Python趣味程式設計:定時給Ta講笑話Python程式設計
- OPTEE - CA和他的互動
- 棧出現的異常和設定棧的大小-Xss
- 程式設計師的一天,最離不開的竟是“TA”?程式設計師
- 數棧產品分享:Kafka—實時離不開的那個TAKafka
- 偵錯程式中的斷點是如何設定的?斷點
- 堆和棧在程式中的比較
- 全棧 JavaScript 程式設計師的崛起全棧JavaScript程式設計師
- java中的棧Java
- 性感的Promise,擁抱ta然後扒光taPromise
- 在程式碼中設定IE9的預設文件模式IE9模式
- 傷不起的全棧程式設計師全棧程式設計師
- 程式設計師的自我修養之全棧程式設計師程式設計師全棧
- Tarjan中棧的分析與SLT棧的實現
- 數棧產品中的程式碼編譯器編譯
- MySQL中的時區設定MySql
- android中設定代理程式碼Android
- Pycharm程式碼塊的設定PyCharm
- VNPY 中基於Ta-lib的KDJ策略實現
- 成為全棧程式設計師的技能表 - dev全棧程式設計師dev
- 程式設計師:全棧的痛你不知道程式設計師全棧
- 初識前端中的棧前端
- Flask中本地棧的使用Flask
- javascript中的棧結構JavaScript
- js中棧的運用JS
- linux中設定程式排程的優先順序別Linux
- webservice設定--“/WebServiceForTest”應用程式中的伺服器錯誤。Web伺服器
- CAD中的線寬設定
- Shiro中的Remember me設定REM
- App中橫豎屏的設定APP
- JSP中的編碼設定JS
- 轉-ArcGIS Engine中的License設定
- Linux中的字型設定 (轉)Linux
- 併發程式設計 棧幀程式設計
- 如何設定redis中hash的field的expire ?Redis
- Linux 中如何設定每個特定的時間執行特定的程式Linux
- win10預設程式怎麼設定介面_win10設定預設程式的方法Win10
- golang中的http的Header中設定Host無效GolangHTTPHeader