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.
This commit is contained in:
Emil Fresk 2024-02-27 10:39:34 +01:00
parent 4a23c8d6da
commit d2e84799c7
4 changed files with 96 additions and 2 deletions

View file

@ -13,6 +13,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
### Fixed ### Fixed
- **Soundness fix:** `thumbv7` was subject to priority inversion.
- **Soundness fix:** Monotonics did not wait long enough in `Duration` based delays. - **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`. This is not directly a change for `rtic`, but required bumping the minimal version of `rtic-monotonics`.

View file

@ -0,0 +1,6 @@
foo - start
pre baz spawn 0 0
post baz spawn 0 0
baz - start
baz - end
foo - end

View file

@ -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");
}
}

View file

@ -1,5 +1,5 @@
use super::cortex_logical2hw; use super::cortex_logical2hw;
use cortex_m::register::basepri; use cortex_m::register::{basepri, basepri_max};
pub use cortex_m::{ pub use cortex_m::{
asm::wfi, asm::wfi,
interrupt, interrupt,
@ -73,7 +73,7 @@ pub unsafe fn lock<T, R>(
critical_section::with(|_| f(&mut *ptr)) critical_section::with(|_| f(&mut *ptr))
} else { } else {
let current = basepri::read(); 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); let r = f(&mut *ptr);
basepri::write(current); basepri::write(current);
r r