diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index d1265ffc4..ea62c2387 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add PIO I2S input - Add PIO onewire parasite power strong pullup - add `wait_for_alarm` and `alarm_scheduled` methods to rtc module ([#4216](https://github.com/embassy-rs/embassy/pull/4216)) +- rp235x: use msplim for stack guard instead of MPU ## 0.8.0 - 2025-08-26 diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 6fb680b34..d03ba1fef 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -565,18 +565,10 @@ unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { #[cfg(all(feature = "_rp235x", not(feature = "_test")))] #[inline(always)] unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { - let core = unsafe { cortex_m::Peripherals::steal() }; + // The RP2350 arm cores are cortex-m33 and can use the MSPLIM register to guard the end of stack. + // We'll need to do something else for the riscv cores. + cortex_m::register::msplim::write(stack_bottom.addr() as u32); - // Fail if MPU is already configured - if core.MPU.ctrl.read() != 0 { - return Err(()); - } - - unsafe { - core.MPU.ctrl.write(5); // enable mpu with background default map - core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address - core.MPU.rlar.write(((stack_bottom as usize + 255) as u32) | 1); - } Ok(()) } diff --git a/examples/rp235x/src/bin/multicore_stack_overflow.rs b/examples/rp235x/src/bin/multicore_stack_overflow.rs new file mode 100644 index 000000000..dba44aa23 --- /dev/null +++ b/examples/rp235x/src/bin/multicore_stack_overflow.rs @@ -0,0 +1,72 @@ +//! This example tests stack overflow handling on core1 of the RP235x chip. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Executor; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +const CORE1_STACK_LENGTH: usize = 4096; + +static mut CORE1_STACK: Stack = Stack::new(); +static EXECUTOR0: StaticCell = StaticCell::new(); +static EXECUTOR1: StaticCell = StaticCell::new(); + +#[cortex_m_rt::entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + let led = Output::new(p.PIN_25, Level::Low); + + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| spawner.spawn(unwrap!(core1_task()))); + }, + ); + + let executor0 = EXECUTOR0.init(Executor::new()); + executor0.run(|spawner| spawner.spawn(unwrap!(core0_task(led)))); +} + +#[embassy_executor::task] +async fn core0_task(mut led: Output<'static>) { + info!("Hello from core 0"); + loop { + info!("core 0 still alive"); + led.set_high(); + Timer::after_millis(500).await; + led.set_low(); + Timer::after_millis(500).await; + } +} + +fn blow_my_stack() { + // Allocating an array a little larger than our stack should ensure a stack overflow when it is used. + let t = [0u8; CORE1_STACK_LENGTH + 64]; + + info!("Array initialised without error"); + // We need to use black_box to otherwise the compiler is too smart and will optimise all of this away. + // We shouldn't get to this code - the initialisation above will touch the stack guard. + for ref i in t { + let _data = core::hint::black_box(*i) + 1; + } +} + +#[embassy_executor::task] +async fn core1_task() { + info!("Hello from core 1"); + + blow_my_stack(); + + loop { + info!("core 1 still alive"); + Timer::after_millis(1000).await; + } +}