Secure World Variable Allocation in ARM TrustZone-M

When working with ARM TrustZone-M on Cortex-M processors, one of the critical tasks is ensuring that sensitive data, such as cryptographic keys or secure application state, is stored in memory that is only accessible to the Secure World. This is particularly important for maintaining the integrity and confidentiality of the system. However, declaring and managing variables in the Secure World memory can be challenging due to the strict separation between Secure and Non-Secure worlds, as well as the need to adhere to the memory partitioning rules defined by the TrustZone-M architecture.

The primary issue revolves around how to declare a global array or variable in the Secure World memory such that it is accessible only to secure functions and remains isolated from the Non-Secure World. This requires a deep understanding of the TrustZone-M memory model, linker script configurations, and the specific mechanisms provided by the ARM Cortex-M architecture to enforce memory isolation.

Linker Script Misconfiguration and Memory Partitioning

One of the most common causes of issues when declaring Secure World variables is improper configuration of the linker script. The linker script is responsible for defining memory regions and assigning sections of the compiled code and data to these regions. In TrustZone-M, the memory is divided into Secure and Non-Secure regions, and the linker script must explicitly define these regions to ensure that Secure World variables are placed in the correct memory space.

Another potential cause is the omission of necessary attributes or pragmas in the variable declaration. ARM TrustZone-M relies on specific compiler directives to mark variables as belonging to the Secure World. Without these directives, the compiler may place the variable in a default memory region, which could be accessible from the Non-Secure World, thereby violating the security model.

Additionally, the memory partitioning unit (MPU) or the Security Attribution Unit (SAU) might not be configured correctly. These hardware units enforce the memory access rules defined by TrustZone-M. If the SAU or MPU is not properly set up, even correctly declared Secure World variables might be accessible from the Non-Secure World, leading to potential security vulnerabilities.

Configuring Linker Scripts and Compiler Directives for Secure World Variables

To declare a global array or variable in the Secure World memory, follow these detailed steps:

Step 1: Define Secure Memory Regions in the Linker Script

The first step is to modify the linker script to define the Secure and Non-Secure memory regions. This involves specifying the base address and size of the Secure memory region and ensuring that the linker places the Secure World variables in this region. Below is an example of how to define a Secure memory region in a linker script:

MEMORY
{
  FLASH (rx)  : ORIGIN = 0x00000000, LENGTH = 512K
  RAM (rwx)   : ORIGIN = 0x20000000, LENGTH = 128K
  SECURE_RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 64K
}

SECTIONS
{
  .secure_data :
  {
    *(.secure_data*)
  } > SECURE_RAM
}

In this example, the SECURE_RAM region is defined with a base address of 0x30000000 and a length of 64K. The .secure_data section is then assigned to this region, ensuring that any variable placed in this section will reside in Secure memory.

Step 2: Use Compiler Directives to Mark Secure Variables

Next, use compiler-specific attributes or pragmas to mark the global array or variable as belonging to the Secure World. For example, in ARM Compiler 6, you can use the __attribute__((section(".secure_data"))) directive to place the variable in the .secure_data section defined in the linker script:

__attribute__((section(".secure_data"))) uint32_t secure_array[100];

This ensures that the secure_array variable is placed in the Secure memory region.

Step 3: Configure the Security Attribution Unit (SAU)

The SAU is responsible for defining the memory regions as Secure or Non-Secure. Configure the SAU to mark the SECURE_RAM region as Secure. This is typically done during the initialization phase of the Secure World software. Below is an example of how to configure the SAU using the ARM CMSIS (Cortex Microcontroller Software Interface Standard) API:

#include "ARMCM33.h"

void configure_sau(void) {
  SAU->RNR = 0; // Select region 0
  SAU->RBAR = 0x30000000U; // Base address of SECURE_RAM
  SAU->RLAR = 0x3000FFFFU | SAU_RLAR_ENABLE_Msk; // Set limit and enable region
  __DSB(); // Ensure the configuration takes effect
  __ISB(); // Ensure the instruction stream is synchronized
}

This code configures the SAU to mark the memory region from 0x30000000 to 0x3000FFFF as Secure.

Step 4: Verify Memory Access Permissions

After configuring the linker script, compiler directives, and SAU, verify that the Secure World variable is only accessible from the Secure World. Attempt to access the variable from the Non-Secure World and ensure that it generates a SecureFault or Memory Management Fault, as expected.

Step 5: Debugging and Validation

Use a debugger to inspect the memory map and verify that the variable is placed in the correct Secure memory region. Additionally, use the debugger to step through the code and ensure that the SAU configuration is applied correctly. If any issues are encountered, double-check the linker script, compiler directives, and SAU configuration.

Step 6: Handling Secure World Data in Zephyr and TFM

If you are using Zephyr OS and Trusted Firmware-M (TFM), ensure that the build system is aware of the Secure memory regions and that the TFM build configuration aligns with the linker script and SAU settings. This may involve modifying the Zephyr and TFM build scripts to include the Secure memory regions and ensure that the Secure World variables are correctly placed.

Step 7: Testing and Validation

Finally, thoroughly test the system to ensure that the Secure World variables are correctly isolated and that the Non-Secure World cannot access them. This includes running both Secure and Non-Secure applications and verifying that the system behaves as expected under various conditions.

By following these steps, you can successfully declare and manage Secure World variables in ARM TrustZone-M, ensuring that sensitive data is protected from unauthorized access. This approach leverages the hardware-enforced memory isolation provided by TrustZone-M, combined with careful configuration of the linker script, compiler directives, and SAU, to achieve a robust and secure implementation.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *