FreeRTOS-MPU CM3. User task cannot call ENTER_CRITICAL?

mc4924 wrote on Sunday, February 07, 2016:

I am currently experimenting with FreeRTOS with MPU for Cortex M3.

It seems to me that given the settings in FreeRTOSConfig.h, an unprivileged task will never be able to use taskENTER_CRITICAL.

For instance, this is from the CORTEX_MPU_LM3Sxxxx_Rowley port:

FreeRTOSConfig.h

...
#define configKERNEL_INTERRUPT_PRIORITY  (( unsigned char ) 7 << configUNUSED_PRIO_BITS)
...
#define configMAX_SYSCALL_INTERRUPT_PRIORITY  (( unsigned char ) 5 << configUNUSED_PRIO_BITS)
...

‘KERNEL_INTERRUPT_PRIORITY’ is the priority that is assigned to SysTick, SVC and pendSV Handlers

‘MAX_SYSCALL_INTERRUPT_PRIORITY’ is the priority that is used in ENTER_CRITICAL. Any exception/interrupt with same or below priority will be masked out between ENTER_CRITICAL and EXIT_CRITICAL.

But if KERNEL_INTERRUPT_PRIORITY is lower or same as MAX_SYSCALL_INTERRUPT_PRIORITY, as it is here (bigger or equal numerical value), after ENTER_CRITICAL is called, the task will not be able to execute another SVC (which will have too low a priority now), including calling EXIT_CRITICAL! (because EXIT_CRITICAL calls prvRaisePrivilege, which uses SVC 2).

So I could do one of two things:

  1. give KERNEL_INTERRUPT_PRIORITY a higher priority than MAX_SYSCALL_INTERRUPT_PRIORITY
  2. give just the SVC handler a higher priority than MAX_SYSCALL_INTERRUPT_PRIORITY

In both cases a small test application seems to work ok (i.e. a non privileged call can use ENTER_CRITICAL/EXIT CRITICAL) but I am not sure of the ramifications of this.

The priorities seem to be set this way (KERNEL_INTERRUPT_PRIORITY lower than MAX_SYSCALL_INTERRUPT_PRIORITY) for most if not all M3/M4 ports, so I guess there must be a good reason for this.

rtel wrote on Sunday, February 07, 2016:

I think it is deliberate that an unprivileged task cannot call enter/exit critical directly as doing so disables a subset of interrupt priorities - which only tasks running with full privileges can do.

The maximum system call priority is normally above the kernel interrupt priority to allow for a full interrupt nesting model where API calls can be made from interrupts that have a priority above the kernel interrupt priority (the kernel must always be the lowest interrupt priority).

mc4924 wrote on Sunday, February 07, 2016:

Thank you for the prompt answer to my question.
Thinking about it,I guess it makes sense wanting to avoid unprivileged task blocking exceptions.

However if I was stubborn and still wanting to be able to ENTER/EXIT_CRITICAL from unprivileged tasks (maybe because I have just a very short critical section) I guess it would be better to adopt my solution n. 2 (give just the SVC a higher priority).
After all the SVC itself is quite short in itself so putting in at high priority will have a limited impact on interrupt latency.

hengblom wrote on Saturday, July 30, 2016:

Waking up this old thread since I ran into exactly the same problem when experimenting with MPU on Coretx-M3.

You say that it is a deliberate design that an unprivileged task shall not be able to enter a critical section. I can understand that, sort of, but if so, why does this code:

void vPortEnterCritical( void )
{
BaseType_t xRunningPrivileged = xPortRaisePrivilege();

portDISABLE_INTERRUPTS();
uxCriticalNesting++;

vPortResetPrivilege( xRunningPrivileged );

}

check if we are unprivileged, and if so, raise the privilege level ? If an unprivileged task should not be allowed to enter a critical section, it would have been better just to assume that the task is privileged, and if it isn’t, let it crash when trying to disable interrupts. It will, as the Claudio says, crash anyway when doing EXIT-CRITICAL.

rtel wrote on Saturday, July 30, 2016:

Perhaps this is something that was changed, I would have to look through
the change logs.