How to use an RTOS with Secure Manager on STM32H5

1. Introduction

When integrating an RTOS with the secure manager, it is important to consider the thread management. This article provides a step-by-step guide to the specific integration process. It focuses on the mechanism responsible for ensuring secure and thread-safe function calls to the secure manager.

2. Prerequisite

  • installed secure manager
  • Have a nonsecure application compatible with the secure manager
  • Have the RTOS library chosen by the user integrated in the nonsecure application

3. Implementation example

Using the secure manager from a nonsecure application can be done in a single thread, which eliminates the possibility of concurrent access.

However, when working with a real-time operating system and a multithreaded application, it is essential to protect the calls made to the secure manager.

This section presents an implementation example of protecting calls to the secure manager in a multithreaded environment.

Note: With the secure manager running, the RTOS is not TrustZone-aware.

3.1. Thread-safe secure calls

To prevent multiple calls from the nonsecure application to the secure manager interface functions, a mechanism is included in tfm_ns_interface.c that can be found in the middleware secure_manager_api.


Figure 1 : tfm_ns_interface.c directory

This mechanism, which is based on __weak functions, needs to be reimplemented with a mutex protection to ensure secure and efficient thread management.

The ns_ipc_seq_begin and ns_ipc_seq_end functions, which are declared by default in the secure manager, must be reimplemented in the RTOS project to support multithreaded use.

Figure 2 : tfm_ns_interface.c functions

3.2. Step by step implementation

The following steps outline how to implement mutex in the secure manager with RTOS in your project.

  1. Initialize the mutex
  2. Create the mutex
  3. Implement the acquisition and release of the mutex in the interface functions.

3.2.1. Detailed example applied with FreeRTOS™.

1. Declare a mutex and initialize it to 0:

static SemaphoreHandle_t nsIpcMutex = { 0 };

2. Create a function that creates the mutex and assigns it to the nsIpcMutex variable.

void tfm_ns_interface_init( void )
{
  nsIpcMutex = xSemaphoreCreateMutex();
  if(nsIpcMutex == NULL)
  {
   // Logging Error
  }
}

3. Reimplement the acquisition and release of the mutex with functions defines in semphr.c from the library FreeRTOS™, in the ns_ipc_seq_begin and ns_ipc_seq_end functions.

void ns_ipc_seq_begin(const ns_ipc_seq_info_t* info)
{
  /* Lock mutex */
  if(nsIpcMutex != NULL)
  {
    xSemaphoreTake(nsIpcMutex, portMAX_DELAY );
  }
  ….
}
void ns_ipc_seq_end(const ns_ipc_seq_info_t* info)
{
  /* Unlock mutex */
  if(nsIpcMutex != NULL)
  {
    xSemaphoreGive(nsIpcMutex);
  }
  ….
}

For more concrete examples, actual implementations can be found in X-CUBE-AWS-H5 & X-CUBE-AZURE-H5 using the secure manager with a real-time operating system.