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