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:
-
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 ofcortex_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 theprivileged
feature from your dependency graph. Laaame.) -
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. -
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.) -
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.)