SVC Exception Not Triggering in Non-Secure Code with Interrupts Disabled

The issue at hand involves the Cortex-M33 processor, where a SuperVisor Call (SVC) instruction executed in non-secure code fails to trigger the corresponding SVC exception handler. This problem arises specifically when the SVC instruction is executed while interrupts are disabled, leading to a HardFault instead of the expected SVC exception. The HardFault is then handled by the secure firmware, which complicates the debugging process and prevents the non-secure SVC handler from being invoked.

The Cortex-M33 processor, part of the ARMv8-M architecture, implements a security extension that divides the execution environment into secure and non-secure states. This division introduces additional complexity when handling exceptions, particularly when transitioning between secure and non-secure states. The SVC instruction is a common mechanism used by Real-Time Operating Systems (RTOS) like Apache NuttX to implement system calls and context switching. However, the interaction between the SVC instruction, interrupt masking, and exception prioritization can lead to unexpected behavior, as seen in this case.

When interrupts are disabled, typically by setting the PRIMASK register, all configurable exceptions, including SVC, are masked. If an SVC instruction is executed while PRIMASK is set, the processor cannot trigger the SVC exception and instead escalates the fault to a HardFault. This escalation occurs because the execution priority of the SVC instruction matches the current execution priority (due to PRIMASK being set), which is not allowed. The HardFault handler, by default, runs in the secure state, further complicating the situation for non-secure applications.

PRIMASK Misconfiguration and SVC Priority Settings

The root cause of the issue lies in the interaction between the PRIMASK register, the priority settings of the SVC exception, and the execution environment of the Cortex-M33. PRIMASK is a special-purpose register that, when set to 1, disables all configurable exceptions, including SVC. This masking prevents the SVC exception from being triggered, even if the SVC instruction is executed. The priority of the SVC exception also plays a critical role. If the SVC priority is set to the same level as the current execution priority (which happens when PRIMASK is set), the processor cannot handle the SVC exception and escalates it to a HardFault.

The Cortex-M33 architecture defines a strict priority hierarchy for exceptions and interrupts. Each exception has an associated priority level, and the processor uses these levels to determine the order in which exceptions are handled. The SVC exception must have a higher priority (lower numerical value) than the current execution priority to be triggered. When PRIMASK is set, the current execution priority is effectively raised to the highest level (0x0), which matches the priority of the SVC exception. This equality in priority levels prevents the SVC exception from being triggered and forces the processor to escalate the fault to a HardFault.

Additionally, the secure and non-secure states introduce further complexity. By default, the HardFault handler runs in the secure state, which means that any HardFault triggered by non-secure code will be handled by the secure firmware. This behavior can obscure the root cause of the issue, as the non-secure application does not directly handle the fault. The secure firmware may not be aware of the specific context in which the fault occurred, making it difficult to diagnose and resolve the issue.

Debugging PRIMASK Settings and Implementing Proper Exception Handling

To resolve the issue, it is essential to carefully examine the PRIMASK settings and the priority configuration of the SVC exception. The first step is to ensure that the SVC instruction is not executed while PRIMASK is set. This can be achieved by modifying the RTOS initialization code to enable interrupts before issuing the SVC instruction. Alternatively, the BASEPRI register can be used instead of PRIMASK to selectively disable interrupts without affecting the SVC exception.

The BASEPRI register allows the programmer to set a priority threshold, below which interrupts and exceptions are disabled. This approach provides more granular control over interrupt masking and ensures that the SVC exception remains enabled. For example, if the SVC exception has a priority of 0x1, setting BASEPRI to 0x2 will disable all interrupts and exceptions with a priority of 0x2 or lower, while still allowing the SVC exception to be triggered.

Another critical step is to verify the priority settings of the SVC exception. The SVC priority must be higher (lower numerical value) than the current execution priority to ensure that the exception is triggered. This can be done by examining the NVIC (Nested Vectored Interrupt Controller) priority registers and adjusting the SVC priority as needed. The NVIC provides a set of registers that allow the programmer to configure the priority levels of exceptions and interrupts. For the Cortex-M33, the priority levels range from 0x0 (highest priority) to 0xFF (lowest priority).

In addition to adjusting the PRIMASK and priority settings, it is important to ensure that the HardFault handler is properly configured to handle faults in the non-secure state. The AIRCR.BFHFNMINS bit in the System Control Block (SCB) can be used to route HardFaults to the non-secure state. However, as noted in the discussion, this approach can lead to unpredictable results and is not recommended. Instead, the focus should be on preventing the HardFault from occurring in the first place by addressing the root cause of the issue.

Finally, thorough testing and debugging are essential to ensure that the changes have the desired effect. This includes verifying that the SVC exception is triggered correctly, that the HardFault handler is not invoked unnecessarily, and that the system operates as expected in both secure and non-secure states. Debugging tools such as breakpoints, watchpoints, and trace analysis can be invaluable in identifying and resolving issues related to exception handling and interrupt masking.

By carefully examining the PRIMASK settings, adjusting the SVC priority, and implementing proper exception handling, it is possible to resolve the issue of SVC calls not triggering the corresponding exception handler in non-secure code. This approach ensures that the system operates reliably and efficiently, while avoiding the pitfalls associated with HardFault escalation and secure state handling.

Similar Posts

Leave a Reply

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