Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion cortex-m-rt/tests/compile-fail/interrupt-not-reexported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ fn foo() -> ! {
loop {}
}

#[interrupt] //~ ERROR failed to resolve: use of unresolved module or unlinked crate `interrupt`
#[interrupt] //~ ERROR cannot find module or crate `interrupt`
fn USART1() {}
49 changes: 49 additions & 0 deletions cortex-m/src/peripheral/nvic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,55 @@ impl NVIC {
unsafe { (*Self::PTR).icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
}

/// Route `interrupt` to the Non-Secure world (ARMv8-M only).
///
/// Sets the corresponding ITNS bit so the interrupt is taken as Non-Secure
/// and will not preempt Secure execution. Call this for every peripheral
/// interrupt handled by the Non-Secure application before jumping to it.
///
/// # Safety
/// Must be called from the Secure world. Routing an interrupt to Non-Secure
/// while Secure handlers depend on it can violate security invariants.
#[cfg(armv8m)]
#[inline]
pub unsafe fn route_to_nonsecure<I>(interrupt: I)
where
I: InterruptNumber,
{
let nr = interrupt.number();
unsafe { (*Self::PTR).itns[usize::from(nr / 32)].modify(|v| v | (1 << (nr % 32))) }
}

/// Route `interrupt` back to the Secure world (ARMv8-M only).
///
/// Clears the corresponding ITNS bit. After this call the interrupt
/// targets Secure state (the default after reset).
///
/// # Safety
/// Must be called from the Secure world.
#[cfg(armv8m)]
#[inline]
pub unsafe fn route_to_secure<I>(interrupt: I)
where
I: InterruptNumber,
{
let nr = interrupt.number();
unsafe { (*Self::PTR).itns[usize::from(nr / 32)].modify(|v| v & !(1 << (nr % 32))) }
Comment thread
leftger marked this conversation as resolved.
Outdated
}

/// Returns `true` if `interrupt` is routed to the Non-Secure world (ARMv8-M only).
#[cfg(armv8m)]
#[inline]
pub fn is_routed_to_nonsecure<I>(interrupt: I) -> bool
where
I: InterruptNumber,
{
let nr = interrupt.number();
let mask = 1 << (nr % 32);
// NOTE(unsafe) atomic read with no side effects
unsafe { ((*Self::PTR).itns[usize::from(nr / 32)].read() & mask) == mask }
}

#[cfg(armv6m)]
#[inline]
fn ipr_index<I>(interrupt: I) -> usize
Expand Down
42 changes: 42 additions & 0 deletions cortex-m/src/peripheral/scb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ pub struct RegisterBlock {
pub cpacr: RW<u32>,
#[cfg(armv6m)]
_reserved9: u32,

/// Non-Secure Access Control (only present on ARMv8-M)
///
/// Controls whether Non-Secure code can access coprocessors. Bits 10–11
/// correspond to CP10 and CP11 (the FPU): setting them allows Non-Secure
/// code to use floating-point instructions.
#[cfg(armv8m)]
pub nsacr: RW<u32>,
}

/// FPU access mode
Expand Down Expand Up @@ -171,6 +179,40 @@ impl SCB {
}
}

/// ARMv8-M TrustZone coprocessor access control.
#[cfg(armv8m)]
impl SCB {
const SCB_NSACR_CP10_CP11: u32 = 0b11 << 10;

/// Allow Non-Secure code to use the FPU (CP10 and CP11).
///
/// Sets NSACR bits 10–11 so that Non-Secure threads can execute
/// floating-point instructions. Without this, any NS FPU instruction
/// raises a UsageFault.
///
/// Call this before jumping to Non-Secure code if the NS application
/// uses floating-point.
#[inline]
pub fn enable_nonsecure_fpu(&mut self) {
unsafe { self.nsacr.modify(|v| v | Self::SCB_NSACR_CP10_CP11) }
}

/// Deny Non-Secure code from using the FPU.
///
/// Clears NSACR bits 10–11.
#[inline]
pub fn disable_nonsecure_fpu(&mut self) {
unsafe { self.nsacr.modify(|v| v & !Self::SCB_NSACR_CP10_CP11) }
}

/// Returns `true` if Non-Secure code is allowed to use the FPU.
#[inline]
pub fn is_nonsecure_fpu_enabled() -> bool {
// NOTE(unsafe) atomic read with no side effects
unsafe { ((*Self::PTR).nsacr.read() & Self::SCB_NSACR_CP10_CP11) != 0 }
}
}

impl SCB {
/// Returns the active exception number
#[inline]
Expand Down
6 changes: 6 additions & 0 deletions cortex-m/src/peripheral/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ fn nvic() {
assert_eq!(address(&nvic.ispr), 0xE000E200);
assert_eq!(address(&nvic.icpr), 0xE000E280);
assert_eq!(address(&nvic.iabr), 0xE000E300);
#[cfg(armv8m)]
assert_eq!(address(&nvic.itns), 0xE000_E380);
#[cfg(armv8m)]
assert_eq!(address(&nvic.itns[1]), 0xE000_E384);
assert_eq!(address(&nvic.ipr), 0xE000E400);
#[cfg(not(armv6m))]
assert_eq!(address(&nvic.stir), 0xE000EF00);
Expand All @@ -139,6 +143,8 @@ fn scb() {
assert_eq!(address(&scb.bfar), 0xE000_ED38);
assert_eq!(address(&scb.afsr), 0xE000_ED3C);
assert_eq!(address(&scb.cpacr), 0xE000_ED88);
#[cfg(armv8m)]
assert_eq!(address(&scb.nsacr), 0xE000_ED8C);
}

#[test]
Expand Down
Loading