#![allow(clippy::missing_inline_in_public_items)]
use core::{
cell::UnsafeCell,
sync::atomic::{AtomicBool, Ordering},
};
pub struct StackHandle(*mut u32, usize);
impl StackHandle {
pub fn top(&mut self) -> *mut u32 {
unsafe { self.0.add(self.1) }
}
pub fn bottom(&mut self) -> *mut u32 {
self.0
}
}
#[repr(align(8), C)]
pub struct Stack<const N: usize> {
space: UnsafeCell<[u32; N]>,
taken: AtomicBool,
}
impl<const N: usize> Stack<N> {
pub const fn new() -> Stack<N> {
Stack {
space: UnsafeCell::new([0; N]),
taken: AtomicBool::new(false),
}
}
pub fn take_handle(&self) -> StackHandle {
if self.taken.load(Ordering::Acquire) {
panic!("Cannot get two handles to one stack!");
}
self.taken.store(true, Ordering::Release);
let start = self.space.get() as *mut u32;
StackHandle(start, 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()
}
}
pub fn switch_to_unprivileged_psp(mut psp_stack: StackHandle, function: extern "C" fn() -> !) -> ! {
#[cfg(armv8m_main)]
unsafe {
crate::register::psplim::write(psp_stack.bottom() as u32);
}
unsafe {
crate::asm::enter_unprivileged_psp(psp_stack.top(), function);
}
}
pub fn switch_to_privileged_psp(mut psp_stack: StackHandle, function: extern "C" fn() -> !) -> ! {
#[cfg(armv8m_main)]
unsafe {
crate::register::psplim::write(psp_stack.bottom() as u32);
}
unsafe {
crate::asm::enter_privileged_psp(psp_stack.top(), function);
}
}