TrustZone中Secure和Non-Secure模式的切换

ARMv8-M的TrustZone支持Secure和Non-Secure模式的直接切换。以下几个汇编指令是状态切换中要用到的比较重要的指令:

指令描述
SGSecure Gateway是状态切换的第一条指令
BXNS用于安全模式切换到非安全模式
BLXNS用于安全模式下的非安全函数调用

一下是状态切换的一个框图:

状态切换

从非安全模式下调用安全模式函数也是允许的,不过entry point的第一条指令必须是SG指令,并且这条SG指令必须在Non-Secure callable区域。

Non-Secure下Secure Call流程

如果Non-Secure程序调用了一个Secure API,API通过BXNS指令返回。如果Non-Secure程序尝试分支(跳转)或者在没有有效entry point的情况下发起一个调用,那么将会产生一个异常。ARMv8-M中Secure异常为SecureFault。

ARMv8-M的TrustZone允许Secure程序调用Non-Secure函数。这种情况下,Secure程序通过BLXNS指令调用Non-Secure软件。这个过程中,返回地址和处理器信息被曝存在一个Secure堆栈中,程序的链接寄存器(Link Register LR)也会设置成一个特殊的值FNC_RETURN,函数地址的最低位必须是0.

下面的流程就是一个Secure程序执行Non-Secure调用的一个流程:

Secure Program call Non-Secure Program

Non-Secure程序执行完成之后会通过RNC_RETURN地址进行跳转,这个操作会触发安全堆栈里面的内容出栈,处理器得到真正的返回地址,实现函数返回。这个过程中状态的转换时隐性的,并且会隐藏真正的返回地址。Secure软件可以向调用中传递参数信息,并可以在调用之前清除必要的Secure数据。

状态转换可以在异常和中断中执行。每个中断可以配置为Secure或者Non-Secure中断,具体的类型通过Interrupt Target Non-Secure(NVIC_INTS)寄存器配置,这个寄存器只能在Secure状态下修改。而不同种类的中断的发生和当前处理器所处的状态无关。

不同类型中断

如果中断产生的时候,CPU的状态和中断类型相同,那么中断的流程和普通的M-系列CPU的中断流程类似,依然具有低延迟的特性。而当处理器运行在Secure模式的时候,产生了Non-Secure中断,这个时候中断处理和普通的中断处理差别较大。

在这种情况下,处理器会将所有Secure相关信息压栈,并会清空寄存器中的数据,防止数据意外泄露。

所有中断相关的特性,比如中断嵌套,中断向量,中断向量表重定义都是支持的。并且TrustZone中依然会保留低延迟的中断特性。不过在Secure模式下触发Non-Secure中断的时候,延迟会有所增加,这主要是要将一些安全数据压栈导致的。

增强型的中断处理可以采用浮点单元(Floating-Point Unit FPU)中的Lazy stacking寄存器,lazy stacking可以降低中断延迟。因为不需要将FPU中的寄存器压栈,除非中断处理程序中也要用到FPU。在ARMv8-M中可以采用同样的形式降低中断延迟。

处理器的Secure状态

简单来说,当前程序的PC地址决定了当前处理器的状态。

  • 如果PC在Non-Secure空间,那么处理器就在Non-Secure状态
  • 如果PC在Secure空间,那么处理器就在Secure状态
  • 如果处理器在Secure状态,那么它必须从Secure内存取指令

ARMv8-M架构支持程序在Secure和Non-Secure之间的调用和跳转。唯一的限制是Non-Secure调用Secure的时候必须有一个有效的Entry Point。

注意:在一些特定的例子里面,当从Non-Scure切换到Secure模式的时候,第一条指令必须是SG指令,并且当SG指令执行的时候,处理器必须处于Non-Secure状态。

设计特点

ARMv8-M中TrustZone的设计具有以下一些特点:

  • Non-Secure调用Secure函数的时候,必须通过有效的Entry Point,但是Entry Point的数量并没有限制。
  • 状态转换的代价比较低,当从Non-Secure转换到Secure状态时候只多了一条SG指令,而从Secure状态转换到Non-Secure状态的时候也只是多了几个时钟
  • 在运行Secure代码的时候依然可以处理Non-Secure中断,处于安全考量,进入中断的时候需要将必要的数据压栈
  • 系统默认从Secure模式启动,启动代码会初始化一个信任链,这个过程也称为Secure boot
  • 低功耗:系统设计并不需要区分Secure和Non-Secure CPU寄存器,并且还可以有效防止Non-Secure中断窥探Secure模式的数据。
  • 简单易用:中断处理函数还是C风格,Non-Secure对Secure的API调用是标准的C/C++函数调用
  • 高扩展性:设计允许Secure调用Non-Secure函数,因为Secure模式一般还要访问Non-Secure模式下的驱动代码,Secure模式下也还是有特权和非特权两种权限,因此可以提供非常灵活的配置。

相关文章

发表新评论