ARMv8-M Exception Priority Scheme and the Security Extension
Article ID: 131836290
Published date: 24 Jul 2017
Last updated: -
Applies to: ARMv8-M, Cortex-M23, Cortex-M33
How does the Security Extension affect the exception priority scheme in ARMv8-M?
This knowledge article is a summary of the exception priority scheme defined in the ARMv8-M architecture, but for more complete details please refer to the ARMv8-M Architecture Reference Manual.
Without the Security Extension:
If the Security Extension is not implemented in an ARMv8-M processor configuration, the exception priority scheme is effectively the same as in the preceding architecture versions. ARMv8-M Baseline behaves like ARMv6-M, while ARMv8-M with the Main Extension included behaves like ARMv7-M.
The priority scheme defines programmable priorities for interrupts and other exceptions, programmed in an 8-bit register field associated with each exception. The highest programmable priority value is zero, with increasing values representing lower priorities. In addition, the scheme defines a base priority level, lower than the lowest programmable priority, plus a small number of fixed priorities with notional negative values for exceptions with priority higher than any programmable priority.
In a Baseline implementation (such as Grebe, Cortex-M23), the programmable priority values are: 0x00, 0x40, 0x80, 0xC0.
In a Mainline implementation (such as Teal, Cortex-M33), the priority field has between 3 and 8 bits implemented. If fewer than 8 bits are implemented, the least significant bits are fixed as zero. The priority value is split into two sections by programmation of the AIRCR.PRIGROUP setting, so that the more significant bits define the pre-empting Group priority, while the less significant bits define the subpriority. Only exceptions with a Group priority strictly higher than the current execution priority will cause the current execution context to be pre-empted to run the handler for the new higher priority exception. The subpriority is used to control the order in which exceptions will be serviced when there are multiple exceptions pending at the same time, which share the same Group priority.
Some exception types cannot be ignored, so if they occur when disabled or when they have insufficient priority to pre-empt the current context, they are escalated to a HardFault.
If multiple exceptions are pending at the same time, and they have identical priorities, they will be handled in order of exception number, which means the order in which their exception vectors appear in the exception vector table.
The fixed priority exceptions are:
HardFault at priority -1
Non-Maskable Interrupt at priority -2
Reset at priority -4
(In the earlier architectures, Reset had a notional priority of -3. In ARMv8-M, it is adjusted to -4, but this has no practical effect on implementations without the Security Extension.)
The architecture provides mechanisms to boost the current execution priority.
Setting PRIMASK.PM to 1 boosts the current execution priority to 0x00, masking all programmable priority exceptions. Programmable priority interrupts will remain pending until the execution priority is lowered again, but fault exceptions can escalate to HardFault to ensure that the fault is recognized.
Setting FAULTMASK.FM to 1 boosts the current execution priority to -1, meaning that even escalation to HardFault is precluded, so only NMI and Reset can pre-empt the current execution context. (FAULTMASK.FM is cleared on an exception return.)
In a Mainline implementation, there is an additional mechanism for boosting priority to intermediate levels. BASEPRI.BASEPRI can be programmed to values between 0x01 and 0xFF to adjust the current execution priority level. A value of zero in BASEPRI.BASEPRI disables the BASEPRI mechanism, rather than boosting the priority level to 0x00. (See PRIMASK above.)
With the Security Extension included:
Inclusion of the Security Extension in an ARMv8-M processor implementation introduces some additional features into the exception priority scheme, and changes some of the behaviors.
The Security Extension introduces a new programmable priority fault exception to handle security violations - SecureFault.
Secure software can program the NVIC_ITNS registers to designate which general interrupt lines represent Secure or Non-secure interrupts.
Secure software can program AIRCR.BFHFNMINS:
0 - BusFault, HardFault and NMI target Secure state
1 - BusFault, HardFault and NMI target Non-secure state
(Note that BusFault does not exist as a discrete fault type in the Baseline architecture - it maps directly to a HardFault. However, for simplicity, this distinction is implied rather than spelled out each time it is mentioned. The ARMv8-M also uses this simplification for the descriptions.)
It is important that security-related faults cannot be inhibited by Non-secure settings, so ARMv8-M includes a new target for fault escalation - Secure HardFault at priority -3. When HardFault is designated as Non-secure by setting AIRCR.BFHFNMINS to 1, security-related faults escalate instead to Secure HardFault to ensure that they will still be recognized.
PRIMASK and FAULTMASK are banked between security states, giving PRIMASK_S and PRIMASK_NS for interrupt disable, and FAULTMASK_S and FAULTMASK_NS for fault masking.
One further programmable option, when the Security Extension is implemented, is to modify the relative priorities of Secure and Non-secure interrupts, so that the priority range for Secure interrupts extends to higher priorities than the range for Non-secure interrupts. This is done by setting AIRCR.PRIS to 1, so that the programmed priorities for Non-secure interrupts are mapped onto the bottom half of the priority range of Secure interrupts. Non-secure priorities 0x00 to 0xFF occupy the range 0x80 to 0xFF in the Secure priority range. If BASEPRI_NS is used, its value is similarly demoted by AIRCR.PRIS into the bottom half of the Secure priority range.
PRIMASK_NS is required to mask Non-secure interrupts, so it sets the current execution priority to the minimum level to mask these. If AIRCR.PRIS is clear, this level is 0x00, but if AIRCR.PRIS is set, this level is 0x80. As a side-effect, PRIMASK_NS also masks any Secure interrupts within the priority range of the Non-secure interrupts.
PRIMASK_S masks all programmable priority interrupts, so it sets the current execution priority level to 0x00.
FAULTMASK_NS is restricted in scope by the need to avoid allowing it to mask Secure faults. For this reason, FAULTMASK_NS is affected by AIRCR.PRIS and AIRCR.BFHFNMINS.
If AIRCR.BFHFNMINS is set (which means that there is a Non-secure HardFault available), FAULTMASK_NS boosts the execution priority to -1 to inhibit the Non-secure Hard Fault. If AIRCR.BFHFNMINS is clear, HardFault at priority -1 is Secure, so FAULTMASK_NS is reduced to be equivalent to PRIMASK_NS in order to avoid inhibiting Secure faults, and has the same dependency upon AIRCR.PRIS, giving a current execution priority of 0x00 or 0x80.
FAULTMASK_S boosts the current execution priority to the level required to mask Secure faults. If AIRCR.BFHFNMINS is clear, this level is -1 to inhibit HardFault, but if AIRCR.BFHFNMINS is set, this level is -3 to inhibit Secure HardFault.
In the case where there is a Secure and a Non-secure version of the same exception, and both versions have identical priority and are both pending at the same time, the Secure version will take precedence.