Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cortex-m/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
14 changes: 6 additions & 8 deletions cortex-m/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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),
)
};
}
Expand Down Expand Up @@ -490,7 +488,7 @@ pub unsafe fn mcr<const CP: u32, const OP1: u32, const CRN: u32, const CRM: u32,
crn = const CRN,
crm = const CRM,
op2 = const OP2,
options(nostack, nomem)
options(nostack)
)
};
}
Expand Down Expand Up @@ -523,7 +521,7 @@ pub unsafe fn mrc<const CP: u32, const OP1: u32, const CRN: u32, const CRM: u32,
crn = const CRN,
crm = const CRM,
op2 = const OP2,
options(nostack, nomem)
options(nostack)
)
};

Expand Down Expand Up @@ -552,7 +550,7 @@ pub unsafe fn mcrr<const CP: u32, const OP1: u32, const CRM: u32>(a: u32, b: u32
cp = const CP,
op1 = const OP1,
crm = const CRM,
options(nostack, nomem)
options(nostack)
)
};
}
Expand Down Expand Up @@ -583,7 +581,7 @@ pub unsafe fn mrrc<const CP: u32, const OPC: u32, const CRM: u32>() -> (u32, u32
cp = const CP,
opc = const OPC,
crm = const CRM,
options(nostack, nomem)
options(nostack)
)
};

Expand Down
8 changes: 6 additions & 2 deletions cortex-m/src/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,21 @@ unsafe impl<T: Nr + Copy> 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);
}

/// 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
Expand All @@ -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.
Expand Down
15 changes: 11 additions & 4 deletions cortex-m/src/register/basepri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")]
Expand All @@ -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);
}
12 changes: 8 additions & 4 deletions cortex-m/src/register/basepri_max.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@

#[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*
///
/// - `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]
#[asm_cfg(any(armv7m, armv8m_main))]
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")]
Expand All @@ -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);
}
2 changes: 1 addition & 1 deletion cortex-m/src/register/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 3 additions & 1 deletion cortex-m/src/register/primask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
Loading