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

猜你喜欢

转载自blog.csdn.net/orlando19860122/article/details/85529476