Skip to content

Critical sections do nothing in unprivileged code #233

Open
@cbiffle

Description

@cbiffle

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.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions