ARM Cortex-M23/M33 FVP Startup Parameter Configuration for TF-M

The Trusted Firmware-M (TF-M) is a secure firmware solution designed for ARM Cortex-M series processors, including the Cortex-M23 and Cortex-M33. These processors are often used in embedded systems requiring high levels of security and reliability. When running TF-M on Fixed Virtual Platforms (FVPs) provided by Keil, developers may encounter differences in startup parameters compared to those used in DS-5 FVPs. These differences can lead to initialization failures, incorrect memory mappings, or unexpected behavior during runtime.

The Cortex-M23 and Cortex-M33 FVPs in Keil are designed to emulate the behavior of these processors in a virtual environment, allowing developers to test and debug their firmware without needing physical hardware. However, the configuration of these FVPs, particularly the startup parameters, can vary significantly from those in DS-5 FVPs. This variation is due to differences in how Keil and DS-5 handle memory initialization, peripheral emulation, and secure/non-secure state transitions.

Understanding these differences is crucial for ensuring that TF-M runs correctly on Keil FVPs. The startup parameters control critical aspects such as the initial stack pointer, vector table location, memory region configurations, and secure/non-secure partitioning. Misconfiguration of these parameters can result in the firmware failing to boot, incorrect memory access permissions, or even security vulnerabilities.

Memory Initialization and Secure State Transition Differences

One of the primary causes of issues when running TF-M on Keil M23/M33 FVPs is the difference in memory initialization and secure state transition handling between Keil and DS-5 FVPs. In DS-5 FVPs, the memory regions and secure/non-secure states are often pre-configured to match the default settings of TF-M. However, Keil FVPs may require explicit configuration of these parameters to ensure compatibility with TF-M.

The Cortex-M23 and Cortex-M33 processors implement ARMv8-M architecture, which introduces the concept of secure and non-secure states. TF-M leverages this architecture to provide a secure execution environment. When running TF-M on Keil FVPs, the secure state transition must be correctly configured to ensure that the firmware can switch between secure and non-secure states as intended. This configuration includes setting up the Secure Attribution Unit (SAU) and the Implementation Defined Attribution Unit (IDAU), which define the memory regions accessible in each state.

Another potential cause of issues is the initialization of the vector table. In ARM Cortex-M processors, the vector table contains the initial stack pointer and the reset handler address. The location of the vector table can vary between secure and non-secure states, and it must be correctly configured in the startup parameters. If the vector table is not properly initialized, the processor may fail to execute the reset handler, leading to a boot failure.

Additionally, the memory regions used by TF-M, such as the code, data, and stack regions, must be correctly mapped in the FVP. Keil FVPs may have different default memory mappings compared to DS-5 FVPs, requiring adjustments to the startup parameters. This includes configuring the Memory Protection Unit (MPU) to enforce the correct access permissions for each memory region.

Configuring Startup Parameters and Memory Regions for TF-M on Keil FVPs

To ensure that TF-M runs correctly on Keil M23/M33 FVPs, developers must carefully configure the startup parameters and memory regions. This process involves several steps, including setting up the vector table, configuring the SAU and IDAU, and mapping the memory regions correctly.

The first step is to configure the vector table location. In TF-M, the vector table is typically located in the secure memory region. The startup parameters must specify the correct address of the vector table to ensure that the processor can fetch the initial stack pointer and reset handler address. This can be done by setting the VTOR (Vector Table Offset Register) to the address of the vector table. For example, if the vector table is located at address 0x00000000, the VTOR should be set to this address.

Next, the SAU and IDAU must be configured to define the secure and non-secure memory regions. The SAU is used to partition the memory into secure and non-secure regions, while the IDAU provides additional attribution for implementation-defined memory regions. The configuration of these units depends on the specific memory layout used by TF-M. For example, if TF-M uses a secure memory region starting at address 0x10000000 with a size of 0x10000, the SAU should be configured to mark this region as secure. This can be done by setting the SAU region registers to the appropriate values.

The MPU must also be configured to enforce the correct access permissions for each memory region. The MPU is used to define the access permissions for different memory regions, such as read-only, read-write, or execute-only. In TF-M, the MPU is typically configured to enforce strict access permissions to prevent unauthorized access to secure memory regions. For example, the secure memory region should be configured as read-only for non-secure code, while the non-secure memory region should be configured as read-write for non-secure code.

Finally, the stack and heap regions must be correctly mapped in the FVP. The stack is used for function call management and local variable storage, while the heap is used for dynamic memory allocation. The startup parameters must specify the correct addresses and sizes for these regions to ensure that the firmware can allocate memory correctly. For example, if the stack is located at address 0x20000000 with a size of 0x1000, the startup parameters should specify this address and size.

In addition to these steps, developers should also ensure that the FVP is configured to emulate the correct peripherals and interrupts. TF-M relies on certain peripherals, such as the SysTick timer and the NVIC (Nested Vectored Interrupt Controller), to function correctly. The FVP must be configured to emulate these peripherals and provide the necessary interrupts for TF-M to operate.

By carefully configuring the startup parameters and memory regions, developers can ensure that TF-M runs correctly on Keil M23/M33 FVPs. This process requires a deep understanding of the ARM Cortex-M23/M33 architecture, as well as the specific requirements of TF-M. However, with the correct configuration, developers can leverage the power of Keil FVPs to test and debug their firmware in a virtual environment, reducing the need for physical hardware and accelerating the development process.

Detailed Configuration Example for TF-M on Keil M23/M33 FVPs

To provide a more concrete example, let’s walk through a detailed configuration of TF-M on a Keil M23/M33 FVP. This example assumes that TF-M is using a specific memory layout, with secure and non-secure memory regions defined as follows:

  • Secure Code Region: 0x000000000x0000FFFF
  • Secure Data Region: 0x100000000x1000FFFF
  • Non-Secure Code Region: 0x200000000x2000FFFF
  • Non-Secure Data Region: 0x300000000x3000FFFF
  • Stack Region: 0x400000000x40000FFF
  • Heap Region: 0x500000000x5000FFFF

Step 1: Configuring the Vector Table

The vector table for TF-M is located in the secure code region at address 0x00000000. To configure the vector table, the VTOR register must be set to this address. This can be done in the startup code as follows:

SCB->VTOR = 0x00000000;

Step 2: Configuring the SAU and IDAU

The SAU and IDAU must be configured to define the secure and non-secure memory regions. The SAU is configured using the SAU region registers, while the IDAU is typically configured using implementation-defined registers. For this example, we will configure the SAU to mark the secure code and data regions as secure:

SAU->RNR = 0; // Select region 0
SAU->RBAR = 0x00000000; // Base address of secure code region
SAU->RLAR = 0x0000FFFF | SAU_RLAR_ENABLE_MASK; // Enable region 0

SAU->RNR = 1; // Select region 1
SAU->RBAR = 0x10000000; // Base address of secure data region
SAU->RLAR = 0x1000FFFF | SAU_RLAR_ENABLE_MASK; // Enable region 1

Step 3: Configuring the MPU

The MPU must be configured to enforce the correct access permissions for each memory region. For this example, we will configure the MPU to enforce the following access permissions:

  • Secure Code Region: Read-only for non-secure code
  • Secure Data Region: No access for non-secure code
  • Non-Secure Code Region: Read-write for non-secure code
  • Non-Secure Data Region: Read-write for non-secure code

This can be done using the MPU region registers as follows:

MPU->RNR = 0; // Select region 0
MPU->RBAR = 0x00000000; // Base address of secure code region
MPU->RLAR = 0x0000FFFF | MPU_RLAR_ENABLE_MASK | MPU_RLAR_AP_RO; // Enable region 0 with read-only access

MPU->RNR = 1; // Select region 1
MPU->RBAR = 0x10000000; // Base address of secure data region
MPU->RLAR = 0x1000FFFF | MPU_RLAR_ENABLE_MASK | MPU_RLAR_AP_NOACCESS; // Enable region 1 with no access

MPU->RNR = 2; // Select region 2
MPU->RBAR = 0x20000000; // Base address of non-secure code region
MPU->RLAR = 0x2000FFFF | MPU_RLAR_ENABLE_MASK | MPU_RLAR_AP_RW; // Enable region 2 with read-write access

MPU->RNR = 3; // Select region 3
MPU->RBAR = 0x30000000; // Base address of non-secure data region
MPU->RLAR = 0x3000FFFF | MPU_RLAR_ENABLE_MASK | MPU_RLAR_AP_RW; // Enable region 3 with read-write access

Step 4: Configuring the Stack and Heap Regions

The stack and heap regions must be correctly mapped in the FVP. For this example, we will configure the stack to be located at address 0x40000000 with a size of 0x1000, and the heap to be located at address 0x50000000 with a size of 0x10000. This can be done in the startup code as follows:

uint32_t *stack_top = (uint32_t *)0x40001000; // Stack grows downwards
uint32_t *heap_base = (uint32_t *)0x50000000; // Heap base address

// Initialize the stack pointer
__set_MSP(stack_top);

// Initialize the heap
Heap_Init(heap_base, 0x10000);

Step 5: Configuring Peripherals and Interrupts

Finally, the FVP must be configured to emulate the correct peripherals and interrupts. This includes configuring the SysTick timer and the NVIC to provide the necessary interrupts for TF-M to operate. For example, the SysTick timer can be configured as follows:

SysTick->LOAD = 0x00FFFFFF; // Set reload value
SysTick->VAL = 0; // Clear current value
SysTick->CTRL = SysTick_CTRL_ENABLE_MASK | SysTick_CTRL_TICKINT_MASK | SysTick_CTRL_CLKSOURCE_MASK; // Enable SysTick timer with interrupt

The NVIC can be configured to enable the necessary interrupts for TF-M. For example, to enable the SecureFault interrupt, the following code can be used:

NVIC_EnableIRQ(SecureFault_IRQn);

By following these steps, developers can ensure that TF-M is correctly configured to run on Keil M23/M33 FVPs. This configuration process requires careful attention to detail, but with the correct setup, developers can leverage the power of Keil FVPs to test and debug their firmware in a virtual environment.

Similar Posts

Leave a Reply

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