x86/
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 2024.
4
5//! Miscellaneous low-level operations
6
7#[cfg(any(doc, target_arch = "x86"))]
8use core::arch::asm;
9
10/// Execute closure without allowing any interrupts on the current core.
11///
12/// This function ensures interrupts are disabled before invoking the given
13/// closue `f`. This allows / you to safely perform single-core operations
14/// which would otherwise race against interrupt handlers.
15#[cfg(any(doc, target_arch = "x86"))]
16pub fn with_interrupts_disabled<F, R>(f: F) -> R
17where
18    F: FnOnce() -> R,
19{
20    use crate::registers::bits32::eflags::{self, EFLAGS};
21    use crate::registers::irq;
22
23    // Safety: We assume that this function is only ever called from inside the Tock kernel itself
24    //         running with a CPL of 0. This allows us to read EFLAGS and disable/enable interrupts
25    //         without fear of triggering an exception.
26    unsafe {
27        let eflags = eflags::read();
28        let enabled = eflags.0.is_set(EFLAGS::FLAGS_IF);
29
30        if enabled {
31            irq::disable();
32        }
33
34        let res = f();
35
36        if enabled {
37            irq::enable();
38        }
39
40        res
41    }
42}
43
44#[cfg(not(any(doc, target_arch = "x86")))]
45pub fn with_interrupts_disabled<F, R>(_: F) -> R
46where
47    F: FnOnce() -> R,
48{
49    unimplemented!()
50}
51
52/// Executes a single NOP instruction.
53#[cfg(any(doc, target_arch = "x86"))]
54#[inline(always)]
55pub fn nop() {
56    unsafe {
57        asm!("nop", options(nomem, nostack, preserves_flags));
58    }
59}
60
61#[cfg(not(any(doc, target_arch = "x86")))]
62#[inline(always)]
63pub fn nop() {
64    unimplemented!()
65}