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
相關文章
- 棧出現的異常和設定棧的大小-Xss
- OPTEE - CA和他的互動
- 程式設計師的一天,最離不開的竟是“TA”?程式設計師
- 數棧產品分享:Kafka—實時離不開的那個TAKafka
- Pycharm程式碼塊的設定PyCharm
- 性感的Promise,擁抱ta然後扒光taPromise
- linux中設定程式排程的優先順序別Linux
- 數棧產品中的程式碼編譯器編譯
- Shiro中的Remember me設定REM
- CAD中的線寬設定
- MySQL中的時區設定MySql
- 程式設計師:全棧的痛你不知道程式設計師全棧
- 成為全棧程式設計師的技能表 - dev全棧程式設計師dev
- Linux 中如何設定每個特定的時間執行特定的程式Linux
- win10預設程式怎麼設定介面_win10設定預設程式的方法Win10
- 併發程式設計 棧幀程式設計
- VNPY 中基於Ta-lib的KDJ策略實現
- RadioGroup 在TS schema 中的設定
- Java全棧程式設計師之01:做個Linux下的程式猿Java全棧程式設計師Linux
- 如何設定redis中hash的field的expire ?Redis
- 用JS設定一個人的程式的話JS
- 初識前端中的棧前端
- js中棧的運用JS
- Flask中本地棧的使用Flask
- javascript中如何設定滑鼠的形狀JavaScript
- python中__setattr__的屬性設定Python
- vue中select的使用以及select設定預設選中Vue
- solaris中如何設定解析度?在solaris中設定解析度的方法教程
- 全棧工程師的定義和價值全棧工程師
- 在word中怎麼設定目錄 word設定目錄的方法
- 定製個機器人幫你和Ta聊天機器人
- 設定select下拉選單的預設選中項
- 給程式設計入門者的嘮叨話(全棧路線)程式設計全棧
- JS中的程式設計題JS程式設計
- golang中的socket程式設計Golang程式設計
- 適合新手的鏈棧程式碼
- “全棧” 程式設計師如何發展?全棧程式設計師
- Rust 程式設計,用 vector 實現棧Rust程式設計