Edit: Frustratingly I am not permitted to use links, so you’ll have to infer my sources.
Closely related to: forums[.]freertos[.]org/t/get-task-handle-from-isr-with-mpu/8060
I have also noticed a hard fault when calling non-fromISR suffix functions (xTaskGetCurrentTaskHandle in this case) from ISRs. I know I know, naughty.
I understand that not calling xTaskGetCurrentTaskHandle neatly avoids the problem, however to my mind the internal/core behaviour of xIsPrivileged/portIS_PRIVILEGED is incorrect.
The FreeRTOS port for the M33 checks the state of bit #0 (nPRIV) of the CONTROL register to judge whether the core is currently in a privileged or unprivileged state.
However the nPRIV bit is only valid when the core is also in Thread mode.
developer[.]arm[.]com/documentation/100235/0004/the-cortex-m33-processor/programmer-s-model/core-registers
(As far as I can tell, when the core exits Thread mode (ie enters Handler mode) it leaves this set to whatever it happens to be set to, because it shouldn’t be used in Handler mode anyway.)
It is clear from: developer[.]arm[.]com/documentation/100235/0004/the-cortex-m33-processor/programmer-s-model/processor-modes-and-privilege-levels-for-software-execution that “In Handler mode, software execution is always privileged.”
So, regardless of where/when/how xIsPrivileged is used, it only accurately returns the current core Privilege level if it takes into account Thread/Handler mode as well as the nPRIV bit.
Seems like it would be better if a given function “did what it said on the tin” at all times rather than mitigate by not using it in certain situations.
I think from reading the ARM documentation that CONTROL[1] (ie CONTROL.SPSEL) can be used as a valid indicator of Handler/Thread mode. Somehow they’ve managed to leave it ambiguous in the documentation though.
Sorry, side rant, but: Why on earth does the ARM documentation give almost enough information to be clear but frequently stop short of being explicit. I don’t like having to infer core behaviour. “In Handler mode, this bit reads as zero” and in Thread mode?.. One assumes it’s always 1 in Thread mode, but we’re left with the possibility that it can be either 0 or 1 in Thread mode depending on reasons. I presume that if we’re using the MSP we’re always in Handler mode and PSP always Thread mode?
I would propose that the BaseType_t xIsPrivileged(void) function be altered to something like:
__asm volatile ( " .syntax unified \n"/* When CONTROL[1]==1 CONTROL[0]==1 mode is unprivileged, */ " \n"/* otherwise we're either in Handler mode or Thread mode + Privileged. */ " mrs r0, control \n"/* r0 = CONTROL. */ " teq r0, #3 \n"/* Perform bitwise r0 XOR 0b11 and update the conditions flag. */ " ite ne \n"/* Result was zero Z==1 for unprivileged, otherwise Z==0 */ " movne r0, #1 \n"/* Z==0: CONTROL[1] + CONTROL[0] != 0b11. Return true to indicate that the processor is privileged. */ " moveq r0, #0 \n"/* Z==1: CONTROL[1] + CONTROL[0] == 0b11. Return false to indicate that the processor is unprivileged. */ " bx lr \n"/* Return. */ " \n" " .align 4 \n" ::: "r0", "memory" );