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
//! Enabling and disabling interrupts /// Returns whether interrupts are enabled. pub fn are_enabled() -> bool { use crate::registers::rflags::{self, RFlags}; rflags::read().contains(RFlags::INTERRUPT_FLAG) } /// Enable interrupts. /// /// This is a wrapper around the `sti` instruction. pub fn enable() { unsafe { asm!("sti" :::: "volatile"); } } /// Disable interrupts. /// /// This is a wrapper around the `cli` instruction. pub fn disable() { unsafe { asm!("cli" :::: "volatile"); } } /// Run a closue 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. /// /// # Examples /// /// ```ignore /// // interrupts are enabled /// without_interrupts(|| { /// // interrupts are disabled /// without_interrupts(|| { /// // interrupts are disabled /// }); /// // interrupts are still disabled /// }); /// // interrupts are enabled again /// ``` pub fn without_interrupts<F, R>(f: F) -> R where F: FnOnce() -> R, { // true if the interrupt flag is set (i.e. interrupts are enabled) let saved_intpt_flag = are_enabled(); // if interrupts are enabled, disable them for now if saved_intpt_flag { disable(); } // do `f` while interrupts are disabled let ret = f(); // re-enable interrupts if they were previously enabled if saved_intpt_flag { enable(); } // return the result of `f` to the caller ret } /// Cause a breakpoint exception by invoking the `int3` instruction. pub fn int3() { unsafe { asm!("int3" :::: "volatile"); } } /// Generate a software interrupt by invoking the `int` instruction. /// /// This currently needs to be a macro because the `int` argument needs to be an /// immediate. This macro will be replaced by a generic function when support for /// const generics is implemented in Rust. #[macro_export] macro_rules! software_interrupt { ($x:expr) => {{ asm!("int $0" :: "N" ($x) :: "volatile"); }}; }