diff --git a/cortex-m/CHANGELOG.md b/cortex-m/CHANGELOG.md index 45fd2aac..0c7d273a 100644 --- a/cortex-m/CHANGELOG.md +++ b/cortex-m/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - The separate `#[cfg(not(cortex_m))]` stub for `interrupt::free`. ### Fixed +- Account for memory-mapped coprocessor state in coprocessor transfers. +- Preserve memory accesses across `control::write`, `asm::bootstrap`, and + `asm::bootload`. +- Preserve memory accesses around semihosting syscalls. +- Fix compiler ordering around interrupt-mask writes. - `NVIC`'s interrupt-bitmap accessors no longer emit a bounds check and a panic path. diff --git a/cortex-m/src/asm.rs b/cortex-m/src/asm.rs index 208ac5ed..ac66b46f 100644 --- a/cortex-m/src/asm.rs +++ b/cortex-m/src/asm.rs @@ -242,9 +242,7 @@ pub unsafe fn bx_ns(addr: u32) { #[inline] #[asm_cfg(cortex_m)] pub unsafe fn semihosting_syscall(mut nr: u32, arg: u32) -> u32 { - unsafe { - asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags)) - }; + unsafe { asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nostack, preserves_flags)) }; nr } @@ -363,7 +361,7 @@ pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! { spsel = in(reg) 2, msp = in(reg) msp, rv = in(reg) rv, - options(noreturn, nomem, nostack), + options(noreturn, nostack), ) }; } @@ -490,7 +488,7 @@ pub unsafe fn mcr(a: u32, b: u32 cp = const CP, op1 = const OP1, crm = const CRM, - options(nostack, nomem) + options(nostack) ) }; } @@ -583,7 +581,7 @@ pub unsafe fn mrrc() -> (u32, u32 cp = const CP, opc = const OPC, crm = const CRM, - options(nostack, nomem) + options(nostack) ) }; diff --git a/cortex-m/src/interrupt.rs b/cortex-m/src/interrupt.rs index 07da650b..bdf63ded 100644 --- a/cortex-m/src/interrupt.rs +++ b/cortex-m/src/interrupt.rs @@ -38,10 +38,12 @@ unsafe impl InterruptNumber for T { } /// Disables all interrupts +/// +/// Forms a read/write memory barrier for the compiler. #[inline] #[asm_cfg(cortex_m)] pub fn disable() { - unsafe { asm!("cpsid i", options(nomem, nostack, preserves_flags)) }; + unsafe { asm!("cpsid i", options(nostack, preserves_flags)) }; // Ensure no subsequent memory accesses are reordered to before interrupts are disabled. compiler_fence(Ordering::SeqCst); @@ -49,6 +51,8 @@ pub fn disable() { /// Enables all the interrupts /// +/// Forms a read/write memory barrier for the compiler. +/// /// # Safety /// /// - Do not call this function inside an `interrupt::free` critical section @@ -58,7 +62,7 @@ pub unsafe fn enable() { // Ensure no preceeding memory accesses are reordered to after interrupts are enabled. compiler_fence(Ordering::SeqCst); - unsafe { asm!("cpsie i", options(nomem, nostack, preserves_flags)) }; + unsafe { asm!("cpsie i", options(nostack, preserves_flags)) }; } /// Execute closure `f` in an interrupt-free context. diff --git a/cortex-m/src/register/basepri.rs b/cortex-m/src/register/basepri.rs index 86eb4bf2..abf8dd34 100644 --- a/cortex-m/src/register/basepri.rs +++ b/cortex-m/src/register/basepri.rs @@ -2,6 +2,8 @@ #[cfg(any(armv7m, armv8m))] use core::arch::asm; +#[cfg(any(armv7m, armv8m))] +use core::sync::atomic::{Ordering, compiler_fence}; use cortex_m_macros::asm_cfg; /// Reads the CPU register @@ -15,16 +17,20 @@ pub fn read() -> u8 { /// Writes to the CPU register /// +/// Forms a read/write memory barrier for the compiler. +/// /// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the /// `cm7-r0p1` Cargo feature or this function WILL misbehave. #[inline] #[asm_cfg(any(armv7m, armv8m_main))] pub unsafe fn write(basepri: u8) { + // Release before enabling interrupts; acquire after disabling them. + // Work around missing asm synchronization effects: rust-lang/rust#144351. + compiler_fence(Ordering::Release); + #[cfg(not(feature = "cm7-r0p1"))] { - unsafe { - asm!("msr BASEPRI, {}", in(reg) basepri, options(nomem, nostack, preserves_flags)) - }; + unsafe { asm!("msr BASEPRI, {}", in(reg) basepri, options(nostack, preserves_flags)) }; } #[cfg(feature = "cm7-r0p1")] @@ -40,8 +46,9 @@ pub unsafe fn write(basepri: u8) { "cpsie i", in(reg) basepri, out(reg) _, - options(nomem, nostack, preserves_flags), + options(nostack, preserves_flags), ) }; } + compiler_fence(Ordering::Acquire); } diff --git a/cortex-m/src/register/basepri_max.rs b/cortex-m/src/register/basepri_max.rs index f59ae421..2971bdd6 100644 --- a/cortex-m/src/register/basepri_max.rs +++ b/cortex-m/src/register/basepri_max.rs @@ -2,6 +2,8 @@ #[cfg(any(armv7m, armv8m))] use core::arch::asm; +#[cfg(any(armv7m, armv8m))] +use core::sync::atomic::{Ordering, compiler_fence}; use cortex_m_macros::asm_cfg; /// Writes to BASEPRI *if* @@ -9,6 +11,8 @@ use cortex_m_macros::asm_cfg; /// - `basepri != 0` AND `basepri::read() == 0`, OR /// - `basepri != 0` AND `basepri < basepri::read()` /// +/// Forms a read/write memory barrier for the compiler. +/// /// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the /// `cm7-r0p1` Cargo feature or this function WILL misbehave. #[inline] @@ -16,9 +20,7 @@ use cortex_m_macros::asm_cfg; pub fn write(basepri: u8) { #[cfg(not(feature = "cm7-r0p1"))] { - unsafe { - asm!("msr BASEPRI_MAX, {}", in(reg) basepri, options(nomem, nostack, preserves_flags)) - }; + unsafe { asm!("msr BASEPRI_MAX, {}", in(reg) basepri, options(nostack, preserves_flags)) }; } #[cfg(feature = "cm7-r0p1")] @@ -34,8 +36,10 @@ pub fn write(basepri: u8) { "cpsie i", in(reg) basepri, out(reg) _, - options(nomem, nostack, preserves_flags), + options(nostack, preserves_flags), ) }; } + // Acquire after disabling interrupts. See rust-lang/rust#144351. + compiler_fence(Ordering::Acquire); } diff --git a/cortex-m/src/register/control.rs b/cortex-m/src/register/control.rs index 52e8f665..f6a7e618 100644 --- a/cortex-m/src/register/control.rs +++ b/cortex-m/src/register/control.rs @@ -199,7 +199,7 @@ pub unsafe fn write(control: Control) { "msr CONTROL, {}", "isb", in(reg) control, - options(nomem, nostack, preserves_flags), + options(nostack, preserves_flags), ); compiler_fence(Ordering::SeqCst); } diff --git a/cortex-m/src/register/primask.rs b/cortex-m/src/register/primask.rs index 163fee95..1effa364 100644 --- a/cortex-m/src/register/primask.rs +++ b/cortex-m/src/register/primask.rs @@ -51,6 +51,8 @@ pub fn read_raw() -> u32 { /// Writes the entire PRIMASK register /// +/// Forms a read/write memory barrier for the compiler. +/// /// Note that bits `[31:1]` are reserved and SBZP (Should-Be-Zero-or-Preserved) /// /// # Safety @@ -64,7 +66,7 @@ pub fn read_raw() -> u32 { pub unsafe fn write_raw(r: u32) { // Ensure no preceeding memory accesses are reordered to after interrupts are possibly enabled. compiler_fence(Ordering::SeqCst); - unsafe { asm!("msr PRIMASK, {}", in(reg) r, options(nomem, nostack, preserves_flags)) }; + unsafe { asm!("msr PRIMASK, {}", in(reg) r, options(nostack, preserves_flags)) }; // Ensure no subsequent memory accesses are reordered to before interrupts are possibly disabled. compiler_fence(Ordering::SeqCst); }