aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/lib.rs68
-rw-r--r--embassy-rp/src/multicore.rs33
2 files changed, 74 insertions, 27 deletions
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! {
219 default => BOOT_LOADER_W25Q080 219 default => BOOT_LOADER_W25Q080
220} 220}
221 221
222/// Installs a stack guard for the CORE0 stack in MPU region 0.
223/// Will fail if the MPU is already confgigured. This function requires
224/// a `_stack_end` symbol to be defined by the linker script, and expexcts
225/// `_stack_end` to be located at the lowest address (largest depth) of
226/// the stack.
227///
228/// This method can *only* set up stack guards on the currently
229/// executing core. Stack guards for CORE1 are set up automatically,
230/// only CORE0 should ever use this.
231///
232/// # Usage
233///
234/// ```no_run
235/// #![feature(type_alias_impl_trait)]
236/// use embassy_rp::install_core0_stack_guard;
237/// use embassy_executor::{Executor, Spawner};
238///
239/// #[embassy_executor::main]
240/// async fn main(_spawner: Spawner) {
241/// // set up by the linker as follows:
242/// //
243/// // MEMORY {
244/// // STACK0: ORIGIN = 0x20040000, LENGTH = 4K
245/// // }
246/// //
247/// // _stack_end = ORIGIN(STACK0);
248/// // _stack_start = _stack_end + LENGTH(STACK0);
249/// //
250/// install_core0_stack_guard().expect("MPU already configured");
251/// let p = embassy_rp::init(Default::default());
252///
253/// // ...
254/// }
255/// ```
256pub fn install_core0_stack_guard() -> Result<(), ()> {
257 extern "C" {
258 static mut _stack_end: usize;
259 }
260 unsafe { install_stack_guard(&mut _stack_end as *mut usize) }
261}
262
263#[inline(always)]
264fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
265 let core = unsafe { cortex_m::Peripherals::steal() };
266
267 // Fail if MPU is already configured
268 if core.MPU.ctrl.read() != 0 {
269 return Err(());
270 }
271
272 // The minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
273 // just shorten the valid stack range a tad.
274 let addr = (stack_bottom as u32 + 31) & !31;
275 // Mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
276 let subregion_select = 0xff ^ (1 << ((addr >> 5) & 7));
277 unsafe {
278 core.MPU.ctrl.write(5); // enable mpu with background default map
279 core.MPU.rbar.write((addr & !0xff) | (1 << 4)); // set address and update RNR
280 core.MPU.rasr.write(
281 1 // enable region
282 | (0x7 << 1) // size 2^(7 + 1) = 256
283 | (subregion_select << 8)
284 | 0x10000000, // XN = disable instruction fetch; no other bits means no permissions
285 );
286 }
287 Ok(())
288}
289
222pub mod config { 290pub mod config {
223 use crate::clocks::ClockConfig; 291 use crate::clocks::ClockConfig;
224 292
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index 468e8470a..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};
52 52
53use crate::interrupt::InterruptExt; 53use crate::interrupt::InterruptExt;
54use crate::peripherals::CORE1; 54use crate::peripherals::CORE1;
55use crate::{gpio, interrupt, pac}; 55use crate::{gpio, install_stack_guard, interrupt, pac};
56 56
57const PAUSE_TOKEN: u32 = 0xDEADBEEF; 57const PAUSE_TOKEN: u32 = 0xDEADBEEF;
58const RESUME_TOKEN: u32 = !0xDEADBEEF; 58const RESUME_TOKEN: u32 = !0xDEADBEEF;
59static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); 59static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false);
60 60
61#[inline(always)] 61#[inline(always)]
62fn install_stack_guard(stack_bottom: *mut usize) { 62fn core1_setup(stack_bottom: *mut usize) {
63 let core = unsafe { cortex_m::Peripherals::steal() }; 63 if let Err(_) = install_stack_guard(stack_bottom) {
64 64 // currently only happens if the MPU was already set up, which
65 // Trap if MPU is already configured 65 // would indicate that the core is already in use from outside
66 if core.MPU.ctrl.read() != 0 { 66 // embassy, somehow. trap if so since we can't deal with that.
67 cortex_m::asm::udf(); 67 cortex_m::asm::udf();
68 } 68 }
69
70 // The minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
71 // just shorten the valid stack range a tad.
72 let addr = (stack_bottom as u32 + 31) & !31;
73 // Mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
74 let subregion_select = 0xff ^ (1 << ((addr >> 5) & 7));
75 unsafe {
76 core.MPU.ctrl.write(5); // enable mpu with background default map
77 core.MPU.rbar.write((addr & !0xff) | 0x8);
78 core.MPU.rasr.write(
79 1 // enable region
80 | (0x7 << 1) // size 2^(7 + 1) = 256
81 | (subregion_select << 8)
82 | 0x10000000, // XN = disable instruction fetch; no other bits means no permissions
83 );
84 }
85}
86
87#[inline(always)]
88fn core1_setup(stack_bottom: *mut usize) {
89 install_stack_guard(stack_bottom);
90 unsafe { 69 unsafe {
91 gpio::init(); 70 gpio::init();
92 } 71 }