aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs324
1 files changed, 120 insertions, 204 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e06eee8..898bccc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,7 +12,7 @@ extern crate cortex_m;
use cortex_m::ctxt::Context;
use cortex_m::interrupt::CriticalSection;
-use cortex_m::peripheral::Peripheral;
+use cortex_m::peripheral::{Peripheral, NVIC, SCB};
use cortex_m::register::{basepri, basepri_max};
use core::cell::UnsafeCell;
@@ -23,6 +23,34 @@ use core::ptr;
// considered when determining priorities.
const PRIORITY_BITS: u8 = 4;
+/// Logical task priority
+unsafe fn task_priority() -> u8 {
+ // NOTE(safe) atomic read
+ let nr = match (*SCB.get()).icsr.read() as u8 {
+ n if n >= 16 => n - 16,
+ _ => panic!("not in a task"),
+ };
+ // NOTE(safe) atomic read
+ hardware((*NVIC.get()).ipr[nr as usize].read())
+}
+
+#[cfg(debug_assertions)]
+unsafe fn lock_check(ceiling: u8) {
+ let ceiling = hardware(ceiling);
+ let task_priority = task_priority();
+
+ if task_priority > ceiling {
+ panic!(
+ "bad ceiling value. task_priority = {}, resource_ceiling = {}",
+ task_priority,
+ ceiling,
+ );
+ }
+}
+
+#[cfg(not(debug_assertions))]
+unsafe fn lock_check(_ceiling: u8) {}
+
// XXX Do we need memory / instruction / compiler barriers here?
#[inline(always)]
unsafe fn lock<T, R, C, F>(f: F, res: *const T, ceiling: u8) -> R
@@ -30,6 +58,7 @@ where
C: Ceiling,
F: FnOnce(&T, C) -> R,
{
+ lock_check(ceiling);
let old_basepri = basepri::read();
basepri_max::write(ceiling);
let ret = f(&*res, ptr::read(0 as *const _));
@@ -44,6 +73,7 @@ where
C: Ceiling,
F: FnOnce(&mut T, C) -> R,
{
+ lock_check(ceiling);
let old_basepri = basepri::read();
basepri_max::write(ceiling);
let ret = f(&mut *res, ptr::read(0 as *const _));
@@ -131,7 +161,7 @@ where
F: FnOnce(&P, C) -> R,
Ctxt: Context,
{
- unsafe { lock(f, self.peripheral.get(), C::ceiling()) }
+ unsafe { lock(f, self.peripheral.get(), C::hw_ceiling()) }
}
/// Mutably locks the resource, preventing tasks with priority lower than
@@ -141,7 +171,7 @@ where
F: FnOnce(&mut P, C) -> R,
Ctxt: Context,
{
- unsafe { lock_mut(f, self.peripheral.get(), C::ceiling()) }
+ unsafe { lock_mut(f, self.peripheral.get(), C::hw_ceiling()) }
}
}
@@ -229,9 +259,43 @@ where
unsafe { &mut *self.data.get() }
}
- /// Returns a mutable pointer to the wrapped value
- pub fn get(&self) -> *mut T {
- self.data.get()
+ /// Returns a mutable reference to the wrapped value
+ pub unsafe fn get(&self) -> &'static mut T {
+ match () {
+ #[cfg(debug_assertions)]
+ () => {
+ let task_priority = task_priority();
+ let system_ceiling =
+ hardware(cortex_m::register::basepri::read());
+ let resource_ceiling = C::ceiling();
+
+ if resource_ceiling < task_priority {
+ panic!("bad ceiling value. task priority = {}, \
+ resource ceiling = {}",
+ task_priority,
+ resource_ceiling);
+ } else if resource_ceiling == task_priority {
+ // OK: safe to access the resource without locking in the
+ // task with highest priority
+ } else if resource_ceiling <= system_ceiling {
+ // OK: use within another resource critical section, where
+ // the locked resource has higher or equal ceiling
+ } else {
+ panic!("racy access to resource. \
+ task priority = {}, \
+ resource ceiling = {}, \
+ system ceiling = {}",
+ task_priority,
+ resource_ceiling,
+ system_ceiling);
+ }
+
+ }
+ #[cfg(not(debug_assertions))]
+ () => {}
+ }
+
+ &mut *self.data.get()
}
/// Locks the resource, preventing tasks with priority lower than `Ceiling`
@@ -241,7 +305,7 @@ where
F: FnOnce(&T, C) -> R,
Ctxt: Context,
{
- unsafe { lock(f, self.data.get(), C::ceiling()) }
+ unsafe { lock(f, self.data.get(), C::hw_ceiling()) }
}
/// Mutably locks the resource, preventing tasks with priority lower than
@@ -251,7 +315,7 @@ where
F: FnOnce(&mut T, C) -> R,
Ctxt: Context,
{
- unsafe { lock_mut(f, self.data.get(), C::ceiling()) }
+ unsafe { lock_mut(f, self.data.get(), C::hw_ceiling()) }
}
}
@@ -278,6 +342,11 @@ impl<T> Resource<T, C0> {
unsafe impl<T, Ceiling> Sync for Resource<T, Ceiling> {}
+/// Maps a hardware priority to a logical priority
+fn hardware(priority: u8) -> u8 {
+ 16 - (priority >> (8 - PRIORITY_BITS))
+}
+
/// Turns a `logical` priority into a NVIC-style priority
///
/// With `logical` priorities, `2` has HIGHER priority than `1`.
@@ -298,86 +367,14 @@ pub struct C0 {
_0: (),
}
-/// Ceiling
-pub struct C1 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C2 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C3 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C4 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C5 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C6 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C7 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C8 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C9 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C10 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C11 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C12 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C13 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C14 {
- _0: (),
-}
-
-/// Ceiling
-pub struct C15 {
- _0: (),
-}
-
/// A real ceiling
// XXX this should be a "closed" trait
pub unsafe trait Ceiling {
- /// Returns the ceiling as a number
+ /// Returns the logical ceiling as a number
fn ceiling() -> u8;
+
+ /// Returns the HW ceiling as a number
+ fn hw_ceiling() -> u8;
}
/// Usable as a ceiling
@@ -388,6 +385,45 @@ pub unsafe trait CeilingLike {}
// XXX this should be a "closed" trait
pub unsafe trait HigherThan<C> {}
+macro_rules! ceiling {
+ ($ceiling:ident, $logical:expr) => {
+ /// Ceiling
+ pub struct $ceiling {
+ _0: ()
+ }
+
+ unsafe impl CeilingLike for $ceiling {}
+
+ unsafe impl Ceiling for $ceiling {
+ #[inline(always)]
+ fn ceiling() -> u8 {
+ $logical
+ }
+
+ #[inline(always)]
+ fn hw_ceiling() -> u8 {
+ ((1 << PRIORITY_BITS) - $logical) << (8 - PRIORITY_BITS)
+ }
+ }
+ }
+}
+
+ceiling!(C1, 1);
+ceiling!(C2, 2);
+ceiling!(C3, 3);
+ceiling!(C4, 4);
+ceiling!(C5, 5);
+ceiling!(C6, 6);
+ceiling!(C7, 7);
+ceiling!(C8, 8);
+ceiling!(C9, 9);
+ceiling!(C10, 10);
+ceiling!(C11, 11);
+ceiling!(C12, 12);
+ceiling!(C13, 13);
+ceiling!(C14, 14);
+ceiling!(C15, 15);
+
unsafe impl HigherThan<C1> for C2 {}
unsafe impl HigherThan<C1> for C3 {}
unsafe impl HigherThan<C1> for C4 {}
@@ -507,124 +543,4 @@ unsafe impl HigherThan<C13> for C15 {}
unsafe impl HigherThan<C14> for C15 {}
-unsafe impl Ceiling for C1 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 1) << 4
- }
-}
-
-unsafe impl Ceiling for C2 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 2) << 4
- }
-}
-
-unsafe impl Ceiling for C3 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 3) << 4
- }
-}
-
-unsafe impl Ceiling for C4 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 4) << 4
- }
-}
-
-unsafe impl Ceiling for C5 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 5) << 4
- }
-}
-
-unsafe impl Ceiling for C6 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 6) << 4
- }
-}
-
-unsafe impl Ceiling for C7 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 7) << 4
- }
-}
-
-unsafe impl Ceiling for C8 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 8) << 4
- }
-}
-
-unsafe impl Ceiling for C9 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 9) << 4
- }
-}
-
-unsafe impl Ceiling for C10 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 10) << 4
- }
-}
-
-unsafe impl Ceiling for C11 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 11) << 4
- }
-}
-
-unsafe impl Ceiling for C12 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 12) << 4
- }
-}
-
-unsafe impl Ceiling for C13 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 13) << 4
- }
-}
-
-unsafe impl Ceiling for C14 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 14) << 4
- }
-}
-
-unsafe impl Ceiling for C15 {
- #[inline(always)]
- fn ceiling() -> u8 {
- ((1 << 4) - 15) << 4
- }
-}
-
unsafe impl CeilingLike for C0 {}
-unsafe impl CeilingLike for C1 {}
-unsafe impl CeilingLike for C2 {}
-unsafe impl CeilingLike for C3 {}
-unsafe impl CeilingLike for C4 {}
-unsafe impl CeilingLike for C5 {}
-unsafe impl CeilingLike for C6 {}
-unsafe impl CeilingLike for C7 {}
-unsafe impl CeilingLike for C8 {}
-unsafe impl CeilingLike for C9 {}
-unsafe impl CeilingLike for C10 {}
-unsafe impl CeilingLike for C11 {}
-unsafe impl CeilingLike for C12 {}
-unsafe impl CeilingLike for C13 {}
-unsafe impl CeilingLike for C14 {}
-unsafe impl CeilingLike for C15 {}