[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.
https://github.com/dferbas/NutOs/blob/master/nut/include/arch/m68k/coldfire/atom_mcf5.h

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() -> 
portDISABLE_INTERRUPTS
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 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHBFEIB.html

*Dušan*

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