Skip to content
Open
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
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() {}
54 changes: 54 additions & 0 deletions cortex-m/src/peripheral/nvic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,60 @@ 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();
let group_idx = usize::from(nr / 32);
let bit_mask = 1 << (nr % 32);
unsafe { (*Self::PTR).itns[group_idx].modify(|v| v | bit_mask) }
}

/// 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();
let group_idx = usize::from(nr / 32);
let bit_mask = 1 << (nr % 32);
unsafe { (*Self::PTR).itns[group_idx].modify(|v| v & !bit_mask) }
}

/// 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 group_idx = usize::from(nr / 32);
let bit_mask = 1 << (nr % 32);
// NOTE(unsafe) atomic read with no side effects
unsafe { ((*Self::PTR).itns[group_idx].read() & bit_mask) == bit_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