查看: 2504|回复: 1

在LPC55S69-EVK上使用TrustZone详解

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3303

    主题

    6550

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32055
    最后登录
    2024-4-30
    发表于 2020-1-9 11:02:17 | 显示全部楼层 |阅读模式
    在LPC55S69-EVK上使用TrustZone详解


    恩智浦的官方社区(community.nxp.com)为客户提供了一个在线技术支持的平台,在这个平台上客户之间可以互相交流,还可以得到恩智浦专家的答疑解惑。
    本文来自社区里的一个帖子,非常详细地介绍了如何在LPC55S69上使用TrustZone实现安全隔离。
    文末有实操视频

    Arm的TrustZone是Cortex-M33的一个可选的安全特性,它将提高在微控制器上运行的嵌入式应用程序的安全性,如LPC55S69-EVK上的NXP LPC55S69(双M33核)
    1.png
    NXP LPC55S69-EVK 板

    与任何事情一样,学习和使用TrustZone的特性需要一些时间。Arm提供了关于TrustZone的文档,但要将其应用于实际的开发板或工具链并不容易。


    恩智浦MCUXpresso SDK附带了三个可用于lpc55s69-evk上的TrustZone的示例,因此我研究了一下这些示例以了解它的工作原理以及如何在我的应用程序中使用它。

    软件和工具


    我使用与我之前写的文章《First Steps with the LPC55S69-EVK (Dual-Core ARMCortex-M33 with Trustzone)》相同的配置:


    Windows10系统下10.3.1版本的MCUXpresso IDE(Eclipse基于ARM嵌入式GNU工具链)


    为LPC55S69提供的MCUXpresso SDK V2.51.


    本文介绍的大多数内容都适用于任何其他带有TrustZone的Cortex-M33环境

    Arm v8-M上的TrustZone


    与ARMV7-M中的一样,处理器有两种基本模式:
    线程模式:此模式通过复位或应用程序运行的常用模式进入。线程模式下的代码可以在特权(完全访问)或非特权(没有限制,例如由MPU(内存保护单元))下执行。


    处理者模式:此模式以特权级别执行,这是中断运行的模式。

    TrustZone保留并扩展了该模型。ARMV8-M上TrustZone的基本概念是将微控制器上的“不受信任”部分与“受信任”部分分开。有了这个分区,受信任方的IP可以得到保护,同时仍然允许“不受信任”的软件在 “不受信任”的一方运行。每个受信任和不受信任的部分可以具有不同的权限,例如某些硬件(GPIO端口等)只能从受信任的一方访问,而不能从不受信任的一方访问。



    我推荐阅读ARM document about TrustZone。
    2.png
    安全与非安全世界


    如果没有TrustZone,就可以用MPU限制内存访问,带有“安全世界”和“非安全世界”的TrustZone概念扩展到“安全”或“受信任”硬件或外设访问。非安全函数只能通过API访问安全硬件,API验证是否允许它通过安全世界访问硬件。所以让安全和不安全的部分一起工作是有办法的。
    与使用MPU类似,这意味着需要考虑以下几点:
    设置内存区域和访问外设的安全权限
    使用安全和非安全API及传输函数
    保护安全世界限制调试或内存读取的功能(逆向工程)

    MPU


    ARM V8-M体系结构的另一个重要变化是,MPU区域的大小是32字节的粒度。在arm v7-m中,大小必须是2^n,这是我没弄明白过的,并且这使得它在实际应用中根本不可用(这可能是很少使用MPU的原因?)

    SAU与IDAU


    因为这一切都不能只在ARM核中实现,所以实现ARM核的供应商在实现方面需要额外的设置。
    安全属性单元(SAU):它位于内核/处理器内部。


    实现定义属性单元(IDAU):此单元位于处理器外部,SAU和IDAU协同工作,用于授予/拒绝对系统(外围设备、内存)的访问。使用SAU+IDAU,内存空间分为三种:
    安全:安全世界的代码、堆栈、数据…


    不安全:非安全世界的代码、堆栈、数据…


    非安全可调用:使用安全网关向量表进入安全代码


    重要(也有点让人困惑)的是,SAU的设置是第一位的,而IDAU是用来让事物变得“不安全”的:
    SAU(安全的) + IDAU(不安全的) => 安全的


    SAU(不安全的) + IDAU(不安全的) => 不安全的


    SAU(非安全可调用) + IDAU(不安全的) ==>  非安全可调用


    或者换言之:默认情况下是安全的,而使用IDAU,安全级别设置为较低的级别。
    工程



    是时候看看一个例子了!NXP MCUXpresso SDK已经提供了一个示例,展示了如何从安全的区域调用非安全的区域。从“Import SDK示例”中,我选择了一些例子去演示TrustZone。
    3.png
    TrustZone示例


    TrustZone中的“hello_world”示例在安全端执行一些代码,最后将控制权传递给非安全端以执行非安全应用程序。该示例遵循安全引导加载程序的模式,然后调用非安全应用程序启动。我已经调整并复制了本文中讨论的工程,您可以在GITHUB上找到它:
    http://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/LPC55S69-EVK。
    “ns”(非安全)和“s”安全项目协同工作。使用安全和非安全的应用程序部分并不能使事情变得更简单,而且似乎没有很多关于这个主题的文档。所以我研究了“hello world”这个例子,以便更好地理解它是如何工作的。

    我已将两者配置为使用newlib(nano)somihost库:
    4.png
    Semihost设置



    对于这两个项目,将SDK调试控制台设置为Semihost Console:
    5.png
    我已经为使用semihost控制台配置了安全和非安全项目,但也可以使用真正的UART。

    两个项目都配置为使用Cortex-M33(这是编译器和链接器中的设置):
    6.png
    M33架构设置






    非安全侧



    非安全项目在编译器和链接器设置中配置为‘Non-Secure’:
    7.png
    TrustZone项目设置


    有一个阻止调试的设置:
    8.png
    Prevent Debugging



    非安全应用链接着安全应用中的一部分对象文件:
    9.png
    链接 CMSE Lib 对象文件


    这意味着必须首先编译“安全”项目。


    这是用于 ‘secure gateway library’ 的,它是使用 –cmse-implib 和 –out-implib 链接指令来建立安全项目的


    来自 http://sourceware.org/binutils/docs/ld/ARM.html



    ‘–cmse-implib’ 选项要求由“–out implib”和“–inimplib”选项指定的导入库是安全网关导入库,适合根据ARMV8-M安全扩展将非安全可执行文件与安全代码链接。
    10.png
    Secure gateway library链接指令


    ‘hello_world_ns’程序链接到地址0x10000:向量表和代码放在以下地址:
    11.png
    非安全内存设置

    安全应用程序



    在安全的一方,将TrustZone的编译器和链接器设置设置为‘secure’:
    12.png
    安全连接和编译器设置



    程序和向量表加载在0x1000'0000,而“veneer”表加载在0x1000'fe00。稍后再详细介绍…
    13.png
    安全内存分配
    调试



    非安全应用能够被烧录到像这样的设备:
    14.png
    到闪存的程序


    这基本上就好像新的(非安全的) 应用程序的烧录是使用引导加载程序或类似的方式来更新应用程序一样。



    为了能够从安全应用程序中调试第二个(非安全的),我必须在调试器中为它加载符号。现在可以像往常一样调试安全的:
    15.png
    调试安全应用



    为了在调试安全应用程序代码时调试非安全应用程序代码,我必须将符号添加到调试器中。我可以通过编辑debug/launch配置来做到这一点。双击.launch文件或使用Run>Debug Configurations打开调试配置,然后使用“调试器”选项卡中的‘Edit Scripts’:
    16.png
    Edit Scripts


    添加以下内容以使用add-symbol-file gdb命令加载其他项目的符号。根据需要调整路径,我将另一个项目放在同一目录层。
    add-symbol-file ../LPC55S69_hello_world_ns/Debug/LPC55S69_hello_world_ns.axf 0x10000



    告诉调试器该应用程序的符号加载在地址0x10000处。在${load}命令之后插入:
    17.png
    加载后添加符号



    运行应用程序会产生以下输出:
    18.png
    控制台输出

    安全状态转换



    armv8-M体系结构增加了安全状态之间的转换指令。例如,blxnx指令用于从安全世界调用非安全函数:


    安全状态转换 (来源: ARM, 用于ARMv8-M的Trustzone技术)
    19.png

    从安全世界调用非安全函数



    安全应用程序的 main() 函数如下。它可能是引导加载程序的基础,引导加载程序跳转到地址0x1'0000处的非安全加载应用程序:


    1. #define NON_SECURE_START          0x00010000

    2. /* typedef for non-secure callback functions */
    3. typedef void (*funcptr_ns) (void) __attribute__((cmse_nonsecure_call));

    4. int main(void)
    5. {
    6.     funcptr_ns ResetHandler_ns;

    7.     /* Init board hardware. */
    8.     /* attach main clock divide to FLEXCOMM0 (debug console) */
    9.     CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

    10.     BOARD_InitPins();
    11.     BOARD_BootClockFROHF96M();
    12.     BOARD_InitDebugConsole();

    13.     PRINTF("Hello from secure world!\r\n");
    14.   
    15.     /* Set non-secure main stack (MSP_NS) */
    16.     __TZ_set_MSP_NS(*((uint32_t *)(NON_SECURE_START)));
    17.   
    18.     /* Set non-secure vector table */
    19.     SCB_NS->VTOR = NON_SECURE_START;
    20.      
    21.     /* Get non-secure reset handler */
    22.     ResetHandler_ns = (funcptr_ns)(*((uint32_t *)((NON_SECURE_START) + 4U)));
    23.       
    24.     /* Call non-secure application */
    25.     PRINTF("Entering normal world.\r\n");
    26.     /* Jump to normal world */
    27.     ResetHandler_ns();
    28.     while (1)
    29.     {
    30.         /* This point should never be reached */
    31.     }
    32. }
    复制代码
    这一行:


    __TZ_set_MSP_NS(*((uint32_t *)(NON_SECURE_START)));


    加载非安全的msp(主堆栈指针)。调试器很好地显示了“banked”的安全寄存器和非安全寄存器:
    20.png
    非安全的 MSP


    以下是从安全世界中调用非安全世界的操作:


    ResetHandler_ns();


    这是一个cmse_nonsecure_call属性的函数指针:


    /* typedef for non-secure callback functions */
    typedef void (*funcptr_ns) (void) __attribute__((cmse_nonsecure_call));
    非安全函数只能使用函数指针从安全世界调用,因此将安全世界与非安全世界分开。


    在这个函数调用之后,执行了几个汇编指令。它清除函数地址的LSB,并清除FPU单精度寄存器或任何可能包含“机密”信息的寄存器。



    最后,它调用库函数 __gnu_cmse_nonsecure_call:
    21.png
    __gnu_cmse_nonsecure_函数调用会压栈寄存器并进行更多的寄存器清除,并使用BLXNS汇编指令最终进入不安全的世界:
    22.png
    __gnu_cmse_nonsecure_call

    所以有很多指令需要执行才能完成转换。

    从非安全世界调用安全世界



    从非安全端调用安全函数使用中间步骤(非安全可调用):
    23.png
    从非安全端调用安全函数使用中间步骤(非安全可调用)
    (来源: ARM, 用于ARMv8-M的Trustzone技术)

    在该示例中,非安全世界正在调用位于安全世界中的printf函数(dbgconsole_printf_nse):
    24.png
    从非安全世界调用printf


    可从非安全世界调用的安全函数必须标记cmse_nonsecure_entry属性:


    CMSE stands for Cortex-M(ARMv8-M) Security Extension
    25.png
    具有cmse_nonsecure_entry 属性的函数



    那么,不安全的世界怎么知道如何调用这个函数呢?答案是链接器准备了一切使之成为可能。为此,非安全应用程序必须将目标文件(或“库”)与“veneerr”函数链接:
    26.png
    链接 CMSE LibObject 文件


    这个对象文件 (或库)是用安全端的以下链接器设置的:



    --cmse-implib --out-implib=hello_world_s_CMSE_lib.o
    27.png
    安全网关库链接器命令



    因此,让我们看看从非安全世界到安全世界的代码: 汇编调用 ‘veneer’ 函数:
    28.png
    调用 printf veneer



    Veneer是以一个简单的 ‘蹦床’ 函数,它为“非安全可调用”加载地址并对该地址执行BX操作:
    29.png
    BX到非安全可呼叫



    “secure non-callable”区域位于“secure world”中,SG指令是第一个要执行的指令,后面跟着一个分支。
    30.png
    非安全可调用区域中的sg指令



    SG(安全网关)指令切换到安全状态,然后B(分支)指令切换到安全功能本身。
    31.png
    执行安保功能



    相比于从“secure world”调用不安全的一面,这个的执行速度是相当快的。在BXNS返回到非安全状态之前,清除所有寄存器,因为它们可能含有机密信息:
    32.png
    再回到非安全区清除寄存器的值

    SAU设置


    那么如何配置保护呢?SAU(安全属性单元)被配置为只能在安全侧完成。


    这个例子使用了以下安全和非安全的代码和数据区域:


    #define CODE_FLASH_START_NS    0x00010000
    #define CODE_FLASH_SIZE_NS     0x00062000
    #define CODE_FLASH_START_NSC   0x1000FE00
    #define CODE_FLASH_SIZE_NSC    0x200
    #define DATA_RAM_START_NS      0x20008000
    #define DATA_RAM_SIZE_NS       0x0002B000
    在这个例子中,这是在BOARD_InitTrustZone()中配置的。以下设置为非安全闪存配置一个运行区域


    /* Configure  SAU region 0 - Non-secure FLASH for CODE execution*/
    /* Set SAU  region number */
    SAU->RNR =  0;


    /* Region base  address */
    SAU->RBAR =  (CODE_FLASH_START_NS & SAU_RBAR_BADDR_Msk);


    /* Region end  address */
    SAU->RLAR =  ((CODE_FLASH_START_NS + CODE_FLASH_SIZE_NS-1) & SAU_RLAR_LADDR_Msk) |
                 /*  Region memory attribute index */
                 ((0U  >> SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk) |
                 /*  Enable region */
                 ((1U  >> SAU_RLAR_ENABLE_Pos) & SAU_RLAR_ENABLE_Msk);
    IDAU(实现定义的属性单元)是可选的,旨在提供一个默认的访问内存映射(安全的、非安全的和非安全的可调用),可以被SAU覆盖


    总结


    了解ARMv8-M安全扩展的细节可能需要更多的时间,还有更多的细节需要探索,比如安全的外设访问或如何保护内存区域。简而言之,它允许将设备划分为“安全的/受信任的和“不安全的/不受信任的”,并通过添加MPU和对外围设备的控制访问将内存映射划分为安全的、不安全的和不安全的可调用。另外还有控制调试级别的功能,以防止逆向工程的发生。

    有了NXP MCUXpresso SDK和IDE,再加上LPC55S69板,我就有了一个可以用来做实验的工作环境。我喜欢这种方法,基本上非安全应用程序需要知道它在安全环境中运行的事实,除非它想调用“secure world”的函数。


    我现在使用为M33开发的带有FreeRTOS端口的LPC55XX,但我是在“非安全”领域使用它。我的目标是让实时操作系统安全运行。目前还不确定这到底会是什么样子,但如果时间允许的话,这是一个很好的用例,我想在下周进行研究。
    “安全”快乐:-)

    视频





    以上介绍是国外网友基于MCUXpresso上一版的IDE和SDK实现的,下面是一个中国的支持工程师基于NXP最新版的MCUXpresso IDE和SDK做的一个演示视频,供大家参考。


    参考链接


    在GitHub 上的工程文件在这篇文章里:
    http://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/LPC55S69-EVK
    First Steps with the LPC55S69-EVK (Dual-Core ARM Cortex-M33 withTrustzone)
    ARM TrustZone: http://developer.arm.com/ip-products/security-ip/trustzone


    ARM v8-M架构下的ARM TrustZone技术:http://static.docs.arm.com/100690_0101/00/armv8_m_architecture_trustzone_technology_100690_0101_00_en.pdf


    Command Line Programming and Debugging with GDB


    ARMv8-M 安全性拓展: 要求和开发工具: http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf



    ARMv8-M TrustZone的背景概念: http://www.lobaro.com/using-the-armv8-m-trustzone-with-gcc/




    作者: NXP Community                                      文章出处:恩智浦MCU加油站

    签到签到
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-4-3 08:35
  • 签到天数: 374 天

    [LV.9]以坛为家II

    1

    主题

    1566

    帖子

    1

    金牌会员

    Rank: 6Rank: 6

    积分
    4336
    最后登录
    2024-4-3
    发表于 2020-1-10 13:42:44 | 显示全部楼层
    不错  
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-5-2 13:02 , Processed in 0.130640 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表