Skip to main content

IAR Embedded Workbench for Arm 9.70.x

Arm TrustZone®

In this section:

The Arm TrustZone® technology is a System on Chip (SOC) and CPU system-wide approach to security.

Arm TrustZone was introduced in Armv6KZ and is supported also in Armv7-A and Armv8-A. It does not require any specific tool support. Similar capabilities were introduced for Cortex-M as Arm TrustZone for Armv8-M, also known as CMSE (Cortex-M Security Extension). CMSE does require tool support, and there is a standard interface for development tools that target CMSE. This extension includes two modes of execution—secure and non-secure. It also adds memory protection and instructions for validating memory access and controlled transition between the two modes.

In 32-bit mode

To use TrustZone for Armv8-M, build two separate images—one for secure mode and one for non-secure mode. The secure image can export function entries that can be used by the non-secure image.

The IAR build tools support TrustZone by means of intrinsic functions, linker options, compiler options, predefined preprocessor symbols, extended keywords, and the section Veneer$$CMSE.

You can find the data types and utility functions needed for working with TrustZone in the header file arm_cmse.h.

The function type attributes __cmse_nonsecure_call and __cmse_nonsecure_entry add code to clear the used registers when calling from secure code to non-secure code.

The IAR build tools follow the standard interface for development tools targeting Cortex-M Security Extensions (CMSE), with the following exceptions:

  • Variadic secure entry functions are not allowed.

  • Secure entry functions with parameters or return values that do not fit in registers are not allowed.

  • Non-secure calls with parameters or return values that do not fit in registers are not allowed.

  • Non-secure calls with parameters or return values in floating-point registers.

  • The compiler option ‑‑cmse requires the architecture Armv8-M with security extensions, and is not supported when building ROPI (read-only position-independent) images or RWPI (read-write position-independent) images.

For more information about Arm TrustZone, see www.arm.com.

An example using the Armv8-M Security Extensions (CMSE)

In the arm\src\ARMv8M_Secure directory, you can find an example project that demonstrates the use of Arm TrustZone and CMSE.

The example consists of two projects:

  • hello_s: The secure part of the application

  • hello_ns: The non-secure part of the application

Note

You must build the secure project before building the non-secure project.

There are two entry functions in hello_s, available to hello_ns via secure gateways in a non-secure callable region:

  • secure_hello: Prints a greeting, in the style of the classic Hello world example.

  • register_secure_goodbye: A callback that returns a string printed on exiting the secure part.

The linker will automatically generate the code for the needed secure gateways and place them in the section Veneers$$CMSE.

To set up and build the example:
  1. Open the example workspace hello_s.eww located in arm\src\ARMv8M_Secure\Hello_Secure.

  2. Set up the project hello_s to run in secure mode by choosing Project>Options>General Options>32-bit and then selecting the options TrustZone and Mode: Secure.

  3. Set up the project hello_ns to run in non-secure mode by choosing Project>Options>General Options>32-bit and then selecting the options TrustZone and Mode: Non-secure.

    The non-secure part must populate a small vector at 0x200000 with addresses to the initialization routine, non-secure top of stack, and non-secure main. This vector is used by the secure part to set up and interact with the non-secure part. In this example, this is done with the following code in nonsecure_hello.c:

    /* Interface towards the secure part */
    #pragma location=NON_SECURE_ENTRY_TABLE
    __root const non_secure_init_t init_table =
    {
      __iar_data_init3,         /* initialization function */
      __section_end("CSTACK"),  /* non-secure stack */
      main_ns                   /* non-secure main */
    };
  4. When the secure project is built, the linker will automatically generate an import library file for the non-secure part that only includes references to functions in the secure part that can be called from the non-secure part. Specify this file by using Project>Options>Linker>Output>TrustZone import library.

  5. Build the secure project.

  6. Include the TrustZone import library file manually in the project hello_ns by specifying an additional library: Project>Options>Linker>Library>Additional libraries.

  7. Build the non-secure project.

  8. The secure project must specify the non-secure project output file as an extra image that should be loaded by the debugger. To do this, use Project>Options>Debugger>Images>Download extra images.

To debug the example:
  1. To debug in the simulator, set the hello_s project as the active project by right-clicking on the project and choosing Set as Active.

  2. Choose Project>Options>Debugger>Driver and select Simulator.

  3. Choose Simulator>Memory Configuration. Make sure that the option Use ranges based on is deselected.

  4. Select Use manual ranges and add the following new ranges:

    Access type

    Start address

    End address

    RAM

    0x0000'0000
    0x003F'FFFF

    RAM

    0x2000'0000
    0x203F'FFFF

    SFR

    0x4000'0000
    0x5FFF'FFFF

    SFR

    0xE000'0000
    0xE00F'FFFF
    Table 90. Memory ranges for TrustZone example 


  5. Click OK to close the Memory Configuration dialog box.

  6. Start C-SPY by choosing Project>Download and Debug.

  7. Choose View>Terminal I/O to open the Terminal I/O window.

  8. Choose Debug>Go to start the execution.

  9. The Terminal I/O window should now print this text:

    Hello from secure World!
    Hello from non-secure World!
    Goodbye, for now.

In 64-bit mode

TrustZone support is automatic in 64-bit mode.