diff options
| -rw-r--r-- | embassy-rp/src/lib.rs | 68 | ||||
| -rw-r--r-- | embassy-rp/src/multicore.rs | 33 |
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 | /// ``` | ||
| 256 | pub 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)] | ||
| 264 | fn 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 | |||
| 222 | pub mod config { | 290 | pub 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 | ||
| 53 | use crate::interrupt::InterruptExt; | 53 | use crate::interrupt::InterruptExt; |
| 54 | use crate::peripherals::CORE1; | 54 | use crate::peripherals::CORE1; |
| 55 | use crate::{gpio, interrupt, pac}; | 55 | use crate::{gpio, install_stack_guard, interrupt, pac}; |
| 56 | 56 | ||
| 57 | const PAUSE_TOKEN: u32 = 0xDEADBEEF; | 57 | const PAUSE_TOKEN: u32 = 0xDEADBEEF; |
| 58 | const RESUME_TOKEN: u32 = !0xDEADBEEF; | 58 | const RESUME_TOKEN: u32 = !0xDEADBEEF; |
| 59 | static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); | 59 | static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); |
| 60 | 60 | ||
| 61 | #[inline(always)] | 61 | #[inline(always)] |
| 62 | fn install_stack_guard(stack_bottom: *mut usize) { | 62 | fn 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)] | ||
| 88 | fn core1_setup(stack_bottom: *mut usize) { | ||
| 89 | install_stack_guard(stack_bottom); | ||
| 90 | unsafe { | 69 | unsafe { |
| 91 | gpio::init(); | 70 | gpio::init(); |
| 92 | } | 71 | } |
