rust-embedded / rust-embedded/cortex-m

Critical sections do nothing in unprivileged code

Open
#233 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
1k
Forks
202
Avg merge
6d 2h
Merged PRs (30d)
2

Description

Currently, the cortex_m::interrupt::free mechanism, for executing a closure without the interference of interrupts, brackets the closure with cpsid and (conditionally, to support nesting) cpsie instructions.

These instructions do nothing in unprivileged mode. (You might expect them to trap; nope.) As a result, cortex_m::interrupt:free becomes a relatively expensive FnOnce::call in unprivileged code.

It's not clear whether cortex_m supports the privileged/unprivileged distinction (there aren't a lot of signs that it does, we're hitting a lot of issues) but this seems like a magnificent footgun.

Options for fixing this off the top of my head:

  1. Use a Cargo feature to change the implementation of things that expect privileged code for use in unprivileged contexts. In this case, operations that are inherently privileged -- like all peripherals on the PPB -- would become contingent on the privileged feature and disappear in unprivileged code. Compile time failures are nice. This is my preferred approach, because my unprivileged code is separately compiled and memory isolated, but I bet it won't cover most peoples' use cases -- I suspect that most users of cortex_m that are doing any multitasking or priv/unpriv distinction are probably using one big blob of code without isolation, all linked against the same cargo features. (Also, because of how Cargo features are defined, it would be super easy to accidentally pick up the privileged feature from your dependency graph. Laaame.)

  2. Detect at runtime the current privileged mode and panic if interrupt::free is used in unprivileged code. This is a less-good option because it introduces a runtime failure, but it sure is easy.

  3. Detect at runtime the current privileged mode and call into hooks for entering and leaving a critical section. (There is no standard way of doing this from unpriv code; it depends on the OS. Our OS doesn't actually support global critical sections in unprivileged code for latency reasons, so we'd leave the hooks unimplemented if you went this way. I'm not even sure you could design a useful hook signature since cortex_m::interrupt::free is ambient authority that requires no context information.)

  4. Declare that cortex_m is not to be used in code that uses unprivileged mode and hope that nobody ever does the wrong thing. (This is actually the conclusion we're heading toward; the APIs really do assume privilege. But it'd be nice to fix this.)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the cortex_m::interrupt::free entry point and verify how it brackets the closure with cpsid and conditionally cpsie in privileged and unprivileged modes. Compare the listed feature, runtime detection, hook, and unsupported-use options, then define a resolved behavior and validation approach before making a change.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
embedded-iot
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.