Reduce SVCall priority on ARMv8-M - #1481
jefftenney wants to merge 6 commits into
Conversation
After this commit, configMAX_SYSCALL_INTERRUPT_PRIORITY must have a zero in the least-significant implemented preemption-priority bit in Trustzone applications. This change ensures that interrupts of higher priority are not masked as a result of non-secure interrupt de-prioritization. For example, consider a PE with 4 preemption-priority bits implemented. If configMAX_SYSCALL_INTERRUPT_PRIORITY is 0x50, then non-secure interrupts that use priority 0x40 would also be masked by FreeRTOS critical sections. This is unexpected because 0x40 is a higher priority than 0x50. De-prioritization changes both 0x50 and 0x40 into 0xA0.
|
These changes test OK in some basic testing. One TZ application and one non-TZ application on STM32U585 (CM33). Note that pre-existing TZ applications that have set |
|
|
@aggarg We have a little more time on the ARMv8-M changes because we don't have a regression to fix like we did on the ARMv7-M MPU ports. The ARMv8-M ports have always used SVC priority 0. So we can take our time and do what we really think is best here. Commit 27d34c7 shows the changes between a basic reduction in SVC priority and a more aggressive reduction that aligns better with FreeRTOS documentation regarding interrupt priorities above I think I like the more aggressive priority reduction. |



Description
Instead of using the maximum priority for SVCall, use a priority just sufficient for:
This PR sets the SVCall priority slightly above configMAX_SYSCALL_INTERRUPT_PRIORITY when starting the scheduler, then reduces the priority to be equal to configMAX_SYSCALL_INTERRUPT_PRIORITY afterward.
After this change, the developer can now assign some interrupts to higher priorities than SVC. This change aligns the ARMv8-M port more closely with FreeRTOS documentation about Cortex M ports. Specifically, the documentation indicates that these ports do not mask interrupts at priorities above configMAX_SYSCALL_INTERRUPT_PRIORITY.
Additional Change
Also require configMAX_SYSCALL_INTERRUPT_PRIORITY to have a zero in the least-significant implemented preemption-priority bit in TrustZone applications. This change prevents confusion caused by the hardware de-prioritizing non-secure interrupts, which coalesces neighboring preemption priority groups. This additional change also simplifies the determination of the optimal priority setting for SVCall during OS startup. Even with de-prioritizing, the optimal priority setting still preempts the critical section from which FreeRTOS starts.
How SVCall is Used in the ARMv8-M Port
The ARMv8-M port uses SVCall to:
Sufficient SVCall Priority
The only time SVCall needs a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY is when starting the scheduler. By design, the scheduler starts from within a critical section. The SVC instruction must preempt execution immediately, so its priority must be higher than the level masked for FreeRTOS critical sections in order to start the scheduler.
The other uses of SVCall occur only in task code, not from ISRs, and not from critical sections either. So there is no further need for SVCall to have a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY after FreeRTOS starts. ISRs don't allocate/free secure contexts, and ISRs already have MPU privilege, and ISRs don't use the yield call intended for task code. Further, users don't allocate/free secure contexts from critical sections, and they don't try to raise MPU privilege from critical sections either. That's because unprivileged tasks can't create a critical section. Finally, any attempt to yield from a critical section doesn't really make sense, MPU enabled or not. If a privileged task in an MPU application attempts to yield from within a critical section, they will rightly encounter the Hard Fault that comes when SVC cannot preempt execution. And if that user actually intended the yield to be delayed until after the critical section, that user has plenty of trivial workarounds.
Automatic Critical Section for SVCall execution
Setting the SVCall priority at configMAX_SYSCALL_INTERRUPT_PRIORITY allows the SVCall handler(s) to forgo creating a critical section manually. This slightly reduces execution time for any SVCall execution that actually needs a critical section. And by nature, SVCall executions are very fast, so any SVCall executions that don't need a critical section won't impact the system very much by effectively executing within one. And finally, future authors of SVCall services may unknowingly assume their code is already running with interrupts masked. With all of these considerations, we don't feel motivated to reduce the SVCall priority even further, for example to the minimum interrupt priority like PendSV uses.
Test Steps
Tested two existing applications - one TZ and one non-TZ. (Neither uses the MPU though.)
Checklist:
Related Issue
#1470
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.