当前位置:   article > 正文

ARMv8-M Trustzone实操_trustzone工程擦鞋flash需要disable icache

trustzone工程擦鞋flash需要disable icache

前言

本文针对ARMv8m架构M23/M33 MCU安全特性使用进行介绍,以nxp LPC55xx系列和STM32L5xx系列为例,为大家阐述如何使用Trustzone技术提高物联网设备安全性,适合有一定平台安全基础的物联网设备开发人员、安全方案开发人员。
在这里插入图片描述

背景

为了提升平台安全性,ARM推出了ARMv8m架构,该架构引入了Trustzone安全扩展,该技术主要利用隔离技术将地址空间划分安全和非安全区域,实现了空间隔离,这里我们称之为安全世界和非安全世界,两个世界的切换/交互通过指令集增加的几条指令实现(SG/BXNX/BLXNX)。该架构主要包括两个系列产品,以m23为代表的baseline产品以及以m33以为代表的mainline产品,前者可以认为是m0的安全版本,后者是m3/m4的安全版本。因为本文主要目的是实操,所以Trustzone具体技术知识不展开讲述。

现状

市面上已经有多家芯片厂商推出了m23/m33内核的MCU产品

厂商型号
NXP 恩智浦LPC55xx
ST 意法STM32L5xx
Nuvoton 新塘M2351
Microchip 微芯SAM L10/L11
Renesas 瑞萨RA2x
NordicNRF5340
Dialog 戴泺格DA1469x
ADI 亚德诺----
Silicon Labs 芯科zhanGecko Series 2
紫光展锐(原RDA)春藤v5663
GigaDevice 兆易创新GD32E232

这气势不亚于当年的cortex m0/m3/m4,因为大家知道安全是制约物联网规模的重要原因之一,而armv8m中的trustzone能够解决设备中大部分安全问题。

安全目标

利用这些芯片我们可以实现哪些安全目标?

安全目标方法
密钥安全安全世界密钥存储区无法被非安全世界的非法软件直接读取
算法安全关键算法可以放在安全世界来防止运行时篡改
外设保护外设可以放进安全世界来防止数据的原始数据的篡改

实操LPC55xx

设置安全属性单元SAU

/* SAU region boundaries */
#define REGION_0_BASE 0
#define REGION_0_END 0x0FFFFFFFU
#define REGION_1_BASE 0x20000000U
#define REGION_1_END 0xFFFFFFFFU
#define REGION_2_BASE 0x1000FE00U
#define REGION_2_END 0x1000FFFFU
    /* 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

SAU IDAU定义
根据代码设置和SAU/IDAU规则可以看出,我们将4G空间按照256M大小以此划分为非安全/安全交替的地址,相邻的256M空间映射到同一个物理器件,这种技术成为alias技术,安全世界可以使用安全地址访问硬件,而非安全世界可以使用对应的安全地址访问硬件,驱动程序无需修改。硬件是否允许访问,取决于MPC/PPC等设置。另外0x1000FE00U处预留了512字节的非安全可调用区域,用来存放跳板函数(veneer entry)。

设置存储器保护控制器MPC
LPC55xx通过AHB Secure Controller来设置ROM/FLASH/SRAM安全属性

	/*设置前64KB flash为安全属性*/
    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_FLASH_MEM_RULE[1] = 0;
    AHB_SECURE_CTRL->SEC_CTRL_FLASH_ROM[0].SEC_CTRL_FLASH_MEM_RULE[2] = 0;
    
    /*设置ROM为非安全属性*/
    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;

	/*设置前128KB SRAM为安全属性*/
    AHB_SECURE_CTRL->SEC_CTRL_RAMX[0].MEM_RULE[0]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM0[0].MEM_RULE[0]                     = 0x33333333U;
    AHB_SECURE_CTRL->SEC_CTRL_RAM0[0].MEM_RULE[1]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM1[0].MEM_RULE[0]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM1[0].MEM_RULE[1]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM2[0].MEM_RULE[0]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM2[0].MEM_RULE[1]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM3[0].MEM_RULE[0]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM3[0].MEM_RULE[1]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_RAM4[0].MEM_RULE[0]                     = 0;
    AHB_SECURE_CTRL->SEC_CTRL_USB_HS[0].MEM_RULE[0]                   = 0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

这样设置后,我们可以将安全代码链接到0x1000 0000处,大小限制64KB,数据链接到0x3000 0000处,大小限制128KB;非安全代码链接到0x0001 0000处,大小限制567KB.

设置外设保护控制器PPC

    //--- 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_AHB0_0_SLAVE_RULE                            = 0x03000000U;
    AHB_SECURE_CTRL->SEC_CTRL_AHB0_1_SLAVE_RULE                            = 0;
    AHB_SECURE_CTRL->SEC_CTRL_AHB1_0_SLAVE_RULE                            = 0;
    AHB_SECURE_CTRL->SEC_CTRL_AHB1_1_SLAVE_RULE                            = 0;
    AHB_SECURE_CTRL->SEC_CTRL_AHB2[0].SEC_CTRL_AHB2_0_SLAVE_RULE           = 0;
    AHB_SECURE_CTRL->SEC_CTRL_AHB2[0].SEC_CTRL_AHB2_1_SLAVE_RULE           = 0;
    AHB_SECURE_CTRL->SEC_GPIO_MASK0 = 0xFFFFFFFFU;
    AHB_SECURE_CTRL->SEC_GPIO_MASK1 = 0xFFFFFFFFU;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

设置flexcomm、iocon、syscon外设为安全属性,其他为非安全属性,flexcomm用来安全世界串口打印,iocon用来设置端口、syscon用来设置模块上下电。

设置中断安全属性TZIC

    NVIC->ITNS[0] = 0;
    NVIC->ITNS[1] = 0;
  • 1
  • 2

设置所有IRQ中断属性为非安全属性。

非安全世界访问安全世界函数

/* Non-secure callable (entry) function, calling a non-secure callback function */
__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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

这是一个在安全世界实现的字符串比较代码,通过cmse_nonsecure_entry attribute属性来提示编译器在非安全可调用区域(上面SAU配置过)生成跳板,跳板也很简单,每个跳板有两条32位指令组成:

sg
bx StringCompare_NSE
  • 1
  • 2

上面预留了512个字节,能够存放64个跳板函数,跳板相关的链接脚本如下:

#define  m_veneer_table_start          0x1000FE00U
#define  m_veneer_table_size           0x200
LR_m_veneer_table m_veneer_table_start m_veneer_table_size {
  ER_m_veneer_table m_veneer_table_start m_veneer_table_size {; veneer table
    *(Veneer$$CMSE)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

所以非安全世界要想访问安全世界函数很简单,只需要将函数设置为cmse_nonsecure_entry 属性即可。值得注意的是,由于跳板函数只能通过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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

callback是非安全世界函数地址,通过cmse_nsfptr_create函数将其转换为cmse_nonsecure_call属性的函数,这样编译器会将调用指令有blx替换成blxnx,触发安全世界的切换。

值得注意的问题

  1. A0版本芯片不要开secure boot,不要写prince key
  2. A0版本PFR驱动和ROM不一致
  3. Hashcrypt设置为安全后需要lock才能生效
  4. 使用flash驱动时需要将ROM对应区域划分为安全
  5. 使用最新的sdk(目前为2.7.1,对应keil DFP 12.1.1)

以上是LPC55xx平台安全属性配置以及两个世界的交互介绍,这些只是我们开发过程中比较简单的一部分,更深层次的使用问题可以在留言区留言

实操STM32L5

SAU设置

/*NSC FLASH 8KB*/
#define SAU_INIT_START0     0x0C03E000      
#define SAU_INIT_END0       0x0C03FFFF    
 
/*NS FLASH 256KB*/ 
#define SAU_INIT_START1     0x08040000
#define SAU_INIT_END1       0x0807FFFF

/*NS SRAM 160KB*/
#define SAU_INIT_START2     0x20018000      
#define SAU_INIT_END2       0x2003FFFF   

/*Peripheral NSalias*/   
#define SAU_INIT_START3     0x40000000       
#define SAU_INIT_END3       0x4FFFFFFF    

/*FMC&OCTOSPI NS*/  
#define SAU_INIT_START4     0x60000000      
#define SAU_INIT_END4       0x9FFFFFFF   

/*SYSTEM MEMORY NS*/    
#define SAU_INIT_START5     0x0BF90000       
#define SAU_INIT_END5       0x0BFA8FFF       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

配置寄存器和LPC平台相同,只是区域不同,和下图IDAU配合,完成安全属性配置
在这里插入图片描述
设置存储器保护控制器MPC
STM32L5通过MPCBB设置MPC

  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[12] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[13] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[14] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[15] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[16] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[17] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[18] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[19] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[20] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[21] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[22] = 0x00000000U;
  MPCBB_desc.AttributeConfig.MPCBB_SecConfig_array[23] = 0x00000000U;

  if (HAL_GTZC_MPCBB_ConfigMem(SRAM1_BASE, &MPCBB_desc) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

设置0x2001 8000开始,160KB SRAM为非安全,MPCBB_SecConfig_array每个bit表示256Byte的安全属性,1表示安全,0表示非安全。

FLASH安全属性设置可以通过

HAL_GTZC_TZSC_MPCWM_ConfigMemAttributes()
  • 1

设置,整个bank的安全属性也可以通过工具设置option bytes的SECWM2_PSTRT > SECWM2_PEND

设置外设保护控制器PPC

   if (HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_USART3, GTZC_TZSC_PERIPH_PRIV | GTZC_TZSC_PERIPH_NSEC) != HAL_OK)
   {
    /* Initialization error */
     while(1);
   }

  HAL_GPIO_ConfigPinAttributes(BUTTON_USER_GPIO_PORT, BUTTON_USER_PIN, GPIO_PIN_NSEC);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过上面接口,实现了外设和端口安全属性的设置。

设置中断属性控制器TZIC
与LPC55xx相同

安全世界和非安全世界交互
与LPC55xx相同

值得注意的问题

  1. STM32L5 iCache是一个读cache,写flash不走icache,所以如果读取了flash,然后再写,会导致cache和flash内容不一致,需要invalidate
  2. RCC_CR priv位,手册上说在TZEN=1,SECCFGR为非0时,非安全世界写该位会导致IAL异常,实际并不会,只是silent failure

以上是STM32L5xx平台安全属性配置以及两个世界的交互介绍,这些只是我们开发过程中比较简单的一部分,更深层次的使用问题可以在留言区留言

持续更新中,感兴趣请关注收藏

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/92005
推荐阅读
相关标签
  

闽ICP备14008679号