1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/// Run a closure with disabled interrupts.
///
/// Run the given closure, disabling interrupts before running it (if they aren't already disabled).
/// Afterwards, interrupts are enabling again if they were enabled before.
///
/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected.
///
/// Only has an effect if `target_os = "none"`.
///
/// # Examples
///
/// ```
/// use hermit_sync::without_interrupts;
///
/// // interrupts are enabled
/// without_interrupts(|| {
///     // interrupts are disabled
///     without_interrupts(|| {
///         // interrupts are disabled
///     });
///     // interrupts are still disabled
/// });
/// // interrupts are enabled again
/// ```
// Doc taken from `x86_64::instructions::interrupts::without_interrupts`.
#[inline]
pub fn without_interrupts<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    let flags = read_disable();

    let ret = f();

    restore(flags);

    ret
}

#[inline]
pub(crate) fn read_disable() -> imp::Flags {
    if cfg!(target_os = "none") {
        let flags = imp::get();

        if flags != DISABLE {
            imp::set(DISABLE);
        }

        flags
    } else {
        DISABLE
    }
}

#[inline]
pub(crate) fn restore(flags: imp::Flags) {
    if flags != DISABLE && cfg!(target_os = "none") {
        imp::set(flags);
    }
}

pub(crate) use imp::{AtomicFlags, DISABLE};

#[cfg(target_arch = "x86_64")]
mod imp {
    use x86_64::instructions::interrupts;

    pub type Flags = bool;
    pub type AtomicFlags = core::sync::atomic::AtomicBool;

    pub const DISABLE: bool = false;

    pub use interrupts::are_enabled as get;

    #[inline]
    pub fn set(enable: bool) {
        if enable {
            interrupts::enable();
        } else {
            interrupts::disable();
        }
    }
}

#[cfg(target_arch = "aarch64")]
mod imp {
    use aarch64_cpu::registers::DAIF;
    use tock_registers::interfaces::{Readable, Writeable};

    pub type Flags = u64;
    pub type AtomicFlags = core::sync::atomic::AtomicU64;

    pub const DISABLE: u64 = 0;

    #[inline]
    pub fn get() -> u64 {
        DAIF.get()
    }

    #[inline]
    pub fn set(value: u64) {
        DAIF.set(value);
    }
}