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}