aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorJorge Aparicio <japaricious@gmail.com>2017-03-05 00:26:14 -0500
committerJorge Aparicio <japaricious@gmail.com>2017-03-05 00:29:08 -0500
commitaba93337993e6be0291199631f7ed6b0f90adf38 (patch)
treed4f3974e8f77074234618a8c1f0cff32ec261037 /src/lib.rs
initial commit
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..62dd508
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,170 @@
+//! Stack Resource Policy for Cortex-M processors
+//!
+//! NOTE ARMv6-M is not supported at the moment.
+
+#![feature(asm)]
+#![feature(const_fn)]
+#![no_std]
+
+// NOTE Only the 4 highest bits of the priority byte (BASEPRI / NVIC.IPR) are
+// considered when determining priorities.
+const PRIORITY_BITS: u8 = 4;
+
+extern crate cortex_m;
+
+use cortex_m::interrupt::CsToken;
+use cortex_m::register::{basepri, basepri_max};
+
+use core::cell::UnsafeCell;
+use core::marker::PhantomData;
+
+// XXX why is this needed?
+#[inline(always)]
+fn compiler_barrier() {
+ unsafe {
+ asm!(""
+ :
+ :
+ : "memory"
+ : "volatile")
+ }
+}
+
+// XXX why is this needed?
+#[inline(always)]
+fn memory_barrier() {
+ unsafe {
+ asm!("dsb
+ isb"
+ :
+ :
+ : "memory"
+ : "volatile")
+ }
+}
+
+pub struct Peripheral<T>
+ where T: 'static
+{
+ _ty: PhantomData<&'static mut T>,
+ address: usize,
+ ceiling: u8,
+}
+
+impl<T> Peripheral<T> {
+ pub const unsafe fn new(address: usize, ceiling: u8) -> Self {
+ Peripheral {
+ _ty: PhantomData,
+ address: address,
+ ceiling: ceiling,
+ }
+ }
+
+ pub fn claim<F, R>(&self, f: F) -> R
+ where F: FnOnce(&T) -> R
+ {
+ unsafe {
+ let old_basepri = basepri::read();
+ basepri_max::write(priority(self.ceiling));
+ memory_barrier();
+ let ret = f(&*(self.address as *const T));
+ compiler_barrier();
+ basepri::write(old_basepri);
+ ret
+ }
+ }
+
+ pub fn claim_mut<F, R>(&self, f: F) -> R
+ where F: FnOnce(&mut T) -> R
+ {
+ unsafe {
+ let old_basepri = basepri::read();
+ basepri_max::write(priority(self.ceiling));
+ memory_barrier();
+ let ret = f(&mut *(self.address as *mut T));
+ compiler_barrier();
+ basepri::write(old_basepri);
+ ret
+ }
+ }
+
+ pub fn take<'a>(&self, _token: &'a CsToken) -> &'a T {
+ unsafe {
+ &*(self.address as *const T)
+ }
+ }
+
+ pub fn take_mut<'a>(&self, _token: &'a CsToken) -> &'a mut T {
+ unsafe {
+ &mut *(self.address as *mut T)
+ }
+ }
+}
+
+pub struct Resource<T> {
+ ceiling: u8,
+ data: UnsafeCell<T>,
+}
+
+impl<T> Resource<T> {
+ pub const fn new(data: T, ceiling: u8) -> Self {
+ Resource {
+ ceiling: ceiling,
+ data: UnsafeCell::new(data),
+ }
+ }
+
+ pub fn claim<F, R>(&self, f: F) -> R
+ where F: FnOnce(&T) -> R
+ {
+ unsafe {
+ let old_basepri = basepri::read();
+ basepri_max::write(priority(self.ceiling));
+ memory_barrier();
+ let ret = f(&*self.data.get());
+ compiler_barrier();
+ basepri::write(old_basepri);
+ ret
+ }
+ }
+
+ pub fn claim_mut<F, R>(&self, f: F) -> R
+ where F: FnOnce(&mut T) -> R
+ {
+ unsafe {
+ let old_basepri = basepri::read();
+ basepri_max::write(priority(self.ceiling));
+ memory_barrier();
+ let ret = f(&mut *self.data.get());
+ compiler_barrier();
+ basepri::write(old_basepri);
+ ret
+ }
+ }
+
+ pub fn take<'a>(&self, _token: &'a CsToken) -> &'a T {
+ unsafe {
+ &*self.data.get()
+ }
+ }
+
+ pub fn take_mut<'a>(&self, _token: &'a CsToken) -> &'a mut T {
+ unsafe {
+ &mut *self.data.get()
+ }
+ }
+}
+
+unsafe impl<T> Sync for Resource<T> {}
+
+/// 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)
+// TODO review the handling extreme value
+pub fn priority(logical: u8) -> u8 {
+ ((1 << PRIORITY_BITS) - logical) << (8 - PRIORITY_BITS)
+}