Secure and Non-Secure Interrupt Priority Mapping in ARMv8
In ARMv8 architectures, the handling of interrupt priorities between secure and non-secure states is a critical aspect of system design, especially when the Priority Inversion Secure (PRIS) bit in the Application Interrupt and Reset Control Register (AIRCR) is set. The PRIS bit remaps the priority of non-secure interrupts to the bottom of the priority range, ensuring that secure world interrupts can preempt non-secure ones. However, this mechanism can lead to unexpected behavior if not properly understood and configured.
The core issue arises when a developer configures two exceptions, such as SysTick and SVC (Supervisor Call), with specific priorities in the secure world and attempts to observe preemption behavior in the non-secure world. Despite setting the PRIS bit, the secure SysTick interrupt fails to preempt the non-secure SVC handler. This behavior is counterintuitive and requires a deep dive into the ARMv8 architecture, particularly the handling of banked registers and priority mapping between security states.
Banked Registers and Priority Configuration Mismatch
The root cause of this issue lies in the banked nature of certain registers and the priority configuration between secure and non-secure states. In ARMv8, SysTick and SVC exceptions are banked, meaning that each security state (secure and non-secure) has its own instance of these registers. When the PRIS bit is set, the priority of non-secure interrupts is remapped, but this remapping does not automatically propagate to the banked registers in the non-secure state.
In the provided scenario, the developer configured the SysTick priority to 2 and the SVC priority to 1 in the secure world. However, the non-secure SVC priority remains at its default value of 0 unless explicitly configured. When the PRIS bit is set, the non-secure SVC priority is remapped to the bottom of the priority range, but this remapping does not change the fact that the secure SysTick and non-secure SVC priorities are effectively the same due to the banked nature of the registers.
For example, in a Cortex-M23 processor with a 2-bit priority level, the secure SysTick priority is set to 0x80 (0x02 shifted left by 6 bits), while the non-secure SVC priority, after remapping, also becomes 0x80. This results in both exceptions having the same priority level, preventing the secure SysTick from preempting the non-secure SVC handler.
Correct Configuration of Interrupt Priorities with PRIS Bit
To resolve this issue, developers must ensure that the priority levels of both secure and non-secure interrupts are correctly configured, taking into account the banked nature of the registers and the effect of the PRIS bit. The following steps outline the necessary actions to achieve the desired preemption behavior:
-
Explicitly Configure Non-Secure Priorities: After setting the PRIS bit, developers must explicitly configure the priority levels of non-secure interrupts. This ensures that the remapped priorities are correctly applied and that the secure and non-secure interrupts have distinct priority levels.
-
Understand the Priority Remapping Mechanism: The PRIS bit remaps non-secure interrupt priorities by shifting them to the bottom of the priority range. Developers must understand how this remapping affects the actual priority values and ensure that the secure interrupts are configured with higher priorities than the remapped non-secure interrupts.
-
Verify Banked Register Configuration: Since SysTick and SVC exceptions are banked, developers must verify that the priority levels are correctly set in both secure and non-secure states. This involves checking the configuration of the banked registers and ensuring that the priorities are consistent with the desired preemption behavior.
-
Use Debugging Tools to Validate Priorities: ARM processors provide debugging tools that allow developers to inspect the current priority levels of interrupts. Using these tools, developers can validate that the priorities are correctly configured and that the PRIS bit is having the intended effect.
-
Consider the Impact of Priority Grouping: ARMv8 architectures support priority grouping, which allows developers to group interrupts into priority levels and sub-priorities. Developers must consider the impact of priority grouping on the remapping of non-secure interrupts and ensure that the grouping configuration aligns with the desired preemption behavior.
By following these steps, developers can ensure that the secure SysTick interrupt can preempt the non-secure SVC handler, achieving the desired behavior in their ARMv8-based systems.
Detailed Analysis of Priority Remapping and Banked Registers
To further understand the issue, let’s delve into the details of priority remapping and the banked nature of registers in ARMv8 architectures.
Priority Remapping with PRIS Bit
The PRIS bit in the AIRCR register is designed to ensure that secure world interrupts can preempt non-secure ones. When the PRIS bit is set, the priority of non-secure interrupts is remapped to the bottom of the priority range. This remapping is achieved by shifting the non-secure priority values and adding an offset to ensure that they are lower than the secure priorities.
For example, in a system with 8 priority levels (0 to 7), setting the PRIS bit might remap non-secure priorities as follows:
Original Priority | Remapped Priority |
---|---|
0 | 4 |
1 | 5 |
2 | 6 |
3 | 7 |
In this example, the non-secure priorities are remapped to the range 4-7, ensuring that secure priorities (0-3) can preempt non-secure ones.
Banked Registers in ARMv8
In ARMv8 architectures, certain registers are banked between secure and non-secure states. This means that each security state has its own instance of these registers, and changes made in one state do not affect the other. SysTick and SVC exceptions are examples of banked registers.
When configuring interrupt priorities, developers must be aware that setting the priority in the secure state does not automatically configure the priority in the non-secure state. This is why, in the provided scenario, the non-secure SVC priority remained at its default value of 0, even though the secure SVC priority was set to 1.
Impact of Banked Registers on Priority Configuration
The banked nature of registers means that developers must explicitly configure the priorities in both secure and non-secure states. In the provided scenario, the developer configured the secure SysTick priority to 2 and the secure SVC priority to 1, but did not configure the non-secure SVC priority. As a result, the non-secure SVC priority remained at its default value of 0, which, after remapping, became the same as the secure SysTick priority.
This configuration led to the secure SysTick interrupt being unable to preempt the non-secure SVC handler, as both exceptions had the same priority level.
Correct Configuration of Banked Registers
To ensure that the secure SysTick interrupt can preempt the non-secure SVC handler, developers must explicitly configure the non-secure SVC priority. This involves setting the priority in the non-secure state to a value that, after remapping, is lower than the secure SysTick priority.
For example, if the secure SysTick priority is set to 2 (which, after remapping, might correspond to a higher priority level), the non-secure SVC priority should be set to a value that, after remapping, is lower than the secure SysTick priority. This ensures that the secure SysTick interrupt can preempt the non-secure SVC handler.
Practical Example: Cortex-M23 Priority Configuration
Let’s consider a practical example using the Cortex-M23 processor, which has a 2-bit priority level. In this processor, the priority levels range from 0 to 3, with 0 being the highest priority and 3 being the lowest.
When the PRIS bit is set, the non-secure priorities are remapped by shifting them left by 6 bits and adding an offset. For example, a non-secure priority of 0 might be remapped to 0x80, while a non-secure priority of 1 might be remapped to 0xC0.
In the provided scenario, the secure SysTick priority was set to 2, which corresponds to a priority level of 0x80 after remapping. The non-secure SVC priority, which was not explicitly configured, remained at its default value of 0, which, after remapping, also corresponds to 0x80. As a result, both exceptions had the same priority level, preventing the secure SysTick from preempting the non-secure SVC handler.
To resolve this issue, the developer should explicitly configure the non-secure SVC priority to a value that, after remapping, is lower than the secure SysTick priority. For example, setting the non-secure SVC priority to 1 would result in a remapped priority of 0xC0, which is lower than the secure SysTick priority of 0x80. This would allow the secure SysTick interrupt to preempt the non-secure SVC handler.
Conclusion
The issue of secure SysTick interrupts failing to preempt non-secure SVC handlers in ARMv8 architectures is a result of the banked nature of registers and the priority remapping mechanism introduced by the PRIS bit. To resolve this issue, developers must explicitly configure the priorities of non-secure interrupts, taking into account the remapping of priorities and the banked nature of the registers.
By understanding the priority remapping mechanism and the impact of banked registers, developers can ensure that secure interrupts can preempt non-secure ones, achieving the desired behavior in their ARMv8-based systems. This involves careful configuration of interrupt priorities in both secure and non-secure states, as well as the use of debugging tools to validate the configuration.
In summary, the key to resolving this issue lies in a thorough understanding of the ARMv8 architecture, particularly the handling of interrupt priorities and the banked nature of registers. By following the steps outlined in this guide, developers can ensure that their systems behave as expected, with secure interrupts correctly preempting non-secure ones.