diff options
Diffstat (limited to 'src/bits64/irq.rs')
-rw-r--r-- | src/bits64/irq.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/bits64/irq.rs b/src/bits64/irq.rs new file mode 100644 index 0000000..84ee0e6 --- /dev/null +++ b/src/bits64/irq.rs @@ -0,0 +1,143 @@ +//! Interrupt description and set-up code. + +use core::fmt; + +use shared::descriptor::*; +use shared::paging::VAddr; +use shared::PrivilegeLevel; + +/// An interrupt gate descriptor. +/// +/// See Intel manual 3a for details, specifically section "6.14.1 64-Bit Mode +/// IDT" and "Table 3-2. System-Segment and Gate-Descriptor Types". +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct IdtEntry { + /// Lower 16 bits of ISR. + pub base_lo: u16, + /// Segment selector. + pub selector: u16, + /// This must always be zero. + pub reserved0: u8, + /// Flags. + pub flags: Flags, + /// The upper 48 bits of ISR (the last 16 bits must be zero). + pub base_hi: u64, + /// Must be zero. + pub reserved1: u16, +} + +impl IdtEntry { + /// A "missing" IdtEntry. + /// + /// If the CPU tries to invoke a missing interrupt, it will instead + /// send a General Protection fault (13), with the interrupt number and + /// some other data stored in the error code. + pub const MISSING: IdtEntry = IdtEntry { + base_lo: 0, + selector: 0, + reserved0: 0, + flags: Flags::BLANK, + base_hi: 0, + reserved1: 0, + }; + + /// Create a new IdtEntry pointing at `handler`, which must be a function + /// with interrupt calling conventions. (This must be currently defined in + /// assembly language.) The `gdt_code_selector` value must be the offset of + /// code segment entry in the GDT. + /// + /// The "Present" flag set, which is the most common case. If you need + /// something else, you can construct it manually. + pub const fn new(handler: VAddr, gdt_code_selector: u16, + dpl: PrivilegeLevel, block: bool) -> IdtEntry { + IdtEntry { + base_lo: ((handler.as_usize() as u64) & 0xFFFF) as u16, + base_hi: handler.as_usize() as u64 >> 16, + selector: gdt_code_selector, + reserved0: 0, + // Nice bitflags operations don't work in const fn, hence these + // ad-hoc methods. + flags: Flags::from_priv(dpl) + .const_or(FLAGS_TYPE_SYS_NATIVE_INTERRUPT_GATE + .const_mux(FLAGS_TYPE_SYS_NATIVE_TRAP_GATE, + block)) + .const_or(FLAGS_PRESENT), + reserved1: 0, + } + } +} + +bitflags!{ + // Taken from Intel Manual Section 4.7 Page-Fault Exceptions. + pub flags PageFaultError: u32 { + /// 0: The fault was caused by a non-present page. + /// 1: The fault was caused by a page-level protection violation + const PFAULT_ERROR_P = bit!(0), + + /// 0: The access causing the fault was a read. + /// 1: The access causing the fault was a write. + const PFAULT_ERROR_WR = bit!(1), + + /// 0: The access causing the fault originated when the processor + /// was executing in supervisor mode. + /// 1: The access causing the fault originated when the processor + /// was executing in user mode. + const PFAULT_ERROR_US = bit!(2), + + /// 0: The fault was not caused by reserved bit violation. + /// 1: The fault was caused by reserved bits set to 1 in a page directory. + const PFAULT_ERROR_RSVD = bit!(3), + + /// 0: The fault was not caused by an instruction fetch. + /// 1: The fault was caused by an instruction fetch. + const PFAULT_ERROR_ID = bit!(4), + + /// 0: The fault was not by protection keys. + /// 1: There was a protection key violation. + const PFAULT_ERROR_PK = bit!(5), + } +} + +impl fmt::Display for PageFaultError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let p = match self.contains(PFAULT_ERROR_P) { + false => "The fault was caused by a non-present page.", + true => "The fault was caused by a page-level protection violation.", + }; + let wr = match self.contains(PFAULT_ERROR_WR) { + false => "The access causing the fault was a read.", + true => "The access causing the fault was a write.", + }; + let us = match self.contains(PFAULT_ERROR_US) { + false => { + "The access causing the fault originated when the processor was executing in \ + supervisor mode." + } + true => { + "The access causing the fault originated when the processor was executing in user \ + mode." + } + }; + let rsvd = match self.contains(PFAULT_ERROR_RSVD) { + false => "The fault was not caused by reserved bit violation.", + true => "The fault was caused by reserved bits set to 1 in a page directory.", + }; + let id = match self.contains(PFAULT_ERROR_ID) { + false => "The fault was not caused by an instruction fetch.", + true => "The fault was caused by an instruction fetch.", + }; + + write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id) + } +} + +#[test] +fn bit_macro() { + assert!(PFAULT_ERROR_PK.bits() == 0b100000); + assert!(PFAULT_ERROR_ID.bits() == 0b10000); + assert!(PFAULT_ERROR_RSVD.bits() == 0b1000); + assert!(PFAULT_ERROR_US.bits() == 0b100); + assert!(PFAULT_ERROR_WR.bits() == 0b10); + assert!(PFAULT_ERROR_P.bits() == 0b1); +} |