OPTEE學習筆記 - 驅動的載入和初始化(CA和TA通訊)
阿新 • • 發佈:2019-01-01
驅動的載入和初始化可以參考https://blog.csdn.net/shuaifengyun/article/details/72934531。已經做出較為詳細的說明,這裡對於其中一些更細節的內容做出一些記錄,僅供學習參考。
文中提到了optee_probe是建立optee驅動的最後一步,其中的操作大多數型如下:
invoke_fn = get_invoke_func(np); if (IS_ERR(invoke_fn)) return (void *)invoke_fn; if (!optee_msg_api_uid_is_optee_api(invoke_fn)) { pr_warn("api uid mismatch\n"); return ERR_PTR(-EINVAL); } if (!optee_msg_api_revision_is_compatible(invoke_fn)) { pr_warn("api revision mismatch\n"); return ERR_PTR(-EINVAL); } if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) { pr_warn("capabilities mismatch\n"); return ERR_PTR(-EINVAL); }
可以看到,首先獲取到一個Invoke_fn的函式,然後後面都是呼叫這個函式與optee進行通訊,獲取到optee的系統資訊,下面就對這個函式如何與optee進行通訊做出說明。
Invoke_fn函式實際上獲取的是optee_smccc_smc函式,函式實現如下
/* * Wrap c macros in asm macros to delay expansion until after the * SMCCC asm macro is expanded. */ /*SMCCC_SMC巨集,觸發smc*/ .macro SMCCC_SMC __SMC(0) .endm /*SMCCC_HVC巨集,觸發hvc*/ .macro SMCCC_HVC __HVC(0) .endm /* 定義SMCCC巨集,其引數為instr */ .macro SMCCC instr /* 將normal world中的暫存器入棧,儲存現場 */ UNWIND( .fnstart) mov r12, sp /* r12指向老的sp地址 */ push {r4-r7} /* 推r4 - r7入棧,則sp = sp - 4 * 4 */ UNWIND( .save {r4-r7}) ldm r12, {r4-r7} /* 把r12指向的內容的刷入r4 - r7,其實就是把引數a4 - a7存入r4 - r7 \instr /* 執行instr引數的內容,即執行smc切換 */ pop {r4-r7} /* 出棧操作,恢復現場 */ ldr r12, [sp, #(4 * 4)] stm r12, {r0-r3} bx lr UNWIND( .fnend) .endm /* * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, * unsigned long a3, unsigned long a4, unsigned long a5, * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) */ ENTRY(arm_smccc_smc) SMCCC SMCCC_SMC ENDPROC(arm_smccc_smc)
由於例子中是arm32的平臺,因此呼叫約定滿足ATPCS呼叫約定。由於smccc_smc函式的入參有9個引數,因此在執行instr前的一些操作後,暫存器和棧空間分佈如下。
res |
a7 |
a6 |
a5 |
a4 |
r7 |
r6 |
r5 |
r4 |
<- r12
<- sp
r0=a0, r1=a1, r2=a2, r3=a3, r4=a4, r5=a5, r6=a6, r7=a7