optee对std smc的处理的详解
文章目錄
- 1、ATF跳轉到optee的std_smc_entry
- 2、optee中的std_smc_entry流程
- (1)、RPC回來的std call的處理
- (2)、REE調用的std call的處理 : thread_std_smc_entry
- 3、線程thread_std_smc_entry
std smc跳轉到optee的場景有兩種:
- REE主動發起std smc的調用,基本就算Globalplatform Client
API(libteec.so)的調用,也就是openssion\invoke\closession等函數的調用; - Optee中發起了RPC反向調用REE后,從REE再切回來是,也是走std call流程
1、ATF跳轉到optee的std_smc_entry
當REE發起std smc調用后,跳轉到ATF后,ATF根據smc_fid的type判定該smc屬于STD,則設置ELR寄存器的值為std_smc_entry(在ATF中保存著一份和optee中同樣的線程向量表),那么當ATF ERET返回時,程序跳轉到ELR中的地址處,也就optee中所定義的線程向量表中的std_smc_entry
uint64_t opteed_smc_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void *cookie,void *handle,uint64_t flags) { ......if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) {cm_set_elr_el3(SECURE, (uint64_t)&optee_vectors->fast_smc_entry);} else {cm_set_elr_el3(SECURE, (uint64_t)&optee_vectors->std_smc_entry); //------------------設置ELR寄存器} ......SMC_RET4(&optee_ctx->cpu_ctx, smc_fid, x1, x2, x3); //-------------ERET返回,程序跳轉到ELR中的地址}2、optee中的std_smc_entry流程
LOCAL_FUNC vector_std_smc_entry , :sub sp, sp, #THREAD_SMC_ARGS_SIZEstore_xregs sp, THREAD_SMC_ARGS_X0, 0, 7mov x0, spbl thread_handle_std_smc //------------------------------std業務邏輯的處理/** Normally thread_handle_std_smc() should return via* thread_exit(), thread_rpc(), but if thread_handle_std_smc()* hasn't switched stack (error detected) it will do a normal "C"* return.*/load_xregs sp, THREAD_SMC_ARGS_X0, 1, 8add sp, sp, #THREAD_SMC_ARGS_SIZEldr x0, =TEESMC_OPTEED_RETURN_CALL_DONEsmc #0 //--------------------------------std業務處理完成后,再次將cpu切回REEb . /* SMC should not return */如果是std call則調用thread_alloc_and_run,如果是RPC回來的(RPC回來也是走的std smc)則走thread_resume_from_rpc(args)
void thread_handle_std_smc(struct thread_smc_args *args) {thread_check_canaries();if (args->a0 == OPTEE_SMC_CALL_RETURN_FROM_RPC)thread_resume_from_rpc(args);elsethread_alloc_and_run(args); }(1)、RPC回來的std call的處理
thread_resume_from_rpc中,直接調用了thread_resume
static void thread_resume_from_rpc(struct thread_smc_args *args) {size_t n = args->a3; /* thread id */struct thread_core_local *l = thread_get_core_local();uint32_t rv = 0;assert(l->curr_thread == -1);lock_global();if (n < CFG_NUM_THREADS &&threads[n].state == THREAD_STATE_SUSPENDED &&args->a7 == threads[n].hyp_clnt_id)threads[n].state = THREAD_STATE_ACTIVE;elserv = OPTEE_SMC_RETURN_ERESUME;unlock_global();if (rv) {args->a0 = rv;return;}l->curr_thread = n;if (is_user_mode(&threads[n].regs))tee_ta_update_session_utime_resume();if (threads[n].have_user_map)core_mmu_set_user_map(&threads[n].user_map);/** Return from RPC to request service of a foreign interrupt must not* get parameters from non-secure world.*/if (threads[n].flags & THREAD_FLAGS_COPY_ARGS_ON_RETURN) {copy_a0_to_a5(&threads[n].regs, args);threads[n].flags &= ~THREAD_FLAGS_COPY_ARGS_ON_RETURN;}thread_lazy_save_ns_vfp();thread_resume(&threads[n].regs); }而在thread_resume中,程序會通過eret返回,也就是跳轉到ELR中的地址. 那么ELR中的值來在來自x2,x2又來自threads[n].regs結構體中的PC值
/* void thread_resume(struct thread_ctx_regs *regs) */ FUNC thread_resume , :load_xregs x0, THREAD_CTX_REGS_SP, 1, 3 //-------------------------x2等于struct thread_ctx_regs結構體中的pc值load_xregs x0, THREAD_CTX_REGS_X4, 4, 30mov sp, x1msr elr_el1, x2 //-------------------------將x2賦值到elr寄存器msr spsr_el1, x3b_if_spsr_is_el0 w3, 1fload_xregs x0, THREAD_CTX_REGS_X1, 1, 3ldr x0, [x0, THREAD_CTX_REGS_X0]eret //------------------------------------eret返回,則跳轉到elr中的地址1: load_xregs x0, THREAD_CTX_REGS_X1, 1, 3ldr x0, [x0, THREAD_CTX_REGS_X0]msr spsel, #1store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 1b eret_to_el0 END_FUNC thread_resume那么threads[n].regs結構體中的PC值又來自哪里呢?
在optee發起RPC調用時,將RPC調用從REE回來后,需要接著運行的地址,寫入到了x2中,然后又保存到了struct thread_ctx_regs結構體中
(2)、REE調用的std call的處理 : thread_std_smc_entry
thread_alloc_and_run函數中,先調用init_regs(threads + n, args), 然后再調用thread_resume(&threads[n].regs)
static void thread_alloc_and_run(struct thread_smc_args *args) {size_t n;struct thread_core_local *l = thread_get_core_local();bool found_thread = false;assert(l->curr_thread == -1);lock_global();for (n = 0; n < CFG_NUM_THREADS; n++) {if (threads[n].state == THREAD_STATE_FREE) {threads[n].state = THREAD_STATE_ACTIVE;found_thread = true;break;}}unlock_global();if (!found_thread) {args->a0 = OPTEE_SMC_RETURN_ETHREAD_LIMIT;return;}l->curr_thread = n;threads[n].flags = 0;init_regs(threads + n, args);/* Save Hypervisor Client ID */threads[n].hyp_clnt_id = args->a7;thread_lazy_save_ns_vfp();thread_resume(&threads[n].regs); }而在init_regs中,將thread_std_smc_entry函數的地址,寫入到了struct thread_ctx_regs結構體中的pc變量中
thread->regs.pc = (uint64_t)thread_std_smc_entry;
而在thread_resume中,將struct thread_ctx_regs結構體中的pc值賦給了x2, x2又賦給了ELR.
thread_resume程序返回后,就將執行ELR執行的地址,也就是對應著thread_std_smc_entry函數
3、線程thread_std_smc_entry
當REE調用標準的std smc時,將進入optee中的thread_std_smc_entry程序,那么該程序都做了什么事情呢?
thread_std_smc_entry調用__thread_std_smc_entry,而__thread_std_smc_entry又會調用平臺的std_smc_hander
void __weak __thread_std_smc_entry(struct thread_smc_args *args) {thread_std_smc_handler_ptr(args); //-------------------------------這里調用vendor廠商實現的std_smc_hander,在main.c中if (args->a0 == OPTEE_SMC_RETURN_OK) {struct thread_ctx *thr = threads + thread_get_id();tee_fs_rpc_cache_clear(&thr->tsd);if (!thread_prealloc_rpc_cache) {thread_rpc_free_arg(thr->rpc_carg);mobj_free(thr->rpc_mobj);thr->rpc_carg = 0;thr->rpc_arg = 0;thr->rpc_mobj = NULL;}} }而平臺實現的std_smc_hander,其實都是指向entry_std.c中的std_smc_hander(意思就是平臺可以自行實現,也可以用標準的entry_std.c中的)
從std_smc_hander的實現來看,std call也就是支持一些標準的命令,如open close invoke等
總結
以上是生活随笔為你收集整理的optee对std smc的处理的详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: optee的RPC流程的代码详解
- 下一篇: optee内核中malloc函数的原理介