赞
踩
一:概述
为了更好地提高MCU的安全性能,Arm在ARMv8-M架构中引入了TrustZone技术。ARMv8-M中的TrustZone技术是一种可选择的安全扩展,旨在为各种嵌入式系统应用提供基本的安全保障。本文基于CM33核的LPC55sxx系列开发板,MCUXpresso IDE v11.1.1_3241集成开发工具。
二:实现原理
2.1:区域划分
TrustZone将内存和外设分为安全区域(S)和非安全区域(NS),CPU访问S时可认为CPU处于安全状态(CPU-S),访问NS时可认为处于非安全状态(CPU-NS)。
对于内存数据和指令的访问,TrustZone遵循以下规则:
NVIC、MPU、SYSTICK、内核控制寄存器等也被备份到两个区域中 ,安全代码和非安全代码可以独立访问自己的资源,安全区和非安全区都有MSP和PSP堆栈指针。
2.2:Secure/Non-Secure存储器配置
在Cortex-M33中,如果选配了TrustZone技术,则4G的内存空间将被划分为安全和非安全内存区域。安全内存空间又可以进一步划分为两种类型: Secure和Non-secure Callable(NSC)。
三种内存区域的特性:
Secure:安全数据只可以被安全代码访问,安全代码只有在CPU处于安全模式时才可以被执行;
Non-secure:非安全数据可以被安全和非安全状态访问,但非安全代码只能在CPU处于非安全状态时被执行;
Non-secure Callable(NSC):NSC区域作为非安全函数访问安全函数的跳板。非安全代码需要先跳转到NSC区域中,执行SG指令,然后再跳转到相应的的安全函数处执行,这也是NS代码访问S函数的唯一方式。
引入NSC存储区的原因,是为了防止其他二进制数据(例如,具有与SG指令的操作码相同的值的查找表)被用作安全状态的入口函数。
2.3:Secure/Non-Secure转换
系统复位后,CPU处于安全状态。CPU可以通过执行新引入的指令,在安全状态调用非安全状态应用程序的代码:
BXNS:用于从安全状态返回到非安全状态
BLXNS:用于在安全状态下调用非安全函数
SG:它被放置在NSC区域中,是从非安全区跳转到NSC区域后执行的第一条指令。当调用NSC区域时,CPU-NS必须以SG指令为地址。SG指令是CPU-NS能执行的唯一一条指令。当执行该指令时,CPU从CPU-NS切换至NSC区域。如果CPU-NS调用的地址处不是SG指令,会产生一个异常,该异常会让CPU进入安全状态。
这里介绍两种特殊的函数:Entry function和Non-secure function。
Entry function是指那些可以被非安全函数调用的安全函数;
Non-secure function是指那些可以被安全函数调用的非安全函数。
用户在实现两种状态下函数的相互调用时,不需要额外关注该执行哪条特殊指令(SG/BXNS/BLXNS),而只需要将那些被调用的函数定义为Entry function或 Non-secure function即可。下面简单介绍如何定义以及使用Entry function和Non-secure function。
2.3.1:Entry function
Entry function需要用“__attribute__((cmse_nonsecure_entry)) ”属性修饰,举例如下:
此时func1()已经被定义为了entry function,在非安全内存中调用entry function的方法与调用普通的非安全函数的方法是相同的。
2.3.2:Non-secure function call
Non-secure function函数定义如下所示:
在安全内存中的调用non-secure function的方法如下:
这样即可实现在安全函数中调用0x21000248u处的非安全函数。
2.4:内存区域的安全属性定义
内存区域的安全属性是由Secure Attribution Unit(SAU)和Implementation Defined Attribution Unit(IDAU) 共同决定的。
SAU的作用和IDAU是相似的,都是用于分离安全区和非安全区。两者最大的区别是SAU位于CPU内部,IDAU在CPU外部。
无论是IDAU和SAU都可以定义一块内存的安全属性,此时CPU会选择两者中较高的安全属性作为此块内存最终的安全属性,最高的安全属性是Secure,其次是Non-Secure Callable,最后是Non-secure。
2.4.1:IDAU
IDAU对内存的属性定义使用了alisa技术,将相邻的256M空间映射到同一物理器件。LPC55S1x/LPC551x对整个内存的映射如下:
.0x0000 0000 ~ 0x1FFF FFFF:永远NS
.0x2000 0000 ~ 0xFFFF FFFF:如果HADDR[28]=0,NS;如果HADDR[28]=1,S
IDAU除了可以向处理器指示特定存储器地址是Secure、NSC还是Non-secure,提供存储器地址所在的区域编号之外,它还可以标记免受安全检查的内存区域,例如ROM表。
2.4.2:SAU
SAU为每个内存区域定义了一个Region Number(RN)。RN可以被TT(Test Target)指令用来获取目标内存的访问权限和安全属性。RN的数量可以被SAU配置为0、4或者8。
SAU是由设计者配置的,设计者可以在IDAU配置的内存属性的基础上,用SAU去重定义内存中的一些区域的安全属性,CPU会根据IDAU和SAU的配置,决定内存的最终安全属性。其中,0xF000 0000到0xFFFF FFFF范围是固定的安全区域,SAU不能将它设为NSC。
LPC55Sxx复位后,默认的SAU配置是: 所有存储空间都是安全的。结合IDAU的默认配置,LPC55Sxx的最终默认配置如下图所示,即所有内存区域都是安全的。
2.5:Secure AHB bus and secure AHB Controller
CM33 TZ-M实现由IDAU和SAU模块组成,它们根据分配给该地址空间的特定安全属性(S、NS或NSC)过滤来自CPU的地址访问。LPC55S1x/LPC551x使用安全的AHB总线实现第二层保护,以在系统级别支持安全可信执行。
安全的AHB控制器通过checker function为所有总线从设备提供访问策略。在LPC55S1x/LPC551x上的所有主控制器输出安全边带信号HPRIV(特权)和HNONSEC(安全访问)作为给定访问的安全属性的指示。安全AHB总线处理这些信号,并将它们与安全AHB控制器中为从设备设置的安全属性进行比较。如果请求访问的安全属性与从设备的安全属性一致,则授予访问权限。如果在数据或指令访问上发生冲突,则会引发安全违规中断,CPU切换至安全模式并处理该冲突。
如上图所示:AHB控制器的保护有三个部分构成:MSW、MPC、PPC。
2.5.1:MSW(Master Security Wrapper)
Armv8-M CM33 TrustZone使能后提供IDAU功能。然而,IDAU在LPC55S1x/LPC551x上不适用于所有其他主控制器。除了CPU之外,每个AHB主控制器都实现了一个特殊的MSW。
MSW允许应用程序对每个主控制器设置安全属性,如果设置为安全属性,它输出地址时必须保证AHB地址的bit28为1。可以看作MSW起着与IDAU类似的功能。
2.5.2:MPC(Memory Protection Checkers)
在LPC55S1x/LPC551x片上flash,ROM和RAM可以使用内存保护检查器(MPC)保护免受具有较低安全层的应用程序的访问。ROM和每个RAM块有相关联的MPC,Flash有一个MPC。Flash、ROM和每个RAM块被划分为更小的子区域,为安全层分配和过滤提供更多的粒度。
ROM和每个RAM被划分为4Kb的子区域,Flash被划分为32Kb的子区域。每个子区域可以通过在安全的AHB控制器中编程相应的寄存器来划分成单独的安全层。
注:SRAM-1、SRAM-2中的sub-regions count错误,datasheet截图懒得修改。
2.5.3:PPC(Peripheral Protection Checkers)
在LPC55S1x/LPC551x上,AHB从端口上的所有外围设备以及APB桥上的每个外围设备都可以使用外设保护检查器(PPC)保护其免受具有较低层安全性的应用程序的访问。每个AHB端口都有关联的PPC,为安全层分配和过滤提供单个从级的粒度,每个APB桥都有关联的PPC,为每个APB周围的安全层分配和过滤提供粒度。每个外围设备可以通过在安全的AHB控制器中编程相应的寄存器来分配单个安全层。
2.5.4:Secure AHB controller
安全AHB控制器是LPC55S1x/LPC551x上的一个模块,位于内存偏移0x400A-C000处。 它允许对所有MPC,PPC以及MSW进行安全属性编程。
简单的说,AHB起到一个中间层比较的作用,一方面它检测来自CPU和其它控制器等上游发出来的地址的安全属性,另一方面它可以对它下游对应的存储和外设地址进行安全属性设定,同时将这两个安全属性进行比较,判断是否能够进行访问。当检测到安全违规时,安全的AHB控制器模块产生中断。它还记录违规发生时的违规信息(例如在AHB从端口上访问的地址)以及生成的主机的访问类型和安全属性未经授权的访问。
2.6:中断、DMA、GPIO:安全实例和掩码
TrustZone在LPC55S1x/LPC551x上提供安全的NVIC(NVIC_NS)和非安全的NVIC(NVIC_NS)能力。CPU0具有内部可编程性,可以将任何中断配置为安全中断,从而允许NVIC_S在屏蔽NVIC_NS时可以看到它。
LPC55S1x/LPC551x有两个DMA实例,其中DMA0提供23个通道,DMA1提供10个通道。 任一DMA可以作为安全的DMA,选择取决于所选择的相关安全外围设备的DMA需求。为了禁用来自安全外围设备的DMA请求,使其对非安全DMA可见,实现了DMA masking特性。可以使用适当的寄存器编程DMA masking。
所有数字IO引脚状态都可以通过GPIO-HS模块读取,而不使用I/O多路复用器。它可能导致信息泄漏,以防安全外围设备连接到接口。为了保护安全外围设备上的传入数据,在LPC55S1x/LPC551x上实现GPIO masking。 任何对信息泄漏敏感的数字I/O可以在安全的AHB控制器模块中使用偏移量为0xF80-0xF84的SEC_GPIO_MASK0/1寄存器来屏蔽。
此外,LPC55S1x/LPC551x在端口0(0-31)上也有GPIO-HS和GPIO-PINT模块的附加实例。与普通GPIO不同,这个GPIO功能是作为IOMUX功能实现的,并且只有在使用IOCON编程选择时才会使用。 它可以用作安全GPIO,从外部设备获取特定的输入模式,用于安全信令。
3:配置例程
假设设备有64KB的code memory,64KB的data memory和4个外设,code memory为0x0000-0xFFFF或0x1000_0000-0x1000_FFFF,data memory为0x2000_0000-0x2000_FFFF或0x3000_0000-0x3000_FFFF(为了简化,该地址在下图未显示):
在执行信任区配置之前,您必须定义哪些MCU资源(内存和外围设备)将被设为安全资源,哪些资源将被设为非安全资源,这取决于特定的环境。对于本例,可信执行环境定义为:
.第一个32KB的代码内存(0x0000-0x7FFF)是NS-memory
.第二个32KB的代码内存(0x8000-0xFFFF)是S-memory
.前48KB的数据内存(0x2000_0000-0x2000_BFFFF)是NS-memory
.后16KB的数据内存(0x2000_C000-0x2000_FFFF)是S-memory
.SPI和TIMER是安全外设
.UART和ADC是非安全外设
剩余地址空间安全。
当上述配置完成后,MCU资源的可用情况如下表所示:
对于SAU配置我们使用规范的SAU配置,这也是实际应用中最常用的一种方式:
规范的SAU配置只需要两个区域,因此仍然有六个SAU区域可用于其他目的,例如NSC区域定义。配置完成后如下图所示:
接下来进行AHB控制器的配置,安全的AHB控制器在系统级别上实现可信执行保护。存储器和外围保护检查器将MCU资源分配给安全域或非安全域。两个检查器的工作方式相同,不同的是内存保护检查器(MPC)将内存划分为子区域,而外设保护检查器(PPC)将每个独立的外设划分为子区域。 每个内存子区域或外围设备都有自己的安全访问规则,将其分配给特定的安全域/级别。
• "Secure - privilege
• "Secure - non-privilege
• "Non-secure - privilege
• "Non-secure - non-privilege
经过适当的AHB安全控制器配置,信任区被完全隔离隔离。在上图中,非安全软件可将0x8000地址处映射成非安全区域,但是该行为被AHB控制器阻止,因为物理地址0x8000的内存已经被分配到安全域。这意味着安全代码只能通过安全别名(0x1000_8000-0x1000FFFF)访问。内存和外围检查器的另一个效果也是更高的配置灵活性。使用规范的SAU配置,您不受SAU区域数量的限制,且灵活性被增强到内存子区域或者外设的级别。
4:IDE实操
打开IDE的配置工具->TEE,弹出TrustZone的配置页面。在本例中,我们实现从安全世界调用非安全世界中的一个字符串比较函数。单板内存分布如下所示:
0x0000 0000 0x0FFF FFFF Non-secure Code Flash memory, Boot ROM, SRAM X.
0x1000 0000 0x1FFF FFFF Secure Code Flash memory, Boot ROM, SRAM X.
0x2000 0000 0x2FFF FFFF Non-secure Data SRAM 0, SRAM 1, SRAM 2, USB-HS SRAM.
0x3000 0000 0x3FFF FFFF Secure Data SRAM 0, SRAM 1, SRAM 2, USB-HS SRAM.
0x4000 0000 0x4FFF FFFF Non-secure Data AHB and APB peripherals.
0x5000 0000 0x5FFF FFFF Secure Data AHB and APB peripherals
4.1:clean的内存属性图
4.2:配置用户内存区域
我们将安全代码放在0x10000000-0x1000FDFF处,NSC区域放在0x1000FE00-0x1000FFFF处,安全stack和data放在0x30000000-0x30003FFF处,非安全代码放在0x00010000-0x0003FFFF处,非安全stack和data放在0x20004000-0x20007FFF处。实际上就是用了PROGRAM_FLASH和SRAM0的区域。此时的一些警告不用管,全部配置完成后即可解决。配置后如下所示:
4.3:配置SAU
点击启用SAU并配置如下
4.4:配置MPC
对Flash和RAM0进行配置
4.5:中断
将FLEXCOMM0、IOCON、SYSCON配置为S-Priv,FLEXCOMM0用来安全世界串口打印,IOCON用来设置端口、SYSCON用来设置模块上下电。
4.6:其它
引脚本例中不需配置,最后将其它->Misc Controls中的Enable secure check for AHB matrix勾选上:
最后的完成图如下:
点击更新源代码,可生成tzm_config.c和tzm_config.h文件。tam_config.c代码如下:
#include "fsl_common.h"
#include "tzm_config.h"
/* SAU region boundaries */
#define REGION_0_BASE 0
#define REGION_0_END 0x0FFFFFFFU
#define REGION_1_BASE 0x20000000U
#define REGION_1_END 0x5FFFFFFFU
#define REGION_2_BASE 0x1000FE00U
#define REGION_2_END 0x1000FFFFU
void BOARD_InitTrustZone()
{
/*####################################################################
# SAU configuration
###################################################################*/
/* Set SAU Control register: Disable SAU and All Secure */
SAU->CTRL = 0;
/* Set SAU region number */
SAU->RNR = 0;
/* Region base address */
SAU->RBAR = REGION_0_BASE & SAU_RBAR_BADDR_Msk;
/* Region end address */
SAU->RLAR = ((REGION_0_END & SAU_RLAR_LADDR_Msk) | ((0U << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk)) | ((1U << SAU_RLAR_ENABLE_Pos) & SAU_RLAR_ENABLE_Msk);
/* Set SAU region number */
SAU->RNR = 0x00000001U;
/* Region base address */
SAU->RBAR = REGION_1_BASE & SAU_RBAR_BADDR_Msk;
/* Region end address */
SAU->RLAR = ((REGION_1_END & SAU_RLAR_LADDR_Msk) | ((0U << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk)) | ((1U << SAU_RLAR_ENABLE_Pos) & SAU_RLAR_ENABLE_Msk);
/* Set SAU region number */
SAU->RNR = 0x00000002U;
/* Region base address */
SAU->RBAR = REGION_2_BASE & SAU_RBAR_BADDR_Msk;
/* Region end address */
SAU->RLAR = ((REGION_2_END & SAU_RLAR_LADDR_Msk) | ((1U << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk)) | ((1U << SAU_RLAR_ENABLE_Pos) & SAU_RLAR_ENABLE_Msk);
/* Force memory writes before continuing */
__DSB();
/* Flush and refill pipeline with updated permissions */
__ISB();
/* Set SAU Control register: Enable SAU and All Secure (applied only if disabled) */
SAU->CTRL = 0x00000001U;
/*####################################################################
# AHB Configurations
###################################################################*/
/*--------------------------------------------------------------------
- AHB Security Level Configurations
-------------------------------------------------------------------*/
/* Configuration of AHB Secure Controller
* Possible values for every memory sector or peripheral rule:
* 0 Non-secure, user access allowed.
* 1 Non-secure, privileged access allowed.
* 2 Secure, user access allowed.
* 3 Secure, privileged access allowed. */
/* Security level configuration of memories */
AHB_SECURE_CTRL->SEC_CTRL_FLASH_ROM[0].SEC_CTRL_FLASH_MEM_RULE[0] = 0x00000033U;
AHB_SECURE_CTRL->SEC_CTRL_FLASH_ROM[0].SEC_CTRL_ROM_MEM_RULE[0] = 0;
AHB_SECURE_CTRL->SEC_CTRL_FLASH_ROM[0].SEC_CTRL_ROM_MEM_RULE[1] = 0;
AHB_SECURE_CTRL->SEC_CTRL_FLASH_ROM[0].SEC_CTRL_ROM_MEM_RULE[2] = 0;
AHB_SECURE_CTRL->SEC_CTRL_FLASH_ROM[0].SEC_CTRL_ROM_MEM_RULE[3] = 0;
AHB_SECURE_CTRL->SEC_CTRL_RAMX[0].MEM_RULE[0] = 0;
AHB_SECURE_CTRL->SEC_CTRL_RAM0[0].MEM_RULE[0] = 0x00003333U;
AHB_SECURE_CTRL->SEC_CTRL_RAM1[0].MEM_RULE[0] = 0;
AHB_SECURE_CTRL->SEC_CTRL_RAM2[0].MEM_RULE[0] = 0;
AHB_SECURE_CTRL->SEC_CTRL_USB_HS[0].MEM_RULE[0] = 0;
/* Security level configuration of peripherals */
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE0_MEM_CTRL0 = 0x00000033U;
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE0_MEM_CTRL1 = 0;
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE0_MEM_CTRL2 = 0;
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE1_MEM_CTRL0 = 0;
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE1_MEM_CTRL1 = 0;
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE1_MEM_CTRL2 = 0;
AHB_SECURE_CTRL->SEC_CTRL_APB_BRIDGE[0].SEC_CTRL_APB_BRIDGE1_MEM_CTRL3 = 0;
AHB_SECURE_CTRL->SEC_CTRL_AHB_PORT7_SLAVE0_RULE = 0x03000000U;
AHB_SECURE_CTRL->SEC_CTRL_AHB_PORT7_SLAVE1_RULE = 0;
AHB_SECURE_CTRL->SEC_CTRL_AHB_PORT8_SLAVE0_RULE = 0;
AHB_SECURE_CTRL->SEC_CTRL_AHB_PORT8_SLAVE1_RULE = 0;
AHB_SECURE_CTRL->SEC_CTRL_AHB_PORT9[0].SLAVE0_RULE = 0;
AHB_SECURE_CTRL->SEC_CTRL_AHB_PORT9[0].SLAVE1_RULE = 0;
/* Security level configuration of masters */
AHB_SECURE_CTRL->MASTER_SEC_LEVEL = 0x80000000U;
AHB_SECURE_CTRL->MASTER_SEC_ANTI_POL_REG = 0xBFFFFFFFU;
/*--------------------------------------------------------------------
- Pins: Reading GPIO state
-------------------------------------------------------------------*/
/* Possible values for every pin:
* 0b0 Deny
* 0b1 Allow */
AHB_SECURE_CTRL->SEC_GPIO_MASK0 = 0xFFFFFFFFU;
AHB_SECURE_CTRL->SEC_GPIO_MASK1 = 0xFFFFFFFFU;
/*--------------------------------------------------------------------
- Interrupts: Interrupt security configuration
-------------------------------------------------------------------*/
/* Possible values for every interrupt:
* 0b0 Secure
* 0b1 Non-secure */
NVIC->ITNS[0] = 0;
NVIC->ITNS[1] = 0;
/*####################################################################
# Global Options
###################################################################*/
SCB->AIRCR = (SCB->AIRCR & 0x000009FF7U) | 0x005FA0000U;
SCB->SCR &= 0x0FFFFFFF7U;
SCB->SHCSR &= 0x0FFF7FFFFU;
SCB->NSACR = 0;
SCnSCB->CPPWR = 0;
AHB_SECURE_CTRL->SEC_MASK_LOCK = 0x00000AAAU;
AHB_SECURE_CTRL->MASTER_SEC_LEVEL = (AHB_SECURE_CTRL->MASTER_SEC_LEVEL & 0x03FFFFFFFU) | 0x080000000U;
AHB_SECURE_CTRL->MASTER_SEC_ANTI_POL_REG = (AHB_SECURE_CTRL->MASTER_SEC_ANTI_POL_REG & 0x03FFFFFFFU) | 0x080000000U;
AHB_SECURE_CTRL->CPU0_LOCK_REG = 0x800002AAU;
AHB_SECURE_CTRL->MISC_CTRL_REG = (AHB_SECURE_CTRL->MISC_CTRL_REG & 0x0FFFF0003U) | 0x00000AAA4U;
AHB_SECURE_CTRL->MISC_CTRL_DP_REG = 0x0000AAA6U;
}
4.7:代码分析
4.7.1:hello_world_s.c
文件开头定义了非安全代码的存储地址和调用非安全函数的函数指针:
#define DEMO_CODE_START_NS 0x00010000
#define NON_SECURE_START DEMO_CODE_START_NS
/* typedef for non-secure callback functions */
typedef void (*funcptr_ns) (void) __attribute__((cmse_nonsecure_call));
将TrustZone的启动代码添加到初始化流程中:
void SystemInitHook(void)
{
/* The TrustZone should be configured as early as possible after RESET.
* Therefore it is called from SystemInit() during startup. The SystemInitHook() weak function
* overloading is used for this purpose.
*/
BOARD_InitTrustZone();
}
Main函数中进行时钟、串口等初始化之后调用非安全代码中的函数:
int main(void)
{
funcptr_ns ResetHandler_ns;
/* Init board hardware. */
/* attach main clock divide to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
BOARD_InitPins();
BOARD_BootClockPLL150M();
BOARD_InitDebugConsole();
PRINTF("Hello from secure world!\r\n");
/* Set non-secure main stack (MSP_NS) */
__TZ_set_MSP_NS(*((uint32_t *)(NON_SECURE_START)));
/* Set non-secure vector table */
SCB_NS->VTOR = NON_SECURE_START;
/* Get non-secure reset handler */
ResetHandler_ns = (funcptr_ns)(*((uint32_t *)((NON_SECURE_START) + 4U)));
/* Call non-secure application */
PRINTF("Entering normal world.\r\n");
/* Jump to normal world */
ResetHandler_ns();
while (1)
{
/* This point should never be reached */
}
}
4.7.2:veneer_table.c
该文件中定义了非安全世界访问安全世界的函数:
__attribute__((cmse_nonsecure_entry)) uint32_t StringCompare_NSE(volatile callbackptr callback, char const *s1, char const *s2)
{
callbackptr_NS callback_NS;
size_t string_length;
int result;
/* Input parameters check */
/* Check whether function pointer is located in non-secure memory */
callback_NS = (callbackptr_NS)cmse_nsfptr_create(callback);
if (cmse_check_pointed_object((int *)callback_NS, CMSE_NONSECURE) == NULL)
{
PRINTF("The callback is not located in normal world!\r\n");
abort();
}
/* Check whether string is properly terminated */
string_length = strnlen(s1, MAX_STRING_LENGTH);
if ((string_length == MAX_STRING_LENGTH) && (s1[string_length] != '\0'))
{
PRINTF("First string too long or invalid string termination!\r\n");
abort();
}
/* Check whether string is properly terminated */
string_length = strnlen(s2, MAX_STRING_LENGTH);
if ((string_length == MAX_STRING_LENGTH) && (s2[string_length] != '\0'))
{
PRINTF("Second string too long or invalid string termination!\r\n");
abort();
}
PRINTF("Comparing two string as a callback to normal world\r\n");
PRINTF("String 1: ");
PRINTF(s1);
PRINTF("String 2: ");
PRINTF(s2);
result = callback_NS(s1, s2);
return result;
}
该函数通过cmse_nonsecure_entry attribute属性来提示编译器在非安全可调用区域(上面SAU配置过)生成跳板,便可在非安全世界直接调用。值得注意的是,由于跳板函数只能通过R0~R3传递数据(两个世界的栈是独立的),所以跳板函数参数不要超过4个。非安全世界只能通过跳板函数访问安全世界提供的服务。
安全世界可以访问安全世界的资源(数据和代码),但是不能直接执行非安全世界代码,需要通过以下方式调用非安全世界函数:
typedef int (*callbackptr_NS)(char const * s1, char const * s2)
__attribute__((cmse_nonsecure_call));
callbackptr_NS callback_NS;
callback_NS = (callbackptr_NS)cmse_nsfptr_create(callback);
callback_NS(s1, s2);
callback是非安全世界函数地址,通过cmse_nsfptr_create函数将其转换为cmse_nonsecure_call属性的函数,这样编译器会将调用指令有blx替换成blxnx,触发安全世界的切换。
4.7.3:hello_world_ns.c
该文件中即调用安全世界函数StringCompare_NSE:
int main(void)
{
int result;
PRINTF_NSE("Welcome in normal world!\r\n");
PRINTF_NSE("This is a text printed from normal world!\r\n");
result = StringCompare_NSE(&strcmp, "Test1\r\n", "Test2\r\n");
if (result == 0)
{
PRINTF_NSE("Both strings are equal!\r\n");
}
else
{
PRINTF_NSE("Both strings are not equal!\r\n");
}
while (1)
{
}
}
4.7.4:执行打印
Hello from secure world!
Entering normal world.
Welcome in normal world!
This is a text printed from normal world!
Comparing two string as a callback to normal world
String 1: Test1
String 2: Test2
Both strings are not equal!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。