diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 4f205a16e..50f028d4c 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -219,6 +219,74 @@ select_bootloader! { default => BOOT_LOADER_W25Q080 } +/// Installs a stack guard for the CORE0 stack in MPU region 0. +/// Will fail if the MPU is already confgigured. This function requires +/// a `_stack_end` symbol to be defined by the linker script, and expexcts +/// `_stack_end` to be located at the lowest address (largest depth) of +/// the stack. +/// +/// This method can *only* set up stack guards on the currently +/// executing core. Stack guards for CORE1 are set up automatically, +/// only CORE0 should ever use this. +/// +/// # Usage +/// +/// ```no_run +/// #![feature(type_alias_impl_trait)] +/// use embassy_rp::install_core0_stack_guard; +/// use embassy_executor::{Executor, Spawner}; +/// +/// #[embassy_executor::main] +/// async fn main(_spawner: Spawner) { +/// // set up by the linker as follows: +/// // +/// // MEMORY { +/// // STACK0: ORIGIN = 0x20040000, LENGTH = 4K +/// // } +/// // +/// // _stack_end = ORIGIN(STACK0); +/// // _stack_start = _stack_end + LENGTH(STACK0); +/// // +/// install_core0_stack_guard().expect("MPU already configured"); +/// let p = embassy_rp::init(Default::default()); +/// +/// // ... +/// } +/// ``` +pub fn install_core0_stack_guard() -> Result<(), ()> { + extern "C" { + static mut _stack_end: usize; + } + unsafe { install_stack_guard(&mut _stack_end as *mut usize) } +} + +#[inline(always)] +fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { + let core = unsafe { cortex_m::Peripherals::steal() }; + + // Fail if MPU is already configured + if core.MPU.ctrl.read() != 0 { + return Err(()); + } + + // The minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will + // just shorten the valid stack range a tad. + let addr = (stack_bottom as u32 + 31) & !31; + // Mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want + let subregion_select = 0xff ^ (1 << ((addr >> 5) & 7)); + unsafe { + core.MPU.ctrl.write(5); // enable mpu with background default map + core.MPU.rbar.write((addr & !0xff) | (1 << 4)); // set address and update RNR + core.MPU.rasr.write( + 1 // enable region + | (0x7 << 1) // size 2^(7 + 1) = 256 + | (subregion_select << 8) + | 0x10000000, // XN = disable instruction fetch; no other bits means no permissions + ); + } + Ok(()) +} + pub mod config { use crate::clocks::ClockConfig; diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 89a2680ad..915761801 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -52,41 +52,20 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; use crate::interrupt::InterruptExt; use crate::peripherals::CORE1; -use crate::{gpio, interrupt, pac}; +use crate::{gpio, install_stack_guard, interrupt, pac}; const PAUSE_TOKEN: u32 = 0xDEADBEEF; const RESUME_TOKEN: u32 = !0xDEADBEEF; static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); #[inline(always)] -fn install_stack_guard(stack_bottom: *mut usize) { - let core = unsafe { cortex_m::Peripherals::steal() }; - - // Trap if MPU is already configured - if core.MPU.ctrl.read() != 0 { +fn core1_setup(stack_bottom: *mut usize) { + if let Err(_) = install_stack_guard(stack_bottom) { + // currently only happens if the MPU was already set up, which + // would indicate that the core is already in use from outside + // embassy, somehow. trap if so since we can't deal with that. cortex_m::asm::udf(); } - - // The minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will - // just shorten the valid stack range a tad. - let addr = (stack_bottom as u32 + 31) & !31; - // Mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want - let subregion_select = 0xff ^ (1 << ((addr >> 5) & 7)); - unsafe { - core.MPU.ctrl.write(5); // enable mpu with background default map - core.MPU.rbar.write((addr & !0xff) | (1 << 4)); // set address and update RNR - core.MPU.rasr.write( - 1 // enable region - | (0x7 << 1) // size 2^(7 + 1) = 256 - | (subregion_select << 8) - | 0x10000000, // XN = disable instruction fetch; no other bits means no permissions - ); - } -} - -#[inline(always)] -fn core1_setup(stack_bottom: *mut usize) { - install_stack_guard(stack_bottom); unsafe { gpio::init(); }