Skip to content
28 changes: 15 additions & 13 deletions cortex-m/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,21 @@ pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
/// it, you may wish to set the `PSPLIM` register to guard against this.
#[cfg(cortex_m)]
#[inline(always)]
pub unsafe fn enter_unprivileged(psp: *const u32, entry: fn() -> !) -> ! {
core::arch::asm!(
"mrs {tmp}, CONTROL",
"orr {tmp}, #3",
"msr PSP, {psp}",
"msr CONTROL, {tmp}",
"isb",
"bx {ent}",
tmp = in(reg) 0,
psp = in(reg) psp,
ent = in(reg) entry,
options(noreturn, nomem, nostack)
);
pub unsafe fn enter_unprivileged(psp: *const u32, entry: extern "C" fn() -> !) -> ! {
unsafe {
core::arch::asm!(
"mrs {tmp}, CONTROL",
"orr {tmp}, #3",
"msr PSP, {psp}",
"msr CONTROL, {tmp}",
"isb",
"bx {ent}",
tmp = in(reg) 0,
psp = in(reg) psp,
ent = in(reg) entry,
options(noreturn, nostack)
);
}
}

/// Bootstrap.
Expand Down
1 change: 1 addition & 0 deletions cortex-m/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub mod interrupt;
pub mod itm;
pub mod peripheral;
pub mod prelude;
pub mod psp;
pub mod register;

pub use crate::peripheral::Peripherals;
Expand Down
52 changes: 52 additions & 0 deletions cortex-m/src/psp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//! Process Stack Pointer support

// This is a useful lint for functions like 'asm::wfi()' but it's not a useful
// lint here.
#![allow(clippy::missing_inline_in_public_items)]

use core::cell::UnsafeCell;

/// A stack you can use as your Process Stack (PSP)
///
/// The const-param N is the size **in 32-bit words**
#[repr(align(8), C)]
pub struct Stack<const N: usize> {
space: UnsafeCell<[u32; N]>,
}

impl<const N: usize> Stack<N> {
/// Const-initialise a Stack
///
/// Use a turbofish to specify the size, like:
///
/// ```rust
/// # use cortex_m::psp::Stack;
/// static PSP_STACK: Stack::<4096> = Stack::new();
/// ```
pub const fn new() -> Stack<N> {
Stack {
space: UnsafeCell::new([0; N]),
}
}

/// Return the top of the stack
pub fn get_top(&self) -> *mut u32 {
let start = self.space.get() as *mut u32;
unsafe { start.add(N) }
}
}

unsafe impl<const N: usize> Sync for Stack<N> {}

impl<const N: usize> core::default::Default for Stack<N> {
fn default() -> Self {
Stack::new()
}
}

/// Switch to running on the PSP
#[cfg(cortex_m)]
pub fn switch_to_psp<const N: usize>(psp_stack: &Stack<N>, function: extern "C" fn() -> !) -> ! {
let stack_top = psp_stack.get_top();
unsafe { crate::asm::enter_unprivileged(stack_top, function) }
}
Loading