1. 程式人生 > >OPTEE學習筆記 - 驅動的載入和初始化(CA和TA通訊)

OPTEE學習筆記 - 驅動的載入和初始化(CA和TA通訊)

驅動的載入和初始化可以參考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