manhuami2007 发表于 2023-1-3 17:57

[ ST NUCLEO-U575ZI-Q 测评] 5-TrustZone模式下-将安全区代码注册到非安全区

<div class='showpostmsg'><p>上一个帖子说的是非安全区调用安全区的代码,这个帖子反过来了,说的是安全区调用非安全区的代码。</p>

<p data-line="99" dir="auto">因为安全区是可以通过绝对地址访问非安全区的函数的。但是非安全区函数的绝对地址不容易获取或者容易更改。因此我们可以使用函数指针的形式指向非安全区对应的函数。</p>

<p data-line="101" dir="auto">那么是如何将非安全区的函数赋值给安全区的函数指针呢?可以通过注册函数的形式获取非安全区的函数地址。</p>

<h4 data-line="102" dir="auto" id="1e4bba3e7a081e5ad98e694bee4bd8de7bdaee4b88ee789b9e782b9-1">1.代码存放位置与特点</h4>

<p data-line="104" dir="auto">这个注册函数也是在&quot;secure_nsc.c&quot;文件中,代码如下所示。可以看到也是需要添加<strong>CMSE_NS_ENTRY</strong>前缀的。因为这个函数要在非安全区进行调用来注册非安全区的函数,被调用的非安全区的函数是作为第2个参数的。这样就可以将函数赋值给NSC区的一个指针。然后通过指针可以调用对应的函数。注意第二个参数的类型是void的指针类型,这个指针在这里还不需要指定成真正的函数指针类型,而是在调用这个指针的时候才会强制转换成真正的函数指针类型。</p>

<pre>
<code class="language-cpp">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;
    }
}
}</code></pre>

<p data-line="130" dir="auto">下面的代码为在非安全区调用上面的注册函数,注册相应的非安全区函数到安全区的函数指针处。</p>

<pre>
<code class="language-cpp">SECURE_RegisterCallback(SECURE_FAULT_CB_ID, (void *)SecureFault_Callback);</code></pre>

<h4 data-line="136" dir="auto" id="2%E5%9C%A8%E5%AE%89%E5%85%A8%E5%8C%BA%E8%B0%83%E7%94%A8%E6%B3%A8%E5%86%8C%E5%90%8E%E7%9A%84%E5%87%BD%E6%95%B0">2.在安全区调用注册后的函数</h4>

<p data-line="138" dir="auto">安全区的代码调用非安全区代码时,使用的汇编指令是BLXNS。在安全状态向非安全状态切换时,返回地址和一些运行状态需要压入安全区的堆栈中,以防止泄露给非安全区,并且要将LR寄存器设置成FNC_RETURN的特殊值,这个目的应该是为了当函数返回时,告知CPU是从非安全区返回的。当然这些操作不用使用者进行操作,而是由编译器进行的。用户通过关键字<strong>cmse_nsfptr_create</strong>告知编译器执行上面的操作。除了这个关键字,还有一个关键字是要用到的,<strong>CMSE_NS_CALL</strong>,这个关键字与上一个帖子里,安全区函数的入口函数关键字<strong>CMSE_NS_ENTRY</strong>是相对的。<strong>CMSE_NS_CALL</strong>是声明为非安全区的入口函数。</p>

<p data-line="140" dir="auto">调用非安全区函数的代码如下:</p>

<pre>
<code class="language-cpp">/*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();
}</code></pre>

<p data-line="157" dir="auto">前两行的typedef是在main.h中定义好的,这个指定了函数指针真正的原型,可以看到下面的代码用这个类型对(void *)的那个指针进行了强制类型转化。最后一行的callback_NS()就调用了非安全区的代码。</p>

<h4 data-line="160" dir="auto" id="3%E5%AE%89%E5%85%A8%E5%8C%BA%E8%B0%83%E7%94%A8%E9%9D%9E%E5%AE%89%E5%85%A8%E5%8C%BA%E7%9A%84%E5%87%BD%E6%95%B0%E8%83%BD%E5%90%A6%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0%E5%92%8C%E8%8E%B7%E5%8F%96%E8%BF%94%E5%9B%9E%E5%80%BC">3.安全区调用非安全区的函数,能否传递参数和获取返回值</h4>

<p data-line="162" dir="auto">同上一个帖子一样,两者之间只能通过通用寄存器R0-R3传递参数。过多的参数会放入栈中,使得函数无法使用,因为栈顶指针是无法从安全区传递到非安全区的。</p>

<p data-line="164" dir="auto">返回值是放在R0寄存器中的,也是可以传递回来的。</p>

<p data-line="166" dir="auto">但是不像上一个帖子中非安全区调用安全区函数那样,将指针以参数的形式传递给被调函数时,是无法使用的。因为指针指向的是安全区的内存,这个是非安全区所不能访问的。那么如何传递大量的数据呢?可以迂回一下,再在安全区注册一个缓存区的指针,指向非安全区的一块区域,然后通过这个指针操作非安全区的数据,并把这个指针传递给被调函数。这样非安全区的代码访问的还是非安全区的数据,就可以了。</p>

<p data-line="168" dir="auto">至此安全区和非安全区之间的交互方式就学习完了,这个交互包括函数的交互,也包括数据的交互。下一个帖子,分享一下TrustZone工程的启动流程。</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

lugl4313820 发表于 2023-1-3 20:27

感谢分享!

okhxyyo 发表于 2023-1-12 09:22

<p>测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html</p>
页: [1]
查看完整版本: [ ST NUCLEO-U575ZI-Q 测评] 5-TrustZone模式下-将安全区代码注册到非安全区