You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
FUNC thread_vector_table , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
b vector_std_smc_entry //OP-TEE中处理标准smc请求
b vector_fast_smc_entry //OP-TEE中处理快速smc
b vector_cpu_on_entry //OP-TEE中处理cpu on操作
b vector_cpu_off_entry //OP-TEE中处理cpu off操作
b vector_cpu_resume_entry //OP-TEE中处理resume操作
b vector_cpu_suspend_entry //OP-TEE中处理cpu suspend操作
b vector_fiq_entry //OP-TEE中处理处理快速中断操作
b vector_system_off_entry //OP-TEE中处理系统off操作
b vector_system_reset_entry //OP-TEE中处理系统重启操作
UNWIND( .fnend)
END_FUNC thread_vector_table
LOCAL_FUNCvector_std_smc_entry , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
push {r0-r7} //将参数入栈movr0, sp//将栈指针赋值给r0寄存器blthread_handle_std_smc//调用处理函数,参数的地址存放在r0寄存器中/* * 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. */pop {r1-r8} //出栈操作ldrr0, =TEESMC_OPTEED_RETURN_CALL_DONE//标记OP-TEE处理完成smc #0//调用smc切回到normal worldb . /* SMC should not return */UNWIND( .fnend)
END_FUNCvector_std_smc_entry
函数thread_handle_std_smc的内容如下:
voidthread_handle_std_smc(structthread_smc_args*args)
{
/* 检查堆栈 */thread_check_canaries();
if (args->a0==OPTEE_SMC_CALL_RETURN_FROM_RPC)
//处理由tee_supplican回复的RPC请求处理结果thread_resume_from_rpc(args);
else//处理来自Libteec的请求,主要包括open session, close session, invoke等thread_alloc_and_run(args);
}
FUNCthread_std_smc_entry , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
/* Pass r0-r7 in a struct thread_smc_args */push {r0-r7} //入栈操作,将r0~r7的数据入栈movr0, sp//将r0执行栈地址作为参数传递給__thread_std_smc_entrybl__thread_std_smc_entry//正式对标准smc进行处理/* * Load the returned r0-r3 into preserved registers and skip the * "returned" r4-r7 since they will not be returned to normal * world. */pop {r4-r7}
addsp, #(4*4)
/* Disable interrupts before switching to temporary stack */cpsidaif//关闭中断blthread_get_tmp_sp//获取堆栈movsp, r0//将r0的值存放到sp中blthread_state_free//释放threadldrr0, =TEESMC_OPTEED_RETURN_CALL_DONE//设置返回到normal的r0寄存器的值movr1, r4movr2, r5movr3, r6movr4, r7smc #0//调用smc,切回到normal worldb . /* SMC should not return */UNWIND( .fnend)
END_FUNCthread_std_smc_entry
10_OPTEE-OS_内核之(二)对安全监控模式的调用的处理
来自正常世界状态(NWS)的安全监控模式调用(smc)最终都会使用OP-TEE提供的处理接口进行处理,而该处理接口中的内容在OP-TEE启动过程中会被初始化。ARM官方将安全监控模式调用的类型分为两个大类:快速安全监控模式调用(fast smc)和标准安全监控模式调用(std smc),使用不同的SMC ID来表示,关于SMC ID的含义和设置,可参阅09_OPTEE-OS_内核之(一)ARM核安全态和非安全态的切换。ARMv7或者ARMv8中都使用smc汇编指令来使ARM核陷入Monitor模式或者EL3阶段,Monitor模式或者EL3判定安全状态位(NS bit)后会设置对应的运行上下文,然后退出Monitor模式或者EL3阶段,再跳转到OP-TEE中使用特定的处理接口作进一步处理。
1. OP-TEE的线程向量表
OP-TEE中会定义一个线程向量表
thread_vector_table
,该线程向量表会被Monitor模式或者EL3使用。关于线程向量表和全局处理变量的内容可参阅 14_OPTEE-OS_内核之(六)线程管理与并发。
在OP-TEE中用于处理各种来自外部或者的monitor模式请求的入口函数都存放在OP-TEE的线程向量表thread_vector_table中。该项量的实现在
optee_os/core/arch/arm/kernel/thread_a32.S
文件中。其内容如下:注意:该
线程向量表
与OP-TEE的中断处理向量表thread_vect_table
是不一样的。thread_vector_table
属于线程级别,会被monitor模式或者其他中断处理函数调用到,而thread_vect_table
才是OP-TEE存放在VBAR寄存器中的中断向量表。当在secure world状态下产生了FIQ事件时,将会调用中断向量表thread_vect_table中的FIQ中断处理函数,然后才会调用到thread_vector_table中给的vector_fiq_entry来执行FIQ的后续处理。2. ARMv7中Monitor模式对安全监控模式的调用的处理
当在正常世界状态或者安全世界状态中触发了安全监控模式调用后,在ARMv7架构中ARM核会切换到Monitor模式,且从MVBAR寄存器中获取到异常向量表的基地址,然后查找到对安全监控模式调用的处理函数——sm_smc_entry,使用该函数来完成对安全监控模式调用的处理。在处理过程中会判定该安全监控模式调用来自正常世界状态还是安全世界状态,如果触发该安全监控模式调用是正常世界状态,则会调用smc_from_nsec函数进行处理,然后再根据SMC ID判定该安全监控模式调用的类型做进一步处理。在Monitor模式中对安全监控模式调用的处理过程如图所示。
libteec和tee_supplicant调用接口之后最终会调用到OP-TEE驱动来触发对应的SMC操作。在OP-TEE驱动中触发SMC操作的方法是调用
arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res)
来实现,其中在REE端需要传递給TEE侧的数据被存放在a0~a7
中。调用上述函数自后,CPU中的cortex就会切换到monitor模式,进入monitor模式之后首先会去获取MVBAR寄存器
中存放的monitor模式的中断向量表地址
,然后查找monitor模式的中断向量表,命中smc的处理函数。进入到处理函数之后再根据从REE侧带入的参数判定是进行
快速smc处理
还是标准的smc处理
。关于monitor模式下如何实现normal world到secure world之间的切换过程请参考文章09_OPTEE-OS_内核之(一)ARM核安全态和非安全态的切换。在REE端触发smc请求之后在monitor的处理流程如下图所示:ARMv7架构通过Monitor模式来实现正常世界状态到安全世界状态之间的切换,并根据不同的SMC ID来判定当前安全监控模式调用是快速安全监控模式调用(fast smc)还是标准安全监控模式调用(std smc),然后通过查找线程向量表进入到fast smc和std smc的处理函数,在各自的处理函数中最终会调用OP-TEE中的全局handler变量中对应的函数指针来实现对该安全监控模式调用的具体处理。当程序运行到sm_from_nsec的时候就已经完成了normal world与secure world的切换,从该函数开始就进入到了OP-TEE的处理范畴。
3. ARMv8中的EL3处理安全监控模式调用的实现
ARMv8架构使用ATF中的bl31来实现安全世界状态与正常世界状态之间的切换,以及安全监控模式调用的第一步处理,bl31运行于EL3,所有的安全监控模式调用在ARMv8架构中都会在EL3先被处理,然后根据不同的TEE方案使用对应的接口进行安全监控模式调用的分发,在分发之前,bl31会设定好ARM核安全状态,保存当前CPU的运行上下文并恢复将要切换到的ARM核状态对应的运行上下文。关于EL3中如何实现正常世界状态与安全世界状态的切换以及如何跳转到OP-TEE中运行,可参阅文章09_OPTEE-OS_内核之(一)ARM核安全态和非安全态的切换。从EL3进入OP-TEE是通过调用OP-TEE在初始化阶段提供的线程向量表来实现的,即EL3在设定CPU运行上下文时会根据SMC ID来判定是进入到vector_std_smc_entry还是vector_fast_smc_entry,在EL3中对安全监控模式调用(smc)的处理流程如图所示。
4. OP-TEE对fast SMC的处理
快速安全监控模式调用(fast smc)一般会在驱动挂载过程中,或需要获取OP-TEE OS版本信息、共享内存配置、Cache信息时被调用。OP-TEE不会使用建立线程的方式对fast smc进行处理,而是在OP-TEE的内核空间调用tee_entry_fast函数对安全监控模式调用(smc)进行处理,并通过再次产生安全监控模式调用(smc)的方式返回最终的处理结果。在OP-TEE中对fast smc的处理过程:
在sm_from_nsec中调用最终会调用到thread_vector_table向量表中的vector_fast_smc_entry函数来对fast smc进行处理。该函数使用汇编实现,定义在
optee_os/core/arch/arm/kernel/thread_a32.S
中,其内容如下:fast smc被处理完成后会重新触发安全监控模式调用:
TEESMC_OPTEED_RETURN_CALL_DONE
分支,执行保存安全世界状态上下文、恢复正常世界状态上下文,并将返回的数据填充到正常世界状态上下文中,然后调用exit_el3退出EL3返回到正常世界状态中继续执行。tee_entry_fast中的内容如下,用户可以根据实际的需求增加。处理函数源码如下。在OP-TEE启动的时候会执行init_handlers操作,该函数的主要作用是将真正的处理函数赋值给各种thread函数指针变量。关于init_handlers函数的调用和处理过程请查阅前期文章。thread_fast_smc_handler_ptr会被赋值成
handlers->fast_smc
,而在vxpress板级中handlers->fast_smc
执行tee_entry_fast函数。该函数内容如下:从上面的函数可以看到,tee_entry_fast会根据不同的command ID来执行特定的操作。使用者也可以在此函数中添加自己需要fast smc实现的功能,只要在REE侧和OP-TEE中定义合法fast smc的command ID并实现具体操作就可以。
5. OP-TEE对std SMC调用的处理
当OP-TEE驱动中触发标准安全监控模式调用(std smc)时:
5.1 用于处理标准smc的向量处理
用于处理标准smc的向量处理函数如下:
函数thread_handle_std_smc的内容如下:
只有在libteec中触发的smc后,需要OP-TEE作出相应的操作后才可能产生来自RPC请求,故先介绍OP-TEE对来自libteec请求部分,主要是对打开session, 关闭close, 调用特定TA的command,取消command等操作。
5.2 对RPC请求返回操作处理
远程处理请求(Remote Procedure Call,RPC)是指OP-TEE需要REE侧协助完成对REE侧资源进行操作的请求。当OP-TEE需要操作REE侧的资源时,OP-TEE会发送RPC类型的安全监控模式调用,REE侧收到来自OP-TEE的RPC请求后,REE侧根据RPC请求的ID进行处理并将处理结果返回给OP-TEE,关于在REE侧如何获取和处理RPC请求可参阅07_OPTEE-OS_系统集成之(五)REE侧上层软件。待REE侧处理完成后,会将处理结果放在OP-TEE驱动设备teepriv0的返回队列中,然后在驱动中触发安全监控模式调用将结果发送到OP-TEE中。OP-TEE驱动产生的安全监控模式调用请求是标准类型的SMC,最终在OP-TEE中会调用thread_resume_from_rpc函数对该请求进行处理。RPC请求的处理过程如图所示:
OP-TEE在发送RPC请求时会带入发送该请求的线程的ID,该ID将会在接收RPC结果时被用于恢复该线程继续执行。关于RPC操作在OP-TEE中的处理过程将会在15_OPTEE-OS_内核之(七)系统调用及IPC机制中详细介绍。
5.3 处理libteec的smc请求
5.3.1 new thread
在07_OPTEE-OS_系统集成之(五)REE侧上层软件一文中介绍了libteec提供给上层使用的所有接口,这些接口调用之后就会就有可能需要OP-TEE进行对应的操作。在monitor模式对这些请求处理之后会进入到OP-TEE中,然后调用thread_alloc_and_run创建一个线程来对请求做专门的处理。而且在处理过成中还有可能TEE与REE侧之间的RPC请求等。thread_alloc_and_run函数的内容如下:
thread_alloc_and_run会建立一个thread,并通过init_regs函数初始化该thread的运行上下文,指定该thread的入口函数以及运行时的参数,初始化完成之后,调用thread_resume启动该线程。thread的运行上下文的配置和初始化在init_regs函数中实现,内容如下:
5.3.2 resume thread
通过init_regs配置完thread的运行上下文之后,通过调用thread_resume函数来唤醒该线程,让其进入到执行状态。resume函数使用汇编来实现,主要是保存一些寄存器状态,指定thread运行在什么模式。
5.3.3 线程入口函数
init_regs的regs.pc中已经指定了该线程被恢复回来后pc指针的值为thread_std_smc_entry。当线程被恢复后就会去执行该函数,进入到处理由调用libteec库中的接口引起的安全监控模式调用(smc)的过程,该入口函数使用汇编实现,内容如下:
在init_regs中的regs.pc中已经制定了该thread被resume回来之后的pc指针为thread_std_smc_entry,当thread被resume之后就会去执行该函数
进入线程后会使用__thread_std_smc_entry函数进行处理,在该函数中会调用在OP-TEE启动过程中初始化的全局handler指针函数来处理标准的安全监控模式调用(std smc),处理完成后该线程资源将会被释放,线程编号将会被重新设定成可用状态等待下次调用。
5.3.4 标准smc请求的handle
在
__thread_std_smc_entry
函数中最终会调用thread_std_smc_handler_ptr来对请求做正式的处理,而thread_std_smc_handler_ptr是在OP-TEE启动的过程中执行init_handlers函数时被初始化成了handlers->std_smc
。而handlers->std_smc
根据不同的板级可能有所不同,在vexpress板级中std_smc的值为tee_entry_std。在tee_entry_std函数中会根据在OP-TEE中填入的cmd值执行不同的分类操作,主要包括打开TA与CA之间的session操作,关闭session操作,CA请求invoke操作,取消invoke操作中特定的cmd操作等,开发者也可以根据实际需求对该部分进行扩展,但是必须保证在REE侧和TEE侧的修改一致。在执行打开session的操作时,根据调用的TA是属于静态TA还是动态TA可能会触发RPC请求,当TA image存放在文件系统中时,在打开session时OP-TEE就会触发RPC请求,请求tee_supplicant从文件系统中读取TA image的内容,并将内容传递给OP-TEE,然后经过对image的校验判定完成TA image的加载操作后才执行open session查找并将该session添加到OP-TEE的全局session的队列中,以便在执行invoke时查询session队列找到对应的session。
6. 总结
本章介绍了OP-TEE中处理快速安全监控模式调用(fast smc)和标准安全监控模式调用(std smc)的详细过程以及由RPC请求和调用libteec库中的接口产生的std smc的处理过程,而对于libteec库产生的std smc进入到tee_entry_std处理之后会根据command ID进行不同的操作,即Open session、close session、invoke command等。open session是invoke command操作的前提,在open session操作中会根据TA的UUID来进行运行上下文的配置,并根据是动态TA还是静态TA配置不同的operation,关于各invoke command的操作将会在12_OPTEE-OS_内核之(四)对TA请求的处理中详细介绍。
The text was updated successfully, but these errors were encountered: