2017-03-05 06:26:14 +01:00
|
|
|
//! Stack Resource Policy for Cortex-M processors
|
|
|
|
//!
|
2017-04-06 21:06:33 +02:00
|
|
|
//! NOTE ARMv6-M is not fully supported at the moment.
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-03-08 14:10:58 +01:00
|
|
|
#![deny(missing_docs)]
|
|
|
|
#![deny(warnings)]
|
2017-03-05 06:26:14 +01:00
|
|
|
#![feature(asm)]
|
|
|
|
#![feature(const_fn)]
|
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
extern crate cortex_m;
|
|
|
|
|
2017-04-08 00:34:06 +02:00
|
|
|
pub mod checked;
|
|
|
|
|
2017-03-11 02:11:36 +01:00
|
|
|
use cortex_m::ctxt::Context;
|
2017-04-04 22:36:23 +02:00
|
|
|
use cortex_m::interrupt::{CriticalSection, Nr};
|
2017-04-06 21:06:33 +02:00
|
|
|
use cortex_m::peripheral::{Peripheral, NVIC};
|
|
|
|
#[cfg(not(thumbv6m))]
|
|
|
|
use cortex_m::peripheral::SCB;
|
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-05 06:26:14 +01:00
|
|
|
use cortex_m::register::{basepri, basepri_max};
|
|
|
|
|
|
|
|
use core::cell::UnsafeCell;
|
2017-03-10 05:59:50 +01:00
|
|
|
use core::marker::PhantomData;
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-11 22:12:58 +01:00
|
|
|
use core::ptr;
|
2017-03-10 05:59:50 +01:00
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-10 05:59:50 +01:00
|
|
|
// NOTE Only the 4 highest bits of the priority byte (BASEPRI / NVIC.IPR) are
|
|
|
|
// considered when determining priorities.
|
|
|
|
const PRIORITY_BITS: u8 = 4;
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-04-03 23:18:26 +02:00
|
|
|
/// Logical task priority
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-04-03 23:18:26 +02:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(all(debug_assertions, not(thumbv6m)))]
|
2017-04-04 23:37:01 +02:00
|
|
|
unsafe fn get_check(logical_ceiling: u8) {
|
|
|
|
let task_priority = task_priority();
|
|
|
|
let system_ceiling = hardware(cortex_m::register::basepri::read());
|
|
|
|
let resource_ceiling = logical_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))]
|
|
|
|
unsafe fn get_check(_: u8) {}
|
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(all(debug_assertions, not(thumbv6m)))]
|
2017-04-03 23:18:26 +02:00
|
|
|
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))]
|
2017-04-04 23:37:01 +02:00
|
|
|
unsafe fn lock_check(_: u8) {}
|
2017-04-03 23:18:26 +02:00
|
|
|
|
2017-03-08 14:10:58 +01:00
|
|
|
// XXX Do we need memory / instruction / compiler barriers here?
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-05 06:26:14 +01:00
|
|
|
#[inline(always)]
|
2017-03-11 22:12:58 +01:00
|
|
|
unsafe fn lock<T, R, C, F>(f: F, res: *const T, ceiling: u8) -> R
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
2017-03-11 22:12:58 +01:00
|
|
|
C: Ceiling,
|
|
|
|
F: FnOnce(&T, C) -> R,
|
2017-03-08 14:10:58 +01:00
|
|
|
{
|
2017-04-03 23:18:26 +02:00
|
|
|
lock_check(ceiling);
|
2017-03-08 14:10:58 +01:00
|
|
|
let old_basepri = basepri::read();
|
|
|
|
basepri_max::write(ceiling);
|
2017-04-08 01:14:48 +02:00
|
|
|
compiler_barrier();
|
2017-03-11 22:12:58 +01:00
|
|
|
let ret = f(&*res, ptr::read(0 as *const _));
|
2017-04-08 01:14:48 +02:00
|
|
|
compiler_barrier();
|
2017-03-08 14:10:58 +01:00
|
|
|
basepri::write(old_basepri);
|
|
|
|
ret
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
|
|
|
|
2017-03-11 05:58:17 +01:00
|
|
|
// XXX Do we need memory / instruction / compiler barriers here?
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-11 05:58:17 +01:00
|
|
|
#[inline(always)]
|
2017-03-11 22:12:58 +01:00
|
|
|
unsafe fn lock_mut<T, R, C, F>(f: F, res: *mut T, ceiling: u8) -> R
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
2017-03-11 22:12:58 +01:00
|
|
|
C: Ceiling,
|
|
|
|
F: FnOnce(&mut T, C) -> R,
|
2017-03-11 05:58:17 +01:00
|
|
|
{
|
2017-04-03 23:18:26 +02:00
|
|
|
lock_check(ceiling);
|
2017-03-11 05:58:17 +01:00
|
|
|
let old_basepri = basepri::read();
|
|
|
|
basepri_max::write(ceiling);
|
2017-04-08 01:14:48 +02:00
|
|
|
compiler_barrier();
|
2017-03-11 22:12:58 +01:00
|
|
|
let ret = f(&mut *res, ptr::read(0 as *const _));
|
2017-04-08 01:14:48 +02:00
|
|
|
compiler_barrier();
|
2017-03-11 05:58:17 +01:00
|
|
|
basepri::write(old_basepri);
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
2017-04-08 01:14:48 +02:00
|
|
|
fn compiler_barrier() {
|
|
|
|
unsafe {
|
|
|
|
asm!(""
|
|
|
|
:
|
|
|
|
:
|
|
|
|
: "memory"
|
|
|
|
: "volatile");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 14:10:58 +01:00
|
|
|
/// A peripheral as a resource
|
2017-03-10 05:59:50 +01:00
|
|
|
pub struct ResourceP<P, Ceiling>
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
P: 'static,
|
2017-03-05 06:26:14 +01:00
|
|
|
{
|
2017-03-10 05:59:50 +01:00
|
|
|
_marker: PhantomData<Ceiling>,
|
|
|
|
peripheral: Peripheral<P>,
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
impl<P, C> ResourceP<P, C>
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
C: CeilingLike,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-03-08 14:10:58 +01:00
|
|
|
/// Wraps a `peripheral` into a `Resource`
|
|
|
|
///
|
|
|
|
/// # Unsafety
|
|
|
|
///
|
2017-03-08 14:22:31 +01:00
|
|
|
/// - Must not create two resources that point to the same peripheral
|
2017-03-10 05:59:50 +01:00
|
|
|
/// - 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<P>) -> Self {
|
2017-03-08 14:10:58 +01:00
|
|
|
ResourceP {
|
2017-03-10 05:59:50 +01:00
|
|
|
_marker: PhantomData,
|
2017-03-08 14:10:58 +01:00
|
|
|
peripheral: p,
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
|
|
|
}
|
2017-03-22 20:33:52 +01:00
|
|
|
|
|
|
|
/// Borrows the resource for the duration of `interrupt::free`
|
|
|
|
pub fn cs_borrow<'cs>(&self, _ctxt: &'cs CriticalSection) -> &'cs P {
|
|
|
|
unsafe { &*self.peripheral.get() }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Mutably borrows the resource for the duration of `interrupt::free`
|
2017-04-03 03:38:45 +02:00
|
|
|
pub fn cs_borrow_mut<'cs>(
|
|
|
|
&self,
|
|
|
|
_ctxt: &'cs mut CriticalSection,
|
|
|
|
) -> &'cs mut P {
|
2017-03-22 20:33:52 +01:00
|
|
|
unsafe { &mut *self.peripheral.get() }
|
|
|
|
}
|
2017-03-10 05:59:50 +01:00
|
|
|
}
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-10 05:59:50 +01:00
|
|
|
impl<P, C> ResourceP<P, C>
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
C: Ceiling,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
|
|
|
/// Borrows the resource without locking
|
2017-03-11 22:12:58 +01:00
|
|
|
///
|
|
|
|
/// NOTE The system ceiling must be higher than this resource ceiling
|
|
|
|
pub fn borrow<'l, SC>(&'static self, _system_ceiling: &'l SC) -> &'l P
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
2017-03-11 22:12:58 +01:00
|
|
|
SC: HigherThan<C>,
|
2017-03-05 06:26:14 +01:00
|
|
|
{
|
2017-03-11 22:12:58 +01:00
|
|
|
unsafe { &*self.peripheral.get() }
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
|
|
|
|
2017-04-04 23:37:01 +02:00
|
|
|
/// Returns an immutable reference to the inner data without locking
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// You must
|
|
|
|
///
|
|
|
|
/// - Preserve the "reference" rules. Don't create an immutable reference if
|
|
|
|
/// the current task already owns a mutable reference to the data.
|
|
|
|
///
|
|
|
|
/// - adhere to the Stack Resource Policy. You can
|
|
|
|
/// - Access the resource from the highest priority task.
|
|
|
|
/// - Access the resource from within a critical section that sets the
|
|
|
|
/// system ceiling to `C`.
|
|
|
|
pub unsafe fn get(&self) -> &'static P {
|
|
|
|
get_check(C::ceiling());
|
|
|
|
|
|
|
|
&*self.peripheral.get()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a mutable reference to the inner data without locking
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// You must
|
|
|
|
///
|
|
|
|
/// - Preserve the "reference" rules. Don't create a mutable reference if
|
|
|
|
/// the current task already owns a reference to the data.
|
|
|
|
///
|
|
|
|
/// - adhere to the Stack Resource Policy. You can
|
|
|
|
/// - Access the resource from the highest priority task.
|
|
|
|
/// - Access the resource from within a critical section that sets the
|
|
|
|
/// system ceiling to `C`.
|
|
|
|
pub unsafe fn get_mut(&self) -> &'static mut P {
|
|
|
|
get_check(C::ceiling());
|
|
|
|
|
|
|
|
&mut *self.peripheral.get()
|
2017-04-03 03:42:38 +02:00
|
|
|
}
|
|
|
|
|
2017-03-11 05:58:17 +01:00
|
|
|
/// Locks the resource, preventing tasks with priority lower than `Ceiling`
|
|
|
|
/// from preempting the current task
|
|
|
|
pub fn lock<R, F, Ctxt>(&'static self, _ctxt: &Ctxt, f: F) -> R
|
|
|
|
where
|
2017-03-11 22:12:58 +01:00
|
|
|
F: FnOnce(&P, C) -> R,
|
2017-03-11 05:58:17 +01:00
|
|
|
Ctxt: Context,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-04-03 23:18:26 +02:00
|
|
|
unsafe { lock(f, self.peripheral.get(), C::hw_ceiling()) }
|
2017-03-10 05:59:50 +01:00
|
|
|
}
|
2017-03-11 05:58:17 +01:00
|
|
|
|
|
|
|
/// Mutably locks the resource, preventing tasks with priority lower than
|
|
|
|
/// `Ceiling` from preempting the current task
|
|
|
|
pub fn lock_mut<R, F, Ctxt>(&'static self, _ctxt: &mut Ctxt, f: F) -> R
|
|
|
|
where
|
2017-03-11 22:12:58 +01:00
|
|
|
F: FnOnce(&mut P, C) -> R,
|
2017-03-11 05:58:17 +01:00
|
|
|
Ctxt: Context,
|
|
|
|
{
|
2017-04-03 23:18:26 +02:00
|
|
|
unsafe { lock_mut(f, self.peripheral.get(), C::hw_ceiling()) }
|
2017-03-11 05:58:17 +01:00
|
|
|
}
|
2017-03-10 05:59:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<P> ResourceP<P, C0> {
|
|
|
|
/// Borrows the resource without locking
|
|
|
|
pub fn borrow<'ctxt, Ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt P
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
Ctxt: Context,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-03-08 14:10:58 +01:00
|
|
|
unsafe { &*self.peripheral.get() }
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
2017-03-11 05:58:17 +01:00
|
|
|
|
|
|
|
/// 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() }
|
|
|
|
}
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
unsafe impl<P, C> Sync for ResourceP<P, C> {}
|
2017-03-08 14:10:58 +01:00
|
|
|
|
|
|
|
/// A resource
|
2017-03-10 05:59:50 +01:00
|
|
|
pub struct Resource<T, Ceiling> {
|
|
|
|
_marker: PhantomData<Ceiling>,
|
2017-03-05 06:26:14 +01:00
|
|
|
data: UnsafeCell<T>,
|
|
|
|
}
|
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
impl<T, C> Resource<T, C> {
|
2017-03-08 14:10:58 +01:00
|
|
|
/// Initializes a resource
|
|
|
|
///
|
2017-03-08 14:22:31 +01:00
|
|
|
/// # Unsafety
|
|
|
|
///
|
2017-03-10 05:59:50 +01:00
|
|
|
/// - 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
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
C: CeilingLike,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-03-05 06:26:14 +01:00
|
|
|
Resource {
|
2017-03-10 05:59:50 +01:00
|
|
|
_marker: PhantomData,
|
2017-03-05 06:26:14 +01:00
|
|
|
data: UnsafeCell::new(data),
|
|
|
|
}
|
|
|
|
}
|
2017-03-22 20:33:52 +01:00
|
|
|
|
|
|
|
/// Borrows the resource for the duration of `interrupt::free`
|
|
|
|
pub fn cs_borrow<'cs>(&self, _ctxt: &'cs CriticalSection) -> &'cs T {
|
|
|
|
unsafe { &*self.data.get() }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Mutably borrows the resource for the duration of `interrupt::free`
|
2017-04-03 03:38:45 +02:00
|
|
|
pub fn cs_borrow_mut<'cs>(
|
|
|
|
&self,
|
|
|
|
_ctxt: &'cs mut CriticalSection,
|
|
|
|
) -> &'cs mut T {
|
2017-03-22 20:33:52 +01:00
|
|
|
unsafe { &mut *self.data.get() }
|
|
|
|
}
|
2017-03-10 05:59:50 +01:00
|
|
|
}
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-10 05:59:50 +01:00
|
|
|
impl<T, C> Resource<T, C>
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
C: Ceiling,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-03-11 22:12:58 +01:00
|
|
|
/// 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
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
2017-03-11 22:12:58 +01:00
|
|
|
SC: HigherThan<C>,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-03-11 22:12:58 +01:00
|
|
|
unsafe { &*self.data.get() }
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
2017-03-11 05:58:17 +01:00
|
|
|
|
2017-04-04 23:37:01 +02:00
|
|
|
/// Returns an immutable reference to the inner data without locking
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// You must
|
|
|
|
///
|
|
|
|
/// - Preserve the "reference" rules. Don't create an immutable reference if
|
|
|
|
/// the current task already owns a mutable reference to the data.
|
|
|
|
///
|
|
|
|
/// - adhere to the Stack Resource Policy. You can
|
|
|
|
/// - Access the resource from the highest priority task.
|
|
|
|
/// - Access the resource from within a critical section that sets the
|
|
|
|
/// system ceiling to `C`.
|
|
|
|
pub unsafe fn get(&'static self) -> &'static T {
|
|
|
|
get_check(C::ceiling());
|
|
|
|
|
|
|
|
&*self.data.get()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a mutable reference to the inner data without locking
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// You must
|
|
|
|
///
|
|
|
|
/// - Preserve the "reference" rules. Don't create a mutable reference if
|
|
|
|
/// the current task already owns a reference to the data.
|
|
|
|
///
|
|
|
|
/// - adhere to the Stack Resource Policy. You can
|
|
|
|
/// - Access the resource from the highest priority task.
|
|
|
|
/// - Access the resource from within a critical section that sets the
|
|
|
|
/// system ceiling to `C`.
|
|
|
|
pub unsafe fn get_mut(&'static self) -> &'static mut T {
|
|
|
|
get_check(C::ceiling());
|
2017-04-03 23:18:26 +02:00
|
|
|
|
|
|
|
&mut *self.data.get()
|
2017-04-03 03:42:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Locks the resource, preventing tasks with priority lower than `Ceiling`
|
|
|
|
/// from preempting the current task
|
|
|
|
pub fn lock<F, R, Ctxt>(&'static self, _ctxt: &Ctxt, f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&T, C) -> R,
|
|
|
|
Ctxt: Context,
|
|
|
|
{
|
2017-04-03 23:18:26 +02:00
|
|
|
unsafe { lock(f, self.data.get(), C::hw_ceiling()) }
|
2017-04-03 03:42:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Mutably locks the resource, preventing tasks with priority lower than
|
|
|
|
/// `Ceiling` from preempting the current task
|
|
|
|
pub fn lock_mut<F, R, Ctxt>(&'static self, _ctxt: &mut Ctxt, f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&mut T, C) -> R,
|
|
|
|
Ctxt: Context,
|
|
|
|
{
|
2017-04-03 23:18:26 +02:00
|
|
|
unsafe { lock_mut(f, self.data.get(), C::hw_ceiling()) }
|
2017-04-03 03:42:38 +02:00
|
|
|
}
|
2017-03-10 05:59:50 +01:00
|
|
|
}
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
impl<T> Resource<T, C0> {
|
|
|
|
/// Borrows the resource without locking
|
|
|
|
pub fn borrow<'ctxt, Ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt T
|
2017-03-11 05:58:17 +01:00
|
|
|
where
|
|
|
|
Ctxt: Context,
|
2017-03-10 05:59:50 +01:00
|
|
|
{
|
2017-03-08 14:10:58 +01:00
|
|
|
unsafe { &*self.data.get() }
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
2017-03-11 05:58:17 +01:00
|
|
|
|
|
|
|
/// 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() }
|
|
|
|
}
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
unsafe impl<T, Ceiling> Sync for Resource<T, Ceiling> {}
|
2017-03-05 06:26:14 +01:00
|
|
|
|
2017-04-03 23:18:26 +02:00
|
|
|
/// Maps a hardware priority to a logical priority
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-04-03 23:18:26 +02:00
|
|
|
fn hardware(priority: u8) -> u8 {
|
|
|
|
16 - (priority >> (8 - PRIORITY_BITS))
|
|
|
|
}
|
|
|
|
|
2017-03-05 06:26:14 +01:00
|
|
|
/// 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)
|
2017-03-08 14:10:58 +01:00
|
|
|
///
|
2017-03-12 00:02:11 +01:00
|
|
|
/// NOTE Input `priority` must be in the range `[1, 16]` (inclusive)
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-12 00:02:11 +01:00
|
|
|
pub fn logical(priority: u8) -> u8 {
|
|
|
|
assert!(priority >= 1 && priority <= 16);
|
2017-03-08 14:10:58 +01:00
|
|
|
|
2017-03-12 00:02:11 +01:00
|
|
|
((1 << PRIORITY_BITS) - priority) << (8 - PRIORITY_BITS)
|
2017-03-05 06:26:14 +01:00
|
|
|
}
|
2017-03-10 05:59:50 +01:00
|
|
|
|
2017-04-04 22:36:23 +02:00
|
|
|
/// Puts `interrupt` in the "to execute" queue
|
|
|
|
///
|
|
|
|
/// This function has no effect if the interrupt was already queued
|
2017-04-04 23:37:01 +02:00
|
|
|
pub fn queue<I>(interrupt: I)
|
|
|
|
where
|
|
|
|
I: Nr,
|
|
|
|
{
|
2017-04-04 22:36:23 +02:00
|
|
|
unsafe {
|
|
|
|
// NOTE(safe) atomic write
|
|
|
|
(*NVIC.get()).set_pending(interrupt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
/// Fake ceiling, indicates that the resource is shared by cooperative tasks
|
|
|
|
pub struct C0 {
|
|
|
|
_0: (),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A real ceiling
|
|
|
|
// XXX this should be a "closed" trait
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-10 05:59:50 +01:00
|
|
|
pub unsafe trait Ceiling {
|
2017-04-03 23:18:26 +02:00
|
|
|
/// Returns the logical ceiling as a number
|
2017-03-10 05:59:50 +01:00
|
|
|
fn ceiling() -> u8;
|
2017-04-03 23:18:26 +02:00
|
|
|
|
|
|
|
/// Returns the HW ceiling as a number
|
|
|
|
fn hw_ceiling() -> u8;
|
2017-03-10 05:59:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Usable as a ceiling
|
2017-03-11 22:12:58 +01:00
|
|
|
// XXX this should be a "closed" trait
|
2017-03-10 05:59:50 +01:00
|
|
|
pub unsafe trait CeilingLike {}
|
|
|
|
|
2017-03-11 22:12:58 +01:00
|
|
|
/// This ceiling is lower than `C`
|
|
|
|
// XXX this should be a "closed" trait
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-03-11 22:12:58 +01:00
|
|
|
pub unsafe trait HigherThan<C> {}
|
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
2017-04-03 23:18:26 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(thumbv6m)]
|
|
|
|
macro_rules! ceiling {
|
|
|
|
($($tt:tt)*) => {};
|
|
|
|
}
|
|
|
|
|
2017-04-03 23:18:26 +02:00
|
|
|
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);
|
|
|
|
|
2017-04-06 21:06:33 +02:00
|
|
|
#[cfg(not(thumbv6m))]
|
|
|
|
macro_rules! higher_than {
|
|
|
|
() => {};
|
|
|
|
($lowest:ident, $($higher:ident,)*) => {
|
|
|
|
$(
|
|
|
|
unsafe impl HigherThan<$lowest> for $higher {}
|
|
|
|
)*
|
|
|
|
|
|
|
|
higher_than!($($higher,)*);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(thumbv6m)]
|
|
|
|
macro_rules! higher_than {
|
|
|
|
($($tt:tt)*) => {};
|
|
|
|
}
|
|
|
|
|
|
|
|
higher_than! {
|
|
|
|
C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15,
|
|
|
|
}
|
2017-03-11 22:12:58 +01:00
|
|
|
|
2017-03-10 05:59:50 +01:00
|
|
|
unsafe impl CeilingLike for C0 {}
|