cortexm/
support.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Helper functions for the Cortex-M architecture.
6
7use crate::scb;
8
9/// NOP instruction
10#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
11#[inline(always)]
12pub fn nop() {
13    use core::arch::asm;
14    unsafe {
15        asm!("nop", options(nomem, nostack, preserves_flags));
16    }
17}
18
19/// WFI instruction
20#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
21#[inline(always)]
22pub unsafe fn wfi() {
23    use core::arch::asm;
24    asm!("wfi", options(nomem, preserves_flags));
25}
26
27/// Single-core critical section operation
28#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
29pub unsafe fn with_interrupts_disabled<F, R>(f: F) -> R
30where
31    F: FnOnce() -> R,
32{
33    use core::arch::asm;
34    // Set PRIMASK
35    asm!("cpsid i", options(nomem, nostack));
36
37    let res = f();
38
39    // Unset PRIMASK
40    asm!("cpsie i", options(nomem, nostack));
41    res
42}
43
44/// NOP instruction (mock)
45// Mock implementations for tests on Travis-CI.
46#[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
47pub fn nop() {
48    unimplemented!()
49}
50
51/// WFI instruction (mock)
52#[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
53pub unsafe fn wfi() {
54    unimplemented!()
55}
56
57/// Single-core critical section operation (mock)
58#[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
59pub unsafe fn with_interrupts_disabled<F, R>(_f: F) -> R
60where
61    F: FnOnce() -> R,
62{
63    unimplemented!()
64}
65
66/// Reset the chip.
67pub fn reset() -> ! {
68    unsafe {
69        scb::reset();
70    }
71    loop {
72        // This is required to avoid the empty loop clippy
73        // warning #[warn(clippy::empty_loop)]
74        nop();
75    }
76}
77
78/// Check if we are executing in an interrupt handler or not.
79///
80/// Returns `true` if the CPU is executing in an interrupt handler. Returns
81/// `false` if the chip is executing in thread mode.
82#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
83pub fn is_interrupt_context() -> bool {
84    use core::arch::asm;
85    let mut interrupt_number: u32;
86
87    // # Safety
88    //
89    // This only reads a register and has no effects.
90    unsafe {
91        // IPSR[8:0] holds the currently active interrupt
92        asm!(
93            "mrs r0, ipsr",
94            out("r0") interrupt_number,
95            options(nomem, nostack, preserves_flags)
96        );
97    }
98
99    // If IPSR[8:0] is 0 then we are in thread mode. Otherwise an interrupt has
100    // occurred and we are in some interrupt service routine.
101    (interrupt_number & 0x1FF) != 0
102}
103
104#[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
105pub fn is_interrupt_context() -> bool {
106    unimplemented!()
107}