Cortex-M33 Unprivileged Mode Stack Corruption and Register Zeroing in Secure State
When running an unprivileged application in the secure state on the Cortex-M33 processor (specifically on the STM32U5 microcontroller with TrustZone enabled), a critical issue arises. The system exhibits unexpected behavior during context switching and exception handling. Specifically, when the Link Register (LR) is set to 0xFFFFFFF9
(indicating a return to Thread Mode with the Main Stack Pointer) and the CONTROL register is set to 1
(enabling unprivileged Thread Mode), executing a BX LR
instruction results in the Stack Pointer (SP) being incremented correctly, but all registers, including the Program Counter (PC) and the Execution Program Status Register (XPSR), are zeroed out. This behavior effectively halts the system, as the processor loses all context.
Additionally, when the CONTROL register is set to 1
and a Supervisor Call (SVC) instruction is executed, the SP is decremented correctly, but no data is stored on the stack. This suggests that the stack frame, which should contain the return address and processor state, is not being written as expected. These issues do not occur when TrustZone is disabled, indicating that the problem is tightly coupled with the secure state implementation and the TrustZone Controller (TZC) behavior.
The root cause of this behavior lies in the interaction between the Cortex-M33’s secure state, the STM32U5’s TrustZone Controller (TZC), and the memory protection mechanisms. The TZC is designed to enforce secure access rules, but in this case, it appears to mishandle unprivileged accesses in the secure state. Specifically, the TZC returns 0
for unprivileged reads and silently ignores unprivileged writes without raising an exception. This behavior violates the expected ARM architecture specifications and leads to the observed system failures.
TrustZone Controller Misconfiguration and Unprivileged Access Handling
The primary cause of the Cortex-M33 unprivileged mode failure in the secure state is the misconfiguration or unintended behavior of the STM32U5’s TrustZone Controller (TZC). The TZC is responsible for enforcing memory access rules based on the security state (secure or non-secure) and the privilege level (privileged or unprivileged) of the accessing entity. In this case, the TZC is not correctly handling unprivileged accesses in the secure state, leading to two critical issues:
-
Unprivileged Read Handling: When an unprivileged application in the secure state attempts to read from a memory location, the TZC returns
0
instead of the actual data. This behavior is not compliant with the ARM architecture, which mandates that unprivileged reads should either return the correct data or trigger a fault exception if access is denied. The return of0
without an exception disrupts the normal operation of the application, as it cannot retrieve valid data. -
Unprivileged Write Handling: When an unprivileged application in the secure state attempts to write to a memory location, the TZC silently ignores the write operation without raising an exception. This behavior is particularly problematic during context switching and exception handling, as the processor expects the stack frame to be populated with the return address and processor state. The silent discard of writes prevents the stack frame from being correctly initialized, leading to the observed register zeroing and system halt.
The combination of these two issues results in the system’s inability to correctly handle unprivileged operations in the secure state. The problem is exacerbated by the fact that the TZC does not generate exceptions for these invalid accesses, making it difficult to diagnose the issue without detailed debugging.
Another contributing factor is the potential misalignment between the Cortex-M33’s secure state implementation and the STM32U5’s TrustZone configuration. The Cortex-M33 expects the secure state to enforce strict access controls while still allowing unprivileged applications to function correctly. However, the STM32U5’s TZC appears to be overly restrictive, effectively breaking the expected behavior of unprivileged mode in the secure state.
Resolving TZC Misconfiguration and Ensuring Secure Unprivileged Mode Functionality
To address the Cortex-M33 unprivileged mode failure in the secure state, the following troubleshooting steps and solutions can be implemented:
Step 1: Verify TrustZone Configuration
The first step is to thoroughly review the TrustZone configuration in the STM32U5. This includes checking the TZC settings, memory region assignments, and access permissions. Ensure that the memory regions used by the unprivileged application in the secure state are correctly configured to allow unprivileged access. The TZC should be configured to enforce secure access rules without silently discarding unprivileged reads and writes.
Step 2: Enable Debugging and Fault Handling
Enable debugging and fault handling mechanisms to capture and diagnose invalid memory accesses. Configure the Cortex-M33’s Fault Exception handlers to log or report any access violations. This will help identify whether the TZC is generating faults for unprivileged accesses and whether the system is correctly handling these faults.
Step 3: Implement Custom Exception Handlers
If the TZC is not generating exceptions for invalid unprivileged accesses, implement custom exception handlers to detect and handle these cases. For example, a BusFault or UsageFault handler can be used to catch invalid memory accesses and log the details for further analysis. This approach provides visibility into the TZC’s behavior and helps identify the root cause of the issue.
Step 4: Update Firmware and TZC Drivers
Ensure that the STM32U5 firmware and TZC drivers are up to date. STMicroelectronics may have released updates or patches to address known issues with the TZC’s handling of unprivileged accesses in the secure state. Applying these updates can resolve the problem without requiring extensive modifications to the application code.
Step 5: Modify Memory Access Patterns
If the TZC cannot be reconfigured to correctly handle unprivileged accesses, modify the memory access patterns of the unprivileged application. For example, use privileged helper functions to perform memory accesses on behalf of the unprivileged application. This approach ensures that all memory accesses are performed with the correct privilege level, avoiding the TZC’s restrictions.
Step 6: Validate Secure State Transitions
Ensure that the transitions between secure and non-secure states are correctly handled. The Cortex-M33’s Secure Attribution Unit (SAU) and Implementation Defined Attribution Unit (IDAU) should be configured to correctly map memory regions and enforce access rules. Validate that the unprivileged application remains in the secure state and does not inadvertently transition to the non-secure state, which could lead to unexpected behavior.
Step 7: Test with TrustZone Disabled
As a diagnostic step, test the application with TrustZone disabled to confirm that the issue is related to the secure state and TZC configuration. If the application functions correctly with TrustZone disabled, this further confirms that the TZC is the root cause of the problem.
Step 8: Consult STM32U5 Documentation and Errata
Review the STM32U5 documentation and errata for any known issues related to the TZC and secure state behavior. STMicroelectronics may provide workarounds or recommendations for handling unprivileged accesses in the secure state.
By following these steps, the Cortex-M33 unprivileged mode failure in the secure state can be resolved, ensuring that the system operates correctly with TrustZone enabled. The key is to carefully configure the TZC, enable robust debugging and fault handling, and validate the secure state transitions and memory access patterns.