ARM Cortex-M33 TrustZone Dual RTOS Kernel Feasibility
Running two separate Real-Time Operating System (RTOS) kernels on a single ARM Cortex-M33 core using TrustZone is a complex but feasible endeavor. The Cortex-M33 processor, with its TrustZone security extension, allows for the partitioning of the system into secure and non-secure worlds. This partitioning is typically used to isolate sensitive code and data in the secure world from potentially untrusted code in the non-secure world. However, the idea of running two full RTOS instances—one in each world—introduces several architectural and operational challenges.
The primary motivation for such a setup is to achieve complete isolation between the secure and non-secure worlds while allowing each world to operate independently with its own RTOS. For instance, the secure world might run a FreeRTOS instance to manage secure tasks, while the non-secure world runs another FreeRTOS instance for non-secure tasks. This setup could be particularly useful in applications where the non-secure world needs to be highly customizable (e.g., allowing users to run bare-metal code or different RTOS implementations) while maintaining strict security in the secure world.
However, this approach is not without its complications. The Cortex-M33’s TrustZone architecture is designed to enforce security by isolating the two worlds, but it does not inherently support the simultaneous operation of two independent RTOS kernels. The secure and non-secure worlds share the same core, and while they have separate memory regions, they must contend for the same CPU resources. This shared resource contention can lead to performance bottlenecks, especially when both RTOS kernels are trying to manage their own tasks, interrupts, and system calls.
One of the key challenges in this setup is the management of system interrupts, such as SysTick, PendSV, and SVC. These interrupts are critical for RTOS operation, as they handle task scheduling, context switching, and system calls. In a dual-RTOS setup, each RTOS would need its own set of these interrupts, but the Cortex-M33’s interrupt architecture does not natively support this. The ARMv8-M architecture, which the Cortex-M33 is based on, introduces the concept of banked registers for some interrupts, but this feature is limited and may not be sufficient for fully independent RTOS operation.
Another challenge is the prioritization of interrupts between the secure and non-secure worlds. The Application Interrupt and Reset Control Register (AIRCR) provides a bit (PRIS) that can be used to ensure that secure-world interrupts always have higher priority than non-secure-world interrupts. While this ensures that the secure world can preempt the non-secure world when necessary, it can also lead to situations where the non-secure world’s real-time constraints are not met. For example, if a non-secure task is waiting for a resource or a delay (e.g., osDelay
), and the secure world is executing a high-priority task, the non-secure task may be starved of CPU time, leading to missed deadlines and degraded performance.
Furthermore, the interaction between the two RTOS kernels through Non-Secure Callable (NSC) functions adds another layer of complexity. NSC functions allow the non-secure world to invoke secure-world functions, but these calls are executed in the context of the secure world. This means that if a non-secure task calls an NSC function that blocks (e.g., waiting for a semaphore), the non-secure RTOS will not be able to perform a context switch, as the CPU is still executing in the secure world. This can lead to inefficiencies and potential deadlocks if not carefully managed.
In summary, while running dual RTOS kernels on a Cortex-M33 with TrustZone is technically possible, it requires careful consideration of interrupt management, resource sharing, and inter-world communication. The next sections will explore the possible causes of issues in such a setup and provide detailed troubleshooting steps and solutions.
Memory and Interrupt Management in Dual RTOS Environments
The feasibility of running dual RTOS kernels on a Cortex-M33 with TrustZone hinges on effective memory and interrupt management. The Cortex-M33’s TrustZone architecture divides the memory map into secure and non-secure regions, with each world having its own set of memory protections and access controls. However, this division does not extend to the CPU’s interrupt handling mechanisms, which are shared between the two worlds. This shared interrupt handling is one of the primary sources of complexity in a dual-RTOS setup.
In a typical single-RTOS setup, the RTOS kernel manages all system interrupts, including SysTick for task scheduling, PendSV for context switching, and SVC for system calls. These interrupts are essential for the RTOS to function correctly, as they allow the kernel to preempt tasks, switch contexts, and handle system calls. However, in a dual-RTOS setup, each RTOS kernel would need its own set of these interrupts to operate independently. The Cortex-M33’s interrupt architecture does not natively support this, as it does not provide separate interrupt vectors or banked registers for all critical RTOS interrupts.
The ARMv8-M architecture introduces some support for banked registers, but this feature is limited. For example, the SysTick timer can be banked, allowing each world to have its own SysTick interrupt. However, other critical interrupts, such as PendSV and SVC, are not banked and must be shared between the two worlds. This sharing can lead to conflicts, as both RTOS kernels may attempt to use the same interrupt for different purposes. For example, if the secure-world RTOS uses PendSV for context switching, the non-secure-world RTOS may not be able to use PendSV for the same purpose without interfering with the secure world.
To address this issue, one possible solution is to use different interrupts for each RTOS kernel. For example, the secure-world RTOS could use PendSV for context switching, while the non-secure-world RTOS could use a different interrupt, such as SVCall. However, this approach requires careful configuration of the interrupt priorities to ensure that the secure world can always preempt the non-secure world when necessary. The AIRCR.PRIS bit can be used to enforce this prioritization, but it must be set correctly to avoid priority inversion or other scheduling anomalies.
Another challenge in dual-RTOS environments is the management of memory barriers and cache coherency. The Cortex-M33’s memory system includes a Memory Protection Unit (MPU) that can be used to enforce access controls between the secure and non-secure worlds. However, the MPU does not automatically handle cache coherency, which can lead to issues when data is shared between the two worlds. For example, if the secure world modifies a shared data structure, the non-secure world may not see the updated data immediately due to caching effects. This can lead to inconsistent behavior and bugs that are difficult to diagnose.
To mitigate these issues, developers must use memory barriers and cache management instructions to ensure that data is properly synchronized between the two worlds. The ARMv8-M architecture provides several instructions for this purpose, including the Data Synchronization Barrier (DSB) and Instruction Synchronization Barrier (ISB). These instructions can be used to ensure that memory operations are completed before proceeding, preventing cache-related issues in dual-RTOS environments.
In summary, memory and interrupt management are critical challenges in dual-RTOS setups on the Cortex-M33. Effective management requires careful configuration of interrupt priorities, the use of banked registers where available, and the proper use of memory barriers and cache management instructions. The next section will provide detailed troubleshooting steps and solutions for these issues.
Implementing Secure and Non-Secure RTOS Synchronization and Context Switching
Implementing secure and non-secure RTOS synchronization and context switching on a Cortex-M33 with TrustZone requires a deep understanding of the processor’s interrupt architecture and the TrustZone security model. The goal is to ensure that both RTOS kernels can operate independently while maintaining the security and real-time constraints of the system. This section provides detailed steps and solutions for achieving this.
The first step in implementing dual RTOS kernels is to configure the interrupt priorities correctly. As mentioned earlier, the AIRCR.PRIS bit can be used to ensure that secure-world interrupts always have higher priority than non-secure-world interrupts. This configuration is essential to prevent the non-secure world from preempting the secure world, which could lead to security vulnerabilities. However, this prioritization must be balanced with the need to meet the real-time constraints of the non-secure world. To achieve this, developers should carefully assign priorities to all interrupts, ensuring that critical non-secure interrupts are given sufficient priority to meet their deadlines.
Next, developers must configure the SysTick timer for both RTOS kernels. The Cortex-M33’s SysTick timer can be banked, allowing each world to have its own SysTick interrupt. This configuration is essential for task scheduling in both RTOS kernels. The secure-world RTOS should configure its SysTick timer to generate interrupts at the desired task scheduling interval, while the non-secure-world RTOS should do the same. However, developers must ensure that the non-secure-world SysTick interrupt does not interfere with the secure-world SysTick interrupt. This can be achieved by setting the non-secure-world SysTick interrupt to a lower priority than the secure-world SysTick interrupt.
For context switching, each RTOS kernel should use a separate interrupt. As mentioned earlier, the secure-world RTOS can use PendSV for context switching, while the non-secure-world RTOS can use SVCall. This separation ensures that the two RTOS kernels do not interfere with each other during context switches. However, developers must ensure that the non-secure-world SVCall interrupt does not block the secure-world PendSV interrupt. This can be achieved by setting the SVCall interrupt to a lower priority than the PendSV interrupt.
To handle inter-world communication, developers must carefully manage Non-Secure Callable (NSC) functions. NSC functions allow the non-secure world to invoke secure-world functions, but these calls are executed in the context of the secure world. This means that if a non-secure task calls an NSC function that blocks (e.g., waiting for a semaphore), the non-secure RTOS will not be able to perform a context switch. To avoid this issue, developers should ensure that NSC functions are non-blocking and return control to the non-secure world as quickly as possible. If a blocking operation is necessary, it should be implemented using a callback mechanism that allows the non-secure world to continue executing while the secure world performs the blocking operation.
Finally, developers must ensure that memory barriers and cache management instructions are used correctly to maintain data consistency between the two worlds. The ARMv8-M architecture provides several instructions for this purpose, including the Data Synchronization Barrier (DSB) and Instruction Synchronization Barrier (ISB). These instructions should be used whenever data is shared between the secure and non-secure worlds to ensure that memory operations are completed before proceeding. Additionally, developers should use the MPU to enforce access controls and prevent unauthorized access to secure-world memory from the non-secure world.
In summary, implementing secure and non-secure RTOS synchronization and context switching on a Cortex-M33 with TrustZone requires careful configuration of interrupt priorities, the use of banked registers for SysTick, the separation of context switching interrupts, and the proper use of NSC functions and memory barriers. By following these steps, developers can achieve a dual-RTOS setup that meets both security and real-time constraints.