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
//! # Interrupt handling for x86.
//!
//! This module contains abstractions for configuring the programmable interrupt controllers:
//! - The legacy [pic] provides backward capabilities. On modern OSs, it is not used anymore and must be disabled when using the modern APICs.
//! - The modern "advanced" [ioapic] and [lapic] controllers are more capable but also more difficult to configure. The former (IOAPIC) is shared between all cores and the latter (LAPIC) exists for each core.
//!
//! These interrupt controllers are configured together with the
//! interrupt descriptor table ([idt]), which is used to define the
//! interrupt-handler functions that are executed for a given interrupt vector.
//!
//! ## Overview
//!
//! The ASCII art below show the way a keyboard interrupt has to undergo to
//! reach the CPU and the configured interrupt service routine on x86.
//!
//! ```text
//!
//! +- Keyboard
//! |
//! +-o------+
//! | IOAPIC | <- Redirection Table (Device -> Vector)
//! +---o----+
//! |
//! ----oo-----... Interrupt Bus
//! |
//! +----o----+
//! | LAPIC 0 | <- EOI, Timer, IPI, ...
//! +----o----+
//! |
//! +---o---+
//! | CPU 0 |
//! | - RIDT+---> IDT[Vector] => ISR
//! +-------+
//!
//! ```
use core::arch::asm;
use super::regs::Flags;
pub mod apic;
#[macro_use]
pub mod idt;
pub mod ioapic;
pub mod lapic;
pub mod pic;
/// Suppresses interrupts during the execution of `f` and
/// restore the previous status afterwards.
pub fn suppress<R>(f: impl FnOnce() -> R) -> R {
let enabled = enabled();
enable(false);
let ret = f();
enable(enabled);
ret
}
/// Return if interrupts are currently enabled.
pub fn enabled() -> bool {
Flags::read().interrupt()
}
/// Enable interrupts.
pub fn enable(enable: bool) {
if enable {
unsafe { asm!("sti", options(nomem, nostack)) };
} else {
unsafe { asm!("cli", options(nomem, nostack)) };
}
}
/// Enable interrupts and halt execution.
///
/// These two instructions are executed atomically, preventing race conditions,
/// where an interrupt in between is missed.
pub fn idle() {
unsafe { asm!("sti; hlt", options(nomem, nostack)) };
}