Skip to content

interrupt::free does not disable all exceptions, which breaks critical sections #196

@jonas-schievink

Description

@jonas-schievink

It calls interrupt::disable, which uses cpsid i, which disables interrupts and exceptions that have configurable priority by setting PRIMASK. Notably, this does not affect (on thumbv6) the NMI and HardFault exceptions since they have fixed priorities.

This means that interrupt::free is unsoundly creating a CriticalSection token when it's not allowed to do so.

Note that it is impossible to fully fix this just in the cortex-m crate, since NMI is always enabled and can not be masked (which is its entire point, I suppose). Also, FAULTMASK could be used to also disable HardFault, but that only exists on thumbv7+ from what I can tell.

Our options here are:

  • Change cortex-m-rt to require unsafe to register HardFault, NMI, etc. handlers
  • Use FAULTMASK / cpsid f when targeting thumbv7+, which could allow safe registration of fault handlers except NMI on thumbv7+ (note that FAULTMASK has somewhat subtle behavior that differs from PRIMASK, so this needs some extra care to make sure it's sound)
  • Make interrupt::free an unsafe fn and document that it's only safe to call when not in one of the non-maskable fault handlers

We should probably change the docs of bare_metal::CriticalSection to reflect semantics when NMIs are present.

This issue is somewhat thorny since 3 crates rely on properties of each other for soundness (cortex-m, cortex-m-rt, and bare-metal).

(thanks to @japaric for noticing this)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions