Skip to content

NVIC_EnableIRQ missing barrier? #493

@kjbracey

Description

@kjbracey

I've been getting paranoid about compiler barriers, particularly as people have been looking at Link-Time Optimisation.

NVIC_DisableIRQ has the DSB/ISB sequence needed by the architecture, and they act as the necessary "acquire" compiler barrier to keep following code in line - don't access RAM until that IRQ disable has completed.

But NVIC_EnableIRQ has nothing - it's just a volatile memory access. If code does something like:

NVIC_DisableIRQ(devx);
// modify some RAM accessed by devx IRQ handler
NVIC_EnableIRQ(devx);

Nothing is ensuring that RAM access occurs before the IRQ is enabled. volatile doesn't say anything about ordering of non-volatile accesses. Eg gcc manual:

Accesses to non-volatile objects are not ordered with respect to volatile accesses. You cannot use a volatile object as a memory barrier to order a sequence of writes to non-volatile memory.

If NVIC_DisableIRQ acts as a barrier, it makes sense that NVIC_EnableIRQ should also have one, so that the pair can function as a "lock/unlock" like above.

So my suggestion is:

_STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
  if ((int32_t)(IRQn) >= 0)
  {
    __COMPILER_BARRIER();
    NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
    __COMPILER_BARRIER(); // not sure if 2nd needed - better safe than sorry
  }
}

Would need a barrier macro in the compiler-specific stuff.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions