日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

optee对std smc的处理的详解

發布時間:2025/3/21 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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結構體中

/* void thread_rpc(uint32_t rv[THREAD_RPC_NUM_ARGS]) */ FUNC thread_rpc , :/* Read daif and create an SPSR */mrs x1, daiforr x1, x1, #(SPSR_64_MODE_EL1 << SPSR_64_MODE_EL_SHIFT)/* Mask all maskable exceptions before switching to temporary stack */msr daifset, #DAIFBIT_ALLpush x0, xzrpush x1, x30bl thread_get_ctx_regsldr x30, [sp, #8]store_xregs x0, THREAD_CTX_REGS_X19, 19, 30mov x19, x0bl thread_get_tmp_sppop x1, xzr /* Match "push x1, x30" above */mov x2, spstr x2, [x19, #THREAD_CTX_REGS_SP]ldr x20, [sp] /* Get pointer to rv[] */mov sp, x0 /* Switch to tmp stack */adr x2, .thread_rpc_return //------------------------等RPC調用從REE再回來時,接著執行thread_rpc_returnmov w0, #THREAD_FLAGS_COPY_ARGS_ON_RETURNbl thread_state_suspendmov x4, x0 /* Supply thread index */ldr w0, =TEESMC_OPTEED_RETURN_CALL_DONEload_wregs x20, 0, 1, 3 /* Load rv[] into w0-w2 */smc #0 //-----------------------------------------------RPC調用,這里要切到REE了b . /* SMC should not return */.thread_rpc_return: //---------------------------------------------等RPC調用從REE再回來時,接著執行thread_rpc_return/** At this point has the stack pointer been restored to the value* stored in THREAD_CTX above.** Jumps here from thread_resume above when RPC has returned. The* IRQ and FIQ bits are restored to what they where when this* function was originally entered.*/pop x16, xzr /* Get pointer to rv[] */store_wregs x16, 0, 0, 5 /* Store w0-w5 into rv[] */ret END_FUNC thread_rpc KEEP_PAGER thread_rpc
(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;

#ifdef ARM64 static void init_regs(struct thread_ctx *thread,struct thread_smc_args *args) {thread->regs.pc = (uint64_t)thread_std_smc_entry;/** Stdcalls starts in SVC mode with masked foreign interrupts, masked* Asynchronous abort and unmasked native interrupts.*/thread->regs.cpsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0,THREAD_EXCP_FOREIGN_INTR | DAIFBIT_ABT);/* Reinitialize stack pointer */thread->regs.sp = thread->stack_va_end;/** Copy arguments into context. This will make the* arguments appear in x0-x7 when thread is started.*/thread->regs.x[0] = args->a0;thread->regs.x[1] = args->a1;thread->regs.x[2] = args->a2;thread->regs.x[3] = args->a3;thread->regs.x[4] = args->a4;thread->regs.x[5] = args->a5;thread->regs.x[6] = args->a6;thread->regs.x[7] = args->a7;/* Set up frame pointer as per the Aarch64 AAPCS */thread->regs.x[29] = 0; } #endif /*ARM64*/

而在thread_resume中,將struct thread_ctx_regs結構體中的pc值賦給了x2, x2又賦給了ELR.
thread_resume程序返回后,就將執行ELR執行的地址,也就是對應著thread_std_smc_entry函數

/* 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

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等

/** 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);break;case OPTEE_MSG_CMD_CLOSE_SESSION:entry_close_session(smc_args, arg, num_params);break;case OPTEE_MSG_CMD_INVOKE_COMMAND:entry_invoke_command(smc_args, arg, num_params);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); }

總結

以上是生活随笔為你收集整理的optee对std smc的处理的详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。