aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmil Fresk <emil.fresk@gmail.com>2024-02-27 10:39:34 +0100
committerEmil Fresk <emil.fresk@gmail.com>2024-02-27 11:59:52 +0100
commitd2e84799c743eeb4b827d8da576be45ed43d6ece (patch)
tree37f04755854326e9aea095cb02fd729d943c92a4
parent4a23c8d6da918b2ddd5a6b694b584fd2737833bb (diff)
Fix thumbv7 soundness issue in the lock implementation
The old lock implementation did not set basepri to max(current ceiling, resource ceiling), it simply set basepri to the resource ceiling.
-rw-r--r--rtic/CHANGELOG.md1
-rw-r--r--rtic/ci/expected/prio-inversion.run6
-rw-r--r--rtic/examples/prio-inversion.rs87
-rw-r--r--rtic/src/export/cortex_basepri.rs4
4 files changed, 96 insertions, 2 deletions
diff --git a/rtic/CHANGELOG.md b/rtic/CHANGELOG.md
index 815b1bb..83c2b19 100644
--- a/rtic/CHANGELOG.md
+++ b/rtic/CHANGELOG.md
@@ -13,6 +13,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
### Fixed
+- **Soundness fix:** `thumbv7` was subject to priority inversion.
- **Soundness fix:** Monotonics did not wait long enough in `Duration` based delays.
This is not directly a change for `rtic`, but required bumping the minimal version of `rtic-monotonics`.
diff --git a/rtic/ci/expected/prio-inversion.run b/rtic/ci/expected/prio-inversion.run
new file mode 100644
index 0000000..9191436
--- /dev/null
+++ b/rtic/ci/expected/prio-inversion.run
@@ -0,0 +1,6 @@
+foo - start
+pre baz spawn 0 0
+post baz spawn 0 0
+ baz - start
+ baz - end
+foo - end
diff --git a/rtic/examples/prio-inversion.rs b/rtic/examples/prio-inversion.rs
new file mode 100644
index 0000000..1c2f7fd
--- /dev/null
+++ b/rtic/examples/prio-inversion.rs
@@ -0,0 +1,87 @@
+//! examples/prio-inversion.rs
+//!
+//! Here we test to make sure we don't have priority inversion.
+
+#![no_main]
+#![no_std]
+#![deny(warnings)]
+#![deny(unsafe_code)]
+#![deny(missing_docs)]
+#![feature(type_alias_impl_trait)]
+
+use panic_semihosting as _;
+use rtic::app;
+
+// t1 p1 use b, a
+// t2 p2 use a
+// t3 p3
+// t4 p4 use b
+//
+// so t1 start , take b take a, pend t3
+// t3 should not start
+// try to see if it starts, IT SHOULD NOT
+
+#[app(device = lm3s6965, dispatchers = [SSI0, QEI0, GPIOA, GPIOB])]
+mod app {
+ use cortex_m_semihosting::{debug, hprintln};
+
+ #[shared]
+ struct Shared {
+ a: u32,
+ b: u32,
+ }
+
+ #[local]
+ struct Local {}
+
+ #[init]
+ fn init(_: init::Context) -> (Shared, Local) {
+ foo::spawn().unwrap();
+
+ (Shared { a: 0, b: 0 }, Local {})
+ }
+
+ #[task(priority = 1, shared = [a, b])]
+ async fn foo(cx: foo::Context) {
+ let foo::SharedResources { mut a, mut b, .. } = cx.shared;
+
+ hprintln!("foo - start");
+
+ // basepri = 0
+ b.lock(|b| {
+ // basepri = max(basepri = 0, ceil(b) = 4) = 4
+ a.lock(|a| {
+ // basepri = max(basepri = 4, ceil(a) = 2) = 4
+
+ hprintln!("pre baz spawn {} {}", a, b);
+
+ // This spawn should be blocked as prio(baz) = 3
+ baz::spawn().unwrap();
+
+ hprintln!("post baz spawn {} {}", a, b);
+ });
+ // basepri = 4
+ });
+ // basepri = 0
+
+ hprintln!("foo - end");
+ debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator
+ }
+
+ #[task(priority = 2, shared = [a])]
+ async fn bar(_: bar::Context) {
+ hprintln!(" bar");
+ }
+
+ #[task(priority = 3)]
+ async fn baz(_: baz::Context) {
+ hprintln!(" baz - start");
+ hprintln!(" baz - end");
+ }
+
+ #[task(priority = 4, shared = [b])]
+ async fn pow(_: pow::Context) {
+ hprintln!(" pow - start");
+ hprintln!(" pow - end");
+ }
+}
diff --git a/rtic/src/export/cortex_basepri.rs b/rtic/src/export/cortex_basepri.rs
index 1401754..8aaa2d4 100644
--- a/rtic/src/export/cortex_basepri.rs
+++ b/rtic/src/export/cortex_basepri.rs
@@ -1,5 +1,5 @@
use super::cortex_logical2hw;
-use cortex_m::register::basepri;
+use cortex_m::register::{basepri, basepri_max};
pub use cortex_m::{
asm::wfi,
interrupt,
@@ -73,7 +73,7 @@ pub unsafe fn lock<T, R>(
critical_section::with(|_| f(&mut *ptr))
} else {
let current = basepri::read();
- basepri::write(cortex_logical2hw(ceiling, nvic_prio_bits));
+ basepri_max::write(cortex_logical2hw(ceiling, nvic_prio_bits));
let r = f(&mut *ptr);
basepri::write(current);
r