//! Stack Resource Policy for Cortex-M processors //! //! NOTE ARMv6-M is not supported at the moment. #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] #![feature(const_fn)] #![no_std] extern crate cortex_m; use cortex_m::ctxt::Context; use cortex_m::peripheral::Peripheral; use cortex_m::register::{basepri, basepri_max}; use core::cell::UnsafeCell; use core::marker::PhantomData; use core::ptr; // NOTE Only the 4 highest bits of the priority byte (BASEPRI / NVIC.IPR) are // considered when determining priorities. const PRIORITY_BITS: u8 = 4; // XXX Do we need memory / instruction / compiler barriers here? #[inline(always)] unsafe fn lock(f: F, res: *const T, ceiling: u8) -> R where C: Ceiling, F: FnOnce(&T, C) -> R, { let old_basepri = basepri::read(); basepri_max::write(ceiling); let ret = f(&*res, ptr::read(0 as *const _)); basepri::write(old_basepri); ret } // XXX Do we need memory / instruction / compiler barriers here? #[inline(always)] unsafe fn lock_mut(f: F, res: *mut T, ceiling: u8) -> R where C: Ceiling, F: FnOnce(&mut T, C) -> R, { let old_basepri = basepri::read(); basepri_max::write(ceiling); let ret = f(&mut *res, ptr::read(0 as *const _)); basepri::write(old_basepri); ret } /// A peripheral as a resource pub struct ResourceP where P: 'static, { _marker: PhantomData, peripheral: Peripheral

, } impl ResourceP where C: CeilingLike, { /// Wraps a `peripheral` into a `Resource` /// /// # Unsafety /// /// - Must not create two resources that point to the same peripheral /// - The ceiling, `C`, must be picked to prevent two or more tasks from /// concurrently accessing the resource through preemption pub const unsafe fn new(p: Peripheral

) -> Self { ResourceP { _marker: PhantomData, peripheral: p, } } } impl ResourceP where C: Ceiling, { /// Borrows the resource without locking /// /// NOTE The system ceiling must be higher than this resource ceiling pub fn borrow<'l, SC>(&'static self, _system_ceiling: &'l SC) -> &'l P where SC: HigherThan, { unsafe { &*self.peripheral.get() } } /// Mutably borrows the resource without locking /// /// NOTE The system ceiling must be higher than this resource ceiling pub fn borrow_mut<'l, SC>( &'static self, _system_ceiling: &'l mut SC, ) -> &'l mut P where SC: HigherThan, { unsafe { &mut *self.peripheral.get() } } /// Locks the resource, preventing tasks with priority lower than `Ceiling` /// from preempting the current task pub fn lock(&'static self, _ctxt: &Ctxt, f: F) -> R where F: FnOnce(&P, C) -> R, Ctxt: Context, { unsafe { lock(f, self.peripheral.get(), C::ceiling()) } } /// Mutably locks the resource, preventing tasks with priority lower than /// `Ceiling` from preempting the current task pub fn lock_mut(&'static self, _ctxt: &mut Ctxt, f: F) -> R where F: FnOnce(&mut P, C) -> R, Ctxt: Context, { unsafe { lock_mut(f, self.peripheral.get(), C::ceiling()) } } } impl

ResourceP { /// Borrows the resource without locking pub fn borrow<'ctxt, Ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt P where Ctxt: Context, { unsafe { &*self.peripheral.get() } } /// Mutably borrows the resource without locking pub fn borrow_mut<'ctxt, Ctxt>( &'static self, _ctxt: &'ctxt mut Ctxt, ) -> &'ctxt mut P where Ctxt: Context, { unsafe { &mut *self.peripheral.get() } } } unsafe impl Sync for ResourceP {} /// A resource pub struct Resource { _marker: PhantomData, data: UnsafeCell, } impl Resource { /// Initializes a resource /// /// # Unsafety /// /// - The ceiling, `C`, must be picked to prevent two or more tasks from /// concurrently accessing the resource through preemption pub const unsafe fn new(data: T) -> Self where C: CeilingLike, { Resource { _marker: PhantomData, data: UnsafeCell::new(data), } } } impl Resource where C: Ceiling, { /// Locks the resource, preventing tasks with priority lower than `Ceiling` /// from preempting the current task pub fn lock(&'static self, _ctxt: &Ctxt, f: F) -> R where F: FnOnce(&T, C) -> R, Ctxt: Context, { unsafe { lock(f, self.data.get(), C::ceiling()) } } /// Mutably locks the resource, preventing tasks with priority lower than /// `Ceiling` from preempting the current task pub fn lock_mut(&'static self, _ctxt: &mut Ctxt, f: F) -> R where F: FnOnce(&mut T, C) -> R, Ctxt: Context, { unsafe { lock_mut(f, self.data.get(), C::ceiling()) } } /// Borrows the resource without locking /// /// NOTE The system ceiling must be higher than this resource ceiling pub fn borrow<'l, SC>(&'static self, _system_ceiling: &'l SC) -> &'l T where SC: HigherThan, { unsafe { &*self.data.get() } } /// Mutably borrows the resource without locking /// /// NOTE The system ceiling must be higher than this resource ceiling pub fn borrow_mut<'l, SC>(&'static self, _ctxt: &'l mut SC) -> &'l mut T where SC: HigherThan, { unsafe { &mut *self.data.get() } } } impl Resource { /// Borrows the resource without locking pub fn borrow<'ctxt, Ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt T where Ctxt: Context, { unsafe { &*self.data.get() } } /// Mutably borrows the resource without locking pub fn borrow_mut<'ctxt, Ctxt>( &'static self, _ctxt: &'ctxt mut Ctxt, ) -> &'ctxt mut T where Ctxt: Context, { unsafe { &mut *self.data.get() } } } unsafe impl Sync for Resource {} /// Turns a `logical` priority into a NVIC-style priority /// /// With `logical` priorities, `2` has HIGHER priority than `1`. /// /// With NVIC priorities, `32` has LOWER priority than `16`. (Also, NVIC /// priorities encode the actual priority in the highest bits of a byte so /// priorities like `1` and `2` aren't actually different) /// /// NOTE Input `priority` must be in the range `[1, 16]` (inclusive) pub fn logical(priority: u8) -> u8 { assert!(priority >= 1 && priority <= 16); ((1 << PRIORITY_BITS) - priority) << (8 - PRIORITY_BITS) } /// Fake ceiling, indicates that the resource is shared by cooperative tasks 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 fn ceiling() -> u8; } /// Usable as a ceiling // XXX this should be a "closed" trait pub unsafe trait CeilingLike {} /// This ceiling is lower than `C` // XXX this should be a "closed" trait pub unsafe trait HigherThan {} unsafe impl HigherThan for C2 {} unsafe impl HigherThan for C3 {} unsafe impl HigherThan for C4 {} unsafe impl HigherThan for C5 {} unsafe impl HigherThan for C6 {} unsafe impl HigherThan for C7 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C3 {} unsafe impl HigherThan for C4 {} unsafe impl HigherThan for C5 {} unsafe impl HigherThan for C6 {} unsafe impl HigherThan for C7 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C4 {} unsafe impl HigherThan for C5 {} unsafe impl HigherThan for C6 {} unsafe impl HigherThan for C7 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C5 {} unsafe impl HigherThan for C6 {} unsafe impl HigherThan for C7 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C6 {} unsafe impl HigherThan for C7 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C7 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C8 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C9 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C10 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C11 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C12 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C13 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan for C14 {} unsafe impl HigherThan for C15 {} unsafe impl HigherThan 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 {}