Reduce SVCall priority on ARMv7-M with MPU - #1470
Conversation
Restore the original SVCall priority for the ARMv7-M MPU ports from before FreeRTOS#832. This change reduces the SVCall preemption priority from zero (the highest) to a priority just higher than configMAX_SYSCALL_INTERRUPT_PRIORITY (numerically lower). Make the same change to the ARMv8-M ports, even though those ports have always used zero (the highest priority) for SVCall until now.
|
|
@aggarg Here's the PR from the recent forum post. I decided not to include ARMv8-M for now. I worry that non-secure interrupt deprioritization (see AIRCR.PRIS) can cause two neighboring preemption priorities to coalesce into one effective preemption priority. The simple method proposed in this PR for optimizing the preemption priority of SVC specifically chooses a priority that neighbors configMAX_SYSCALL_INTERRUPT_PRIORITY. If the least-significant implemented bit in configMAX_SYSCALL_INTERRUPT_PRIORITY happens to be set to 1, then the two neighboring preemption priorities would coalesce during deprioritization. Then SVC would fail to preempt an ISR it is supposed to preempt. I haven't actually tested that theory yet, but there's no need for it to hold up this PR. The ARMv8-M ports have always had SVC at priority zero (the max), so optimizing the SVC priority can be a future effort. The ARMv7-M MPU ports however, used to have an optimized SVC priority (before #832), so this PR restores that optimization. Incidentally, if I'm right about preemption priorities coalescing, then even priority zero isn't completely safe for SVC. If the user sets configMAX_SYSCALL_INTERRUPT_PRIORITY to the maximum allowed priority (eg, 0x10 for four implemented bits), then it will coalesce during deprioritization. (Both will become preemption priority 0x80.) When I find some time I'll prove this one way or the other and report back. |
|
Thank you for the change @jefftenney! What is the reason to keep SVC at Regarding the coalescing, the following table shows the mapping when 4-bits are implemented:
So priorities with the least significant implemented bit set must not be used, as they are equivalent to their counterparts with the least significant implemented bit cleared. May be we need to add an assert similar to this one to verify that |
If my understanding of the FreeRTOS configuration is correct, if an interrupt running at configMAX_SYSCALL_INTERRUPT_PRIORITY makes a system call, SVCall at the same effective priority would be unable to pre-empt it and the SVC would escalate to HardFault. This is why SVC must be assigned a higher priority using configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL.
I would add that this assertion is needed only when TrustZone is used and AIRCR.PRIS is set. Otherwise, using those priorities is perfectly valid. |
Right. Thanks for clarifying.
We always set AIRCR.PRIS when TrustZone is used: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/portable/GCC/ARM_CM33/non_secure/port.c#L1189 |
|
Thanks for that illustration table @aggarg. That's exactly what I had in my head. By any chance have you proven that it really happens as we suspect? It's surprising that the silicon offers to deprioritize the NS interrupts but then can't maintain relative preemption priorities among them. At the same time, I don't see how the silicon could do anything other than what we suspect.
Yes, that would work nicely. But here's an alternative a little more backward compatible. We keep the existing rules for setting configMAX_SYSCALL_INTERRUPT_PRIORITY, but we modify the port code to choose an optimal priority for SVC during startup. That optimal priority would be either -1 or -2 from configMAX_SYSCALL_INTERRUPT_PRIORITY, to avoid coalescing with configMAX_SYSCALL_INTERRUPT_PRIORITY. Only if no suitable SVC priority exists would the port code assert. The assert would occur only if the developer set configMAX_SYSCALL_INTERRUPT_PRIORITY to the maximum allowed priority (eg, 0x10 for four bits). The developer would be forced to reduce configMAX_SYSCALL_INTERRUPT_PRIORITY (eg, 0x20) in this case.
I don't have a strong opinion. The ARMv8-M stuff will take a little more consideration, but the ARMv7-M stuff is ready to go now. |



Description
Restore the original SVCall priority for the ARMv7-M MPU ports from before #832. This change reduces the SVCall preemption priority from zero (the highest) to a priority just higher than configMAX_SYSCALL_INTERRUPT_PRIORITY (numerically lower).
Make the same change to the ARMv8-M ports, even though those ports have always used zero (the highest priority) for SVCall until now.The corresponding changes to ARMv8-M should wait for a future effort.After these changes, SVC no longer delays all interrupts. The developer can now assign some interrupts to higher priorities than SVC. This is important for MPU ports because they may use SVC to enter and exit system calls with MPU privilege.
Non-MPU ports don't need this change because SVC is used only to start FreeRTOS in those ports. The CM0 ports don't need this change because FreeRTOS masks all interrupts during kernel operations due to the lack of a BASEPRI register on that architecture. Those ports can't accommodate higher priority interrupts to interrupt kernel operations, so there's no need for them to accommodate higher priority interrupts to interrupt SVC executions.
Test Steps
Run any demo application on its target hardware or QEMU. Since SVC is used to start FreeRTOS, a successful startup indicates SVC is still working properly.
Checklist:
Related Issue
https://forums.freertos.org/t/cortex-m-mpu-ports-delay-high-priority-isrs/25115
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.