上一个帖子说的是非安全区调用安全区的代码,这个帖子反过来了,说的是安全区调用非安全区的代码。
因为安全区是可以通过绝对地址访问非安全区的函数的。但是非安全区函数的绝对地址不容易获取或者容易更改。因此我们可以使用函数指针的形式指向非安全区对应的函数。
那么是如何将非安全区的函数赋值给安全区的函数指针呢?可以通过注册函数的形式获取非安全区的函数地址。
1.代码存放位置与特点
这个注册函数也是在"secure_nsc.c"文件中,代码如下所示。可以看到也是需要添加CMSE_NS_ENTRY前缀的。因为这个函数要在非安全区进行调用来注册非安全区的函数,被调用的非安全区的函数是作为第2个参数的。这样就可以将函数赋值给NSC区的一个指针。然后通过指针可以调用对应的函数。注意第二个参数的类型是void的指针类型,这个指针在这里还不需要指定成真正的函数指针类型,而是在调用这个指针的时候才会强制转换成真正的函数指针类型。
void *pSecureFaultCallback = NULL;
void *pSecureErrorCallback = NULL;
CMSE_NS_ENTRY void SECURE_RegisterCallback(SECURE_CallbackIDTypeDef CallbackId, void *func)
{
if(func != NULL)
{
switch(CallbackId)
{
case SECURE_FAULT_CB_ID: /* SecureFault Interrupt occurred */
pSecureFaultCallback = func;
break;
case GTZC_ERROR_CB_ID: /* GTZC Interrupt occurred */
pSecureErrorCallback = func;
break;
default:
/* unknown */
break;
}
}
}
下面的代码为在非安全区调用上面的注册函数,注册相应的非安全区函数到安全区的函数指针处。
SECURE_RegisterCallback(SECURE_FAULT_CB_ID, (void *)SecureFault_Callback);
2.在安全区调用注册后的函数
安全区的代码调用非安全区代码时,使用的汇编指令是BLXNS。在安全状态向非安全状态切换时,返回地址和一些运行状态需要压入安全区的堆栈中,以防止泄露给非安全区,并且要将LR寄存器设置成FNC_RETURN的特殊值,这个目的应该是为了当函数返回时,告知CPU是从非安全区返回的。当然这些操作不用使用者进行操作,而是由编译器进行的。用户通过关键字cmse_nsfptr_create告知编译器执行上面的操作。除了这个关键字,还有一个关键字是要用到的,CMSE_NS_CALL,这个关键字与上一个帖子里,安全区函数的入口函数关键字CMSE_NS_ENTRY是相对的。CMSE_NS_CALL是声明为非安全区的入口函数。
调用非安全区函数的代码如下:
/*main.h*/
typedef void CMSE_NS_CALL (*funcptr)(void);
typedef funcptr funcptr_NS;
/*stm32u5xx_it.c*/
funcptr_NS callback_NS;
if(pSecureErrorCallback != (funcptr_NS)NULL)
{
/* return function pointer with cleared LSB */
callback_NS = (funcptr_NS)cmse_nsfptr_create(pSecureErrorCallback);
callback_NS();
}
前两行的typedef是在main.h中定义好的,这个指定了函数指针真正的原型,可以看到下面的代码用这个类型对(void *)的那个指针进行了强制类型转化。最后一行的callback_NS()就调用了非安全区的代码。
3.安全区调用非安全区的函数,能否传递参数和获取返回值
同上一个帖子一样,两者之间只能通过通用寄存器R0-R3传递参数。过多的参数会放入栈中,使得函数无法使用,因为栈顶指针是无法从安全区传递到非安全区的。
返回值是放在R0寄存器中的,也是可以传递回来的。
但是不像上一个帖子中非安全区调用安全区函数那样,将指针以参数的形式传递给被调函数时,是无法使用的。因为指针指向的是安全区的内存,这个是非安全区所不能访问的。那么如何传递大量的数据呢?可以迂回一下,再在安全区注册一个缓存区的指针,指向非安全区的一块区域,然后通过这个指针操作非安全区的数据,并把这个指针传递给被调函数。这样非安全区的代码访问的还是非安全区的数据,就可以了。
至此安全区和非安全区之间的交互方式就学习完了,这个交互包括函数的交互,也包括数据的交互。下一个帖子,分享一下TrustZone工程的启动流程。