[En-Nut-Discussion] NutExitCritical() behaviour on ARM Cortex-M

Dušan dferbas at solarmonitor.cz
Thu Dec 5 14:41:18 CET 2019

Hi Philipp,

I think the first instruction only reads current priority mask to the 
function return code register.
Then all ints are globally disabled.

In our Coldfire Nut/OS port, we have e.g. uart interrupts, which can be 
interrupted by ethernet ones.
We used to save interrupt priority, because you do not know at which 
int. priority level you are running.

I realized later, when the Nut community rejected this approach, that if 
you run a normal code,
you should be at zero priority level. So there is no need to store int 
priority, except in drivers.

For drivers I found following 2 examples:

You can check e.g. Zephyr RTOS: https://github.com/zephyrproject-rtos/zephyr
irq_disable ~ arch/arm/core/irq_manage.c:arch_irq_disable ->
-> ext/hal/cmsis/Core/Include/core_cm4.h:NVIC_DisableIRQ(), which uses 
NVIC->ICER instructions to disable ints.
I think no cpsid instruction.

Similar with FreeRTOS - https://github.com/jameswalmsley/FreeRTOS
Source/portable/GCC/ARM_CM4F/port.c:vPortEnterCritical() -> 
vPortRaiseBASEPRI - I think this is called from normal context
     New priority is stored into basepri register,
     isb, dsb are used to enable immediate execution of pending ints

ulPortRaiseBASEPRI - here priority is first saved into a register (for 
further restoral)

Current Nut/OS cm3 port does not use isb instruction.
Can anyone say if it is needed?
As per 


On 5.12.2019 6:21, Philipp Burch wrote:
> Hi everyone,
> I usually only work with critical sections that disable a specific
> interrupt known to access the resource to be protected. But now I have
> some code which may be accessed from different interrupts, so I would
> like to have a critical section that disables interrupts globally on an
> ARM Cortex-M.
> For those processors, NutEnterCritical() and NutExitCritical() are
> defined in arch/cm3/atom.h as follows:
> #define NutEnterCritical() \
> { \
>      asm volatile (  \
>          "@ NutEnterCritical"    "\n\t" \
>          "mrs     r0, PRIMASK"   "\n\t" \
>          "cpsid   i"             "\n\t" \
>          :::"r0" \
>      ); \
> }
> #define NutExitCritical() \
>      {\
>          asm volatile ( \
>          "@ NutExitCritical"     "\n\t" \
>          "mrs     r0, PRIMASK"   "\n\t" \
>          "cpsie   i"             "\n\t" \
>          :::"r0" \
>      ); \
> }
> But I really can't figure out how this is supposed to work.
> NutEnterCritical() seems more or less reasonable. It moves state into r0
> and then disables the interrupts. Only: What happens to the stored state
> in r0? As far as I understand it, the clobber just tells the compiler
> that the code modifies the contents of r0 and it needs to restore them
> afterwards, but not to actually save the contents in r0 to be used
> afterwards.
> Now, what about NutExitCritical()? This seems to again move state *into*
> r0 and then enables the interrupts. But isn't it the idea to read the
> stored state and put it into PRIMASK to restore the interrupt flag to
> what it was before NutEnterCritical()?
> Additionally, the code disabling single interrupts required me to insert
> __DSB(); __ISB(); to avoid spurious interrupts to occur at the beginning
> of the critical section. Maybe these should be included.
> https://electronics.stackexchange.com/a/415138 also suggests to add
> "memory" and "cc" clobbers to the inline assembly code.
> Am I just missing something in the current implementation?
> Thank you and best regards,
> Philipp
> _______________________________________________
> http://lists.egnite.de/mailman/listinfo/en-nut-discussion

More information about the En-Nut-Discussion mailing list