Skip to main content

strat9_kernel/sync/
irq.rs

1use crate::arch::x86_64;
2
3/// Preuve typée que les IRQ sont masquées sur le CPU courant.
4///
5/// L'allocateur mémoire consomme ce token pour empêcher à la compilation les
6/// appels depuis des contextes où une interruption pourrait ré-entrer sur le
7/// même verrou et provoquer un deadlock.
8///
9/// Intentionnellement non-`Copy` et non-`Clone` : le token ne doit pas pouvoir
10/// s'échapper du contexte IRQ-off dans lequel il a été créé.
11#[derive(Debug)]
12pub struct IrqDisabledToken(());
13
14impl IrqDisabledToken {
15    /// Vérifie l'état courant des interruptions et retourne la preuve si elles
16    /// sont déjà désactivées.
17    #[inline]
18    pub fn verify() -> Option<Self> {
19        if x86_64::interrupts_enabled() {
20            None
21        } else {
22            Some(Self(()))
23        }
24    }
25
26    /// Builds the proof without re-checking `RFLAGS`.
27    /// Reserved for internal producers of the `sync` module (guardian, with_irqs_disabled).
28    ///
29    /// # Safety
30    /// The caller must guarantee that IRQs are indeed disabled on the current CPU for the entire
31    /// logical validity of the token.
32
33    #[inline]
34    pub(super) unsafe fn new_unchecked() -> Self {
35        Self(())
36    }
37
38    /// Create a token when the caller guarantees that IRQs are already disabled.
39    /// Only to be used for implementing external traits (e.g. `X86FrameAllocator`)
40    /// whose signature cannot accept a token parameter. The caller MUST guarantee
41    /// that interrupts are disabled on the current CPU.
42    ///
43    /// # Safety
44    /// The caller must guarantee that IRQs are disabled on the current CPU.
45    ///
46    #[inline]
47    pub(crate) unsafe fn token_from_trusted_context() -> Self {
48        Self::new_unchecked()
49    }
50}
51
52/// Execute a closure with IRQs disabled, providing an `IrqDisabledToken` as proof.
53///
54/// Saves and disables IRQs before calling `f`, then restores the previous flag state.
55#[inline]
56pub fn with_irqs_disabled<R>(f: impl FnOnce(&IrqDisabledToken) -> R) -> R {
57    let saved = crate::arch::x86_64::save_flags_and_cli();
58    // SAFETY: save_flags_and_cli() has just disabled interrupts on this CPU;
59    // the token is dropped before restore_flags() re-enables them.
60    let token = unsafe { IrqDisabledToken::new_unchecked() };
61    let result = f(&token);
62    crate::arch::x86_64::restore_flags(saved);
63    result
64}