diff --git a/cortex-m/src/psp.rs b/cortex-m/src/psp.rs index 36b663f2..9979669a 100644 --- a/cortex-m/src/psp.rs +++ b/cortex-m/src/psp.rs @@ -79,29 +79,48 @@ impl core::default::Default for Stack { /// In Unprivileged Mode, code can no longer perform privileged operations, /// such as disabling interrupts. /// -#[cfg(cortex_m)] -pub fn switch_to_unprivileged_psp(mut psp_stack: StackHandle, function: extern "C" fn() -> !) -> ! { - // set the stack limit - #[cfg(armv8m_main)] - unsafe { - crate::register::psplim::write(psp_stack.bottom() as u32); +pub fn switch_to_unprivileged_psp(psp_stack: StackHandle, function: extern "C" fn() -> !) -> ! { + #[cfg(cortex_m)] + { + let mut psp_stack = psp_stack; + // set the stack limit + #[cfg(armv8m_main)] + unsafe { + crate::register::psplim::write(psp_stack.bottom() as u32); + } + // do the switch + unsafe { + crate::asm::enter_unprivileged_psp(psp_stack.top(), function); + } } - // do the switch - unsafe { - crate::asm::enter_unprivileged_psp(psp_stack.top(), function); + #[cfg(not(cortex_m))] + { + _ = psp_stack; + _ = function; + unimplemented!() } } /// Switch to running on the Process Stack Pointer (PSP), but remain in privileged mode #[cfg(cortex_m)] -pub fn switch_to_privileged_psp(mut psp_stack: StackHandle, function: extern "C" fn() -> !) -> ! { - // set the stack limit - #[cfg(armv8m_main)] - unsafe { - crate::register::psplim::write(psp_stack.bottom() as u32); +pub fn switch_to_privileged_psp(psp_stack: StackHandle, function: extern "C" fn() -> !) -> ! { + #[cfg(cortex_m)] + { + let mut psp_stack = psp_stack; + // set the stack limit + #[cfg(armv8m_main)] + unsafe { + crate::register::psplim::write(psp_stack.bottom() as u32); + } + // do the switch + unsafe { + crate::asm::enter_privileged_psp(psp_stack.top(), function); + } } - // do the switch - unsafe { - crate::asm::enter_privileged_psp(psp_stack.top(), function); + #[cfg(not(cortex_m))] + { + _ = psp_stack; + _ = function; + unimplemented!() } } diff --git a/testsuite/src/main.rs b/testsuite/src/main.rs index 5aa22037..259c2f3a 100644 --- a/testsuite/src/main.rs +++ b/testsuite/src/main.rs @@ -12,7 +12,9 @@ fn panic(info: &core::panic::PanicInfo) -> ! { minitest::fail() } -static EXCEPTION_FLAG: AtomicBool = AtomicBool::new(false); +static PENDSV_FLAG: AtomicBool = AtomicBool::new(false); +static SVCALL_FLAG: AtomicBool = AtomicBool::new(false); +static WANT_FAULT: AtomicBool = AtomicBool::new(false); const STACK_SIZE_WORDS: usize = 1024; @@ -20,12 +22,30 @@ static STACK: cortex_m::psp::Stack = cortex_m::psp::Stack::new #[cortex_m_rt::exception] fn PendSV() { - EXCEPTION_FLAG.store(true, Ordering::SeqCst); + minitest::log!("Hit PendSV!"); + PENDSV_FLAG.store(true, Ordering::SeqCst); +} + +#[cortex_m_rt::exception] +fn SVCall() { + minitest::log!("Handling SWI :)"); + SVCALL_FLAG.store(true, Ordering::SeqCst); +} + +#[cortex_m_rt::exception] +unsafe fn HardFault(frame: &cortex_m_rt::ExceptionFrame) -> ! { + minitest::log!("{:?}", frame); + if WANT_FAULT.load(Ordering::Relaxed) { + minitest::log!("Trapped breakpoint OK!"); + minitest::exit() + } else { + minitest::fail() + } } #[minitest::tests] mod tests { - use crate::{EXCEPTION_FLAG, Ordering}; + use crate::{Ordering, PENDSV_FLAG}; use minitest::log; #[init] @@ -67,28 +87,28 @@ mod tests { #[test] fn critical_section_nesting() { - EXCEPTION_FLAG.store(false, Ordering::SeqCst); + PENDSV_FLAG.store(false, Ordering::SeqCst); critical_section::with(|_| { critical_section::with(|_| { cortex_m::peripheral::SCB::set_pendsv(); - assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst)); + assert!(!PENDSV_FLAG.load(Ordering::SeqCst)); }); - assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst)); + assert!(!PENDSV_FLAG.load(Ordering::SeqCst)); }); - assert!(EXCEPTION_FLAG.load(Ordering::SeqCst)); + assert!(PENDSV_FLAG.load(Ordering::SeqCst)); } #[test] fn interrupt_free_nesting() { - EXCEPTION_FLAG.store(false, Ordering::SeqCst); + PENDSV_FLAG.store(false, Ordering::SeqCst); cortex_m::interrupt::free(|_| { cortex_m::interrupt::free(|_| { cortex_m::peripheral::SCB::set_pendsv(); - assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst)); + assert!(!PENDSV_FLAG.load(Ordering::SeqCst)); }); - assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst)); + assert!(!PENDSV_FLAG.load(Ordering::SeqCst)); }); - assert!(EXCEPTION_FLAG.load(Ordering::SeqCst)); + assert!(PENDSV_FLAG.load(Ordering::SeqCst)); } #[test] @@ -99,4 +119,61 @@ mod tests { let delta = unsafe { top.offset_from(bottom) }; assert_eq!(delta as usize, super::STACK_SIZE_WORDS); } + + #[test] + fn check_asm() { + // Data Memory Barrier - harmless + cortex_m::asm::dmb(); + // Data Sync Barrier - harmless + cortex_m::asm::dsb(); + // Instruction Sync Barrier - harmless + cortex_m::asm::isb(); + // A NOP loop - harmless + cortex_m::asm::delay(100); + // A single NOP - harmless + cortex_m::asm::nop(); + // Set the event flag + cortex_m::asm::sev(); + // Wait for Event (will not block - flag is set) + cortex_m::asm::wfe(); + // Pend an interrupt, the wait for it + cortex_m::peripheral::SCB::set_pendsv(); + cortex_m::interrupt::free(|_| { + cortex_m::peripheral::SCB::set_pendsv(); + // wfi will turn interrupts back on + cortex_m::asm::wfi(); + }); + // Print to the debug console with a semihosting syscall + let msg = c"This is a test\n"; + const SYS_WRITE0: u32 = 0x04; + unsafe { + cortex_m::asm::semihosting_syscall(SYS_WRITE0, msg.as_ptr() as usize as u32); + } + } + + // this test must be last! + #[test] + fn run_psp() { + static STACK: cortex_m::psp::Stack<4096> = cortex_m::psp::Stack::new(); + minitest::log!("Switching to PSP..."); + cortex_m::psp::switch_to_unprivileged_psp(STACK.take_handle(), crate::user_fn); + } +} + +/// This code runs on the Process Stack Pointer (i.e. "User mode") +extern "C" fn user_fn() -> ! { + // should not be set + assert!(!SVCALL_FLAG.load(Ordering::SeqCst)); + // this should fire the SVCall handler + unsafe { + core::arch::asm!("swi 0x00"); + } + // check we hit the SVCall handler + assert!(SVCALL_FLAG.load(Ordering::SeqCst)); + // now test breakpoints, and exit the tests at the same time + // (bkpt will trip the HardFault handler) + crate::WANT_FAULT.store(true, Ordering::Relaxed); + loop { + cortex_m::asm::bkpt(); + } }