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}