rtic/src/lib.rs

459 lines
9.3 KiB
Rust
Raw Normal View History

2017-03-05 06:26:14 +01:00
//! Stack Resource Policy for Cortex-M processors
//!
//! NOTE ARMv6-M is not supported at the moment.
#![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-03-11 02:11:36 +01:00
use cortex_m::ctxt::Context;
use cortex_m::peripheral::Peripheral;
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;
// 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
// XXX Do we need memory / instruction / compiler barriers here?
2017-03-05 06:26:14 +01:00
#[inline(always)]
unsafe fn claim<T, R, F>(f: F, res: *const T, ceiling: u8) -> R
where
F: FnOnce(&T) -> R,
{
let old_basepri = basepri::read();
basepri_max::write(ceiling);
let ret = f(&*res);
basepri::write(old_basepri);
ret
2017-03-05 06:26:14 +01:00
}
// XXX Do we need memory / instruction / compiler barriers here?
#[inline(always)]
unsafe fn claim_mut<T, R, F>(f: F, res: *mut T, ceiling: u8) -> R
where
F: FnOnce(&mut T) -> R,
{
let old_basepri = basepri::read();
basepri_max::write(ceiling);
let ret = f(&mut *res);
basepri::write(old_basepri);
ret
}
/// A peripheral as a resource
2017-03-10 05:59:50 +01:00
pub struct ResourceP<P, Ceiling>
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>
where
C: CeilingLike,
2017-03-10 05:59:50 +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 {
ResourceP {
2017-03-10 05:59:50 +01:00
_marker: PhantomData,
peripheral: p,
2017-03-05 06:26:14 +01: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<P, C> ResourceP<P, C>
where
C: Ceiling,
2017-03-10 05:59:50 +01:00
{
/// Borrows the resource without locking
// TODO document unsafety
pub unsafe fn borrow<'ctxt, Ctxt>(
&'static self,
_ctxt: &'ctxt Ctxt,
) -> &'ctxt P
where
Ctxt: Context,
2017-03-05 06:26:14 +01:00
{
2017-03-10 05:59:50 +01:00
&*self.peripheral.get()
2017-03-05 06:26:14 +01:00
}
/// Mutably borrows the resource without locking
// TODO document unsafety
pub unsafe fn borrow_mut<'ctxt, Ctxt>(
&'static self,
_ctxt: &'ctxt mut Ctxt,
) -> &'ctxt mut P
where
Ctxt: Context,
{
&mut *self.peripheral.get()
}
/// 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
F: FnOnce(&P) -> R,
Ctxt: Context,
2017-03-10 05:59:50 +01:00
{
unsafe { claim(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<R, F, Ctxt>(&'static self, _ctxt: &mut Ctxt, f: F) -> R
where
F: FnOnce(&mut P) -> R,
Ctxt: Context,
{
unsafe { claim_mut(f, self.peripheral.get(), C::ceiling()) }
}
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
where
Ctxt: Context,
2017-03-10 05:59:50 +01:00
{
unsafe { &*self.peripheral.get() }
2017-03-05 06:26:14 +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> {}
/// 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> {
/// 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
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-10 05:59:50 +01:00
}
2017-03-05 06:26:14 +01:00
2017-03-10 05:59:50 +01:00
impl<T, C> Resource<T, C>
where
C: Ceiling,
2017-03-10 05:59:50 +01: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) -> R,
Ctxt: Context,
2017-03-05 06:26:14 +01:00
{
2017-03-10 05:59:50 +01:00
unsafe { claim(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<F, R, Ctxt>(&'static self, _ctxt: &mut Ctxt, f: F) -> R
where
F: FnOnce(&mut T) -> R,
Ctxt: Context,
{
unsafe { claim_mut(f, self.data.get(), C::ceiling()) }
}
2017-03-10 05:59:50 +01:00
/// Borrows the resource, without locking
pub unsafe fn borrow<'ctxt, Ctxt>(
&'static self,
_ctxt: &'ctxt Ctxt,
) -> &'ctxt T
where
Ctxt: Context,
2017-03-10 05:59:50 +01:00
{
&*self.data.get()
2017-03-05 06:26:14 +01:00
}
/// Mutably borrows the resource, without locking
pub unsafe fn borrow_mut<'ctxt, Ctxt>(
&'static self,
_ctxt: &'ctxt mut Ctxt,
) -> &'ctxt mut T
where
Ctxt: Context,
{
&mut *self.data.get()
}
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
where
Ctxt: Context,
2017-03-10 05:59:50 +01:00
{
unsafe { &*self.data.get() }
2017-03-05 06:26:14 +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
/// 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 `logical` must be in the range `[1, 15]` (inclusive)
2017-03-10 16:56:08 +01:00
pub const fn logical(priority: u8) -> u8 {
// NOTE elements 1 and 2 of the tuple are a poor man's const context range
// checker
2017-03-10 16:56:08 +01:00
(((1 << PRIORITY_BITS) - priority) << (8 - PRIORITY_BITS),
priority - 1,
priority + 240)
.0
2017-03-05 06:26:14 +01:00
}
2017-03-10 05:59:50 +01:00
/// 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
pub unsafe trait CeilingLike {}
unsafe impl Ceiling for C1 {
fn ceiling() -> u8 {
((1 << 4) - 1) << 4
}
}
unsafe impl Ceiling for C2 {
fn ceiling() -> u8 {
((1 << 4) - 2) << 4
}
}
unsafe impl Ceiling for C3 {
fn ceiling() -> u8 {
((1 << 4) - 3) << 4
}
}
unsafe impl Ceiling for C4 {
fn ceiling() -> u8 {
((1 << 4) - 4) << 4
}
}
unsafe impl Ceiling for C5 {
fn ceiling() -> u8 {
((1 << 4) - 5) << 4
}
}
unsafe impl Ceiling for C6 {
fn ceiling() -> u8 {
((1 << 4) - 6) << 4
}
}
unsafe impl Ceiling for C7 {
fn ceiling() -> u8 {
((1 << 4) - 7) << 4
}
}
unsafe impl Ceiling for C8 {
fn ceiling() -> u8 {
((1 << 4) - 8) << 4
}
}
unsafe impl Ceiling for C9 {
fn ceiling() -> u8 {
((1 << 4) - 9) << 4
}
}
unsafe impl Ceiling for C10 {
fn ceiling() -> u8 {
((1 << 4) - 10) << 4
}
}
unsafe impl Ceiling for C11 {
fn ceiling() -> u8 {
((1 << 4) - 11) << 4
}
}
unsafe impl Ceiling for C12 {
fn ceiling() -> u8 {
((1 << 4) - 12) << 4
}
}
unsafe impl Ceiling for C13 {
fn ceiling() -> u8 {
((1 << 4) - 13) << 4
}
}
unsafe impl Ceiling for C14 {
fn ceiling() -> u8 {
((1 << 4) - 14) << 4
}
}
unsafe impl Ceiling for C15 {
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 {}