diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs deleted file mode 100644 index c71e642..0000000 --- a/src/arch/x86_64/idt.rs +++ /dev/null @@ -1,653 +0,0 @@ -// Copyright 2017 Philipp Oppermann. See the README.md -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Provides types for the Interrupt Descriptor Table and its entries. - -use core::fmt; -use core::marker::PhantomData; -use core::mem; -use core::ops::{Index, IndexMut}; -use bit_field::BitField; -use x86_64::{PrivilegeLevel, VirtualAddress}; - -/// An Interrupt Descriptor Table with 256 entries. -/// -/// The field descriptions are taken from the -/// [AMD64 manual volume 2](https://support.amd.com/TechDocs/24593.pdf) -/// (with slight modifications). -#[repr(C)] -pub struct Idt { - /// A divide by zero exception (`#DE`) occurs when the denominator of a DIV instruction or - /// an IDIV instruction is 0. A `#DE` also occurs if the result is too large to be - /// represented in the destination. - /// - /// The saved instruction pointer points to the instruction that caused the `#DE`. - /// - /// The vector number of the `#DE` exception is 0. - pub divide_by_zero: IdtEntry, - - /// When the debug-exception mechanism is enabled, a `#DB` exception can occur under any - /// of the following circumstances: - /// - ///
- /// - /// - Instruction execution. - /// - Instruction single stepping. - /// - Data read. - /// - Data write. - /// - I/O read. - /// - I/O write. - /// - Task switch. - /// - Debug-register access, or general detect fault (debug register access when DR7.GD=1). - /// - Executing the INT1 instruction (opcode 0F1h). - /// - ///
- /// - /// `#DB` conditions are enabled and disabled using the debug-control register, `DR7` - /// and `RFLAGS.TF`. - /// - /// In the following cases, the saved instruction pointer points to the instruction that - /// caused the `#DB`: - /// - /// - Instruction execution. - /// - Invalid debug-register access, or general detect. - /// - /// In all other cases, the instruction that caused the `#DB` is completed, and the saved - /// instruction pointer points to the instruction after the one that caused the `#DB`. - /// - /// The vector number of the `#DB` exception is 1. - pub debug: IdtEntry, - - /// An non maskable interrupt exception (NMI) occurs as a result of system logic - /// signaling a non-maskable interrupt to the processor. - /// - /// The processor recognizes an NMI at an instruction boundary. - /// The saved instruction pointer points to the instruction immediately following the - /// boundary where the NMI was recognized. - /// - /// The vector number of the NMI exception is 2. - pub non_maskable_interrupt: IdtEntry, - - /// A breakpoint (`#BP`) exception occurs when an `INT3` instruction is executed. The - /// `INT3` is normally used by debug software to set instruction breakpoints by replacing - /// - /// The saved instruction pointer points to the byte after the `INT3` instruction. - /// - /// The vector number of the `#BP` exception is 3. - pub breakpoint: IdtEntry, - - /// An overflow exception (`#OF`) occurs as a result of executing an `INTO` instruction - /// while the overflow bit in `RFLAGS` is set to 1. - /// - /// The saved instruction pointer points to the instruction following the `INTO` - /// instruction that caused the `#OF`. - /// - /// The vector number of the `#OF` exception is 4. - pub overflow: IdtEntry, - - /// A bound-range exception (`#BR`) exception can occur as a result of executing - /// the `BOUND` instruction. The `BOUND` instruction compares an array index (first - /// operand) with the lower bounds and upper bounds of an array (second operand). - /// If the array index is not within the array boundary, the `#BR` occurs. - /// - /// The saved instruction pointer points to the `BOUND` instruction that caused the `#BR`. - /// - /// The vector number of the `#BR` exception is 5. - pub bound_range_exceeded: IdtEntry, - - /// An invalid opcode exception (`#UD`) occurs when an attempt is made to execute an - /// invalid or undefined opcode. The validity of an opcode often depends on the - /// processor operating mode. - /// - ///
A `#UD` occurs under the following conditions: - /// - /// - Execution of any reserved or undefined opcode in any mode. - /// - Execution of the `UD2` instruction. - /// - Use of the `LOCK` prefix on an instruction that cannot be locked. - /// - Use of the `LOCK` prefix on a lockable instruction with a non-memory target location. - /// - Execution of an instruction with an invalid-operand type. - /// - Execution of the `SYSENTER` or `SYSEXIT` instructions in long mode. - /// - Execution of any of the following instructions in 64-bit mode: `AAA`, `AAD`, - /// `AAM`, `AAS`, `BOUND`, `CALL` (opcode 9A), `DAA`, `DAS`, `DEC`, `INC`, `INTO`, - /// `JMP` (opcode EA), `LDS`, `LES`, `POP` (`DS`, `ES`, `SS`), `POPA`, `PUSH` (`CS`, - /// `DS`, `ES`, `SS`), `PUSHA`, `SALC`. - /// - Execution of the `ARPL`, `LAR`, `LLDT`, `LSL`, `LTR`, `SLDT`, `STR`, `VERR`, or - /// `VERW` instructions when protected mode is not enabled, or when virtual-8086 mode - /// is enabled. - /// - Execution of any legacy SSE instruction when `CR4.OSFXSR` is cleared to 0. - /// - Execution of any SSE instruction (uses `YMM`/`XMM` registers), or 64-bit media - /// instruction (uses `MMXTM` registers) when `CR0.EM` = 1. - /// - Execution of any SSE floating-point instruction (uses `YMM`/`XMM` registers) that - /// causes a numeric exception when `CR4.OSXMMEXCPT` = 0. - /// - Use of the `DR4` or `DR5` debug registers when `CR4.DE` = 1. - /// - Execution of `RSM` when not in `SMM` mode. - /// - ///
- /// - /// The saved instruction pointer points to the instruction that caused the `#UD`. - /// - /// The vector number of the `#UD` exception is 6. - pub invalid_opcode: IdtEntry, - - /// A device not available exception (`#NM`) occurs under any of the following conditions: - /// - ///
- /// - /// - An `FWAIT`/`WAIT` instruction is executed when `CR0.MP=1` and `CR0.TS=1`. - /// - Any x87 instruction other than `FWAIT` is executed when `CR0.EM=1`. - /// - Any x87 instruction is executed when `CR0.TS=1`. The `CR0.MP` bit controls whether the - /// `FWAIT`/`WAIT` instruction causes an `#NM` exception when `TS=1`. - /// - Any 128-bit or 64-bit media instruction when `CR0.TS=1`. - /// - ///
- /// - /// The saved instruction pointer points to the instruction that caused the `#NM`. - /// - /// The vector number of the `#NM` exception is 7. - pub device_not_available: IdtEntry, - - /// A double fault (`#DF`) exception can occur when a second exception occurs during - /// the handling of a prior (first) exception or interrupt handler. - /// - ///
- /// - /// Usually, the first and second exceptions can be handled sequentially without - /// resulting in a `#DF`. In this case, the first exception is considered _benign_, as - /// it does not harm the ability of the processor to handle the second exception. In some - /// cases, however, the first exception adversely affects the ability of the processor to - /// handle the second exception. These exceptions contribute to the occurrence of a `#DF`, - /// and are called _contributory exceptions_. The following exceptions are contributory: - /// - /// - Invalid-TSS Exception - /// - Segment-Not-Present Exception - /// - Stack Exception - /// - General-Protection Exception - /// - /// A double-fault exception occurs in the following cases: - /// - /// - If a contributory exception is followed by another contributory exception. - /// - If a divide-by-zero exception is followed by a contributory exception. - /// - If a page fault is followed by another page fault or a contributory exception. - /// - /// If a third interrupting event occurs while transferring control to the `#DF` handler, - /// the processor shuts down. - /// - ///
- /// - /// The returned error code is always zero. The saved instruction pointer is undefined, - /// and the program cannot be restarted. - /// - /// The vector number of the `#DF` exception is 8. - pub double_fault: IdtEntry, - - /// This interrupt vector is reserved. It is for a discontinued exception originally used - /// by processors that supported external x87-instruction coprocessors. On those processors, - /// the exception condition is caused by an invalid-segment or invalid-page access on an - /// x87-instruction coprocessor-instruction operand. On current processors, this condition - /// causes a general-protection exception to occur. - coprocessor_segment_overrun: IdtEntry, - - /// An invalid TSS exception (`#TS`) occurs only as a result of a control transfer through - /// a gate descriptor that results in an invalid stack-segment reference using an `SS` - /// selector in the TSS. - /// - /// The returned error code is the `SS` segment selector. The saved instruction pointer - /// points to the control-transfer instruction that caused the `#TS`. - /// - /// The vector number of the `#DF` exception is 10. - pub invalid_tss: IdtEntry, - - /// An segment-not-present exception (`#NP`) occurs when an attempt is made to load a - /// segment or gate with a clear present bit. - /// - /// The returned error code is the segment-selector index of the segment descriptor - /// causing the `#NP` exception. The saved instruction pointer points to the instruction - /// that loaded the segment selector resulting in the `#NP`. - /// - /// The vector number of the `#NP` exception is 11. - pub segment_not_present: IdtEntry, - - /// An stack segment exception (`#SS`) can occur in the following situations: - /// - /// - Implied stack references in which the stack address is not in canonical - /// form. Implied stack references include all push and pop instructions, and any - /// instruction using `RSP` or `RBP` as a base register. - /// - Attempting to load a stack-segment selector that references a segment descriptor - /// containing a clear present bit. - /// - Any stack access that fails the stack-limit check. - /// - /// The returned error code depends on the cause of the `#SS`. If the cause is a cleared - /// present bit, the error code is the corresponding segment selector. Otherwise, the - /// error code is zero. The saved instruction pointer points to the instruction that - /// caused the `#SS`. - /// - /// The vector number of the `#NP` exception is 12. - pub stack_segment_fault: IdtEntry, - - /// A general protection fault (`#GP`) can occur in various situations. Common causes include: - /// - /// - Executing a privileged instruction while `CPL > 0`. - /// - Writing a 1 into any register field that is reserved, must be zero (MBZ). - /// - Attempting to execute an SSE instruction specifying an unaligned memory operand. - /// - Loading a non-canonical base address into the `GDTR` or `IDTR`. - /// - Using WRMSR to write a read-only MSR. - /// - Any long-mode consistency-check violation. - /// - /// The returned error code is a segment selector, if the cause of the `#GP` is - /// segment-related, and zero otherwise. The saved instruction pointer points to - /// the instruction that caused the `#GP`. - /// - /// The vector number of the `#GP` exception is 13. - pub general_protection_fault: IdtEntry, - - /// A page fault (`#PF`) can occur during a memory access in any of the following situations: - /// - /// - A page-translation-table entry or physical page involved in translating the memory - /// access is not present in physical memory. This is indicated by a cleared present - /// bit in the translation-table entry. - /// - An attempt is made by the processor to load the instruction TLB with a translation - /// for a non-executable page. - /// - The memory access fails the paging-protection checks (user/supervisor, read/write, - /// or both). - /// - A reserved bit in one of the page-translation-table entries is set to 1. A `#PF` - /// occurs for this reason only when `CR4.PSE=1` or `CR4.PAE=1`. - /// - /// The virtual (linear) address that caused the `#PF` is stored in the `CR2` register. - /// The saved instruction pointer points to the instruction that caused the `#PF`. - /// - /// The page-fault error code is described by the - /// [`PageFaultErrorCode`](struct.PageFaultErrorCode.html) struct. - /// - /// The vector number of the `#PF` exception is 14. - pub page_fault: IdtEntry, - - /// vector nr. 15 - reserved_1: IdtEntry, - - /// The x87 Floating-Point Exception-Pending exception (`#MF`) is used to handle unmasked x87 - /// floating-point exceptions. In 64-bit mode, the x87 floating point unit is not used - /// anymore, so this exception is only relevant when executing programs in the 32-bit - /// compatibility mode. - /// - /// The vector number of the `#MF` exception is 16. - pub x87_floating_point: IdtEntry, - - /// An alignment check exception (`#AC`) occurs when an unaligned-memory data reference - /// is performed while alignment checking is enabled. An `#AC` can occur only when CPL=3. - /// - /// The returned error code is always zero. The saved instruction pointer points to the - /// instruction that caused the `#AC`. - /// - /// The vector number of the `#AC` exception is 17. - pub alignment_check: IdtEntry, - - /// The machine check exception (`#MC`) is model specific. Processor implementations - /// are not required to support the `#MC` exception, and those implementations that do - /// support `#MC` can vary in how the `#MC` exception mechanism works. - /// - /// There is no reliable way to restart the program. - /// - /// The vector number of the `#MC` exception is 18. - pub machine_check: IdtEntry, - - /// The SIMD Floating-Point Exception (`#XF`) is used to handle unmasked SSE - /// floating-point exceptions. The SSE floating-point exceptions reported by - /// the `#XF` exception are (including mnemonics): - /// - /// - IE: Invalid-operation exception (also called #I). - /// - DE: Denormalized-operand exception (also called #D). - /// - ZE: Zero-divide exception (also called #Z). - /// - OE: Overflow exception (also called #O). - /// - UE: Underflow exception (also called #U). - /// - PE: Precision exception (also called #P or inexact-result exception). - /// - /// The saved instruction pointer points to the instruction that caused the `#XF`. - /// - /// The vector number of the `#XF` exception is 19. - pub simd_floating_point: IdtEntry, - - /// vector nr. 20 - pub virtualization: IdtEntry, - - /// vector nr. 21-29 - reserved_2: [IdtEntry; 9], - - /// The Security Exception (`#SX`) signals security-sensitive events that occur while - /// executing the VMM, in the form of an exception so that the VMM may take appropriate - /// action. (A VMM would typically intercept comparable sensitive events in the guest.) - /// In the current implementation, the only use of the `#SX` is to redirect external INITs - /// into an exception so that the VMM may — among other possibilities. - /// - /// The only error code currently defined is 1, and indicates redirection of INIT has occurred. - /// - /// The vector number of the ``#SX`` exception is 30. - pub security_exception: IdtEntry, - - /// vector nr. 31 - reserved_3: IdtEntry, - - /// User-defined interrupts can be initiated either by system logic or software. They occur - /// when: - /// - /// - System logic signals an external interrupt request to the processor. The signaling - /// mechanism and the method of communicating the interrupt vector to the processor are - /// implementation dependent. - /// - Software executes an `INTn` instruction. The `INTn` instruction operand provides - /// the interrupt vector number. - /// - /// Both methods can be used to initiate an interrupt into vectors 0 through 255. However, - /// because vectors 0 through 31 are defined or reserved by the AMD64 architecture, - /// software should not use vectors in this range for purposes other than their defined use. - /// - /// The saved instruction pointer depends on the interrupt source: - /// - /// - External interrupts are recognized on instruction boundaries. The saved instruction - /// pointer points to the instruction immediately following the boundary where the - /// external interrupt was recognized. - /// - If the interrupt occurs as a result of executing the INTn instruction, the saved - /// instruction pointer points to the instruction after the INTn. - pub interrupts: [IdtEntry; 256 - 32], -} - -impl Idt { - /// Creates a new IDT filled with non-present entries. - pub const fn new() -> Idt { - // debug_assert_eq!(mem::size_of::(), 256 * 16); - Idt { - divide_by_zero: IdtEntry::missing(), - debug: IdtEntry::missing(), - non_maskable_interrupt: IdtEntry::missing(), - breakpoint: IdtEntry::missing(), - overflow: IdtEntry::missing(), - bound_range_exceeded: IdtEntry::missing(), - invalid_opcode: IdtEntry::missing(), - device_not_available: IdtEntry::missing(), - double_fault: IdtEntry::missing(), - coprocessor_segment_overrun: IdtEntry::missing(), - invalid_tss: IdtEntry::missing(), - segment_not_present: IdtEntry::missing(), - stack_segment_fault: IdtEntry::missing(), - general_protection_fault: IdtEntry::missing(), - page_fault: IdtEntry::missing(), - reserved_1: IdtEntry::missing(), - x87_floating_point: IdtEntry::missing(), - alignment_check: IdtEntry::missing(), - machine_check: IdtEntry::missing(), - simd_floating_point: IdtEntry::missing(), - virtualization: IdtEntry::missing(), - reserved_2: [IdtEntry::missing(); 9], - security_exception: IdtEntry::missing(), - reserved_3: IdtEntry::missing(), - interrupts: [IdtEntry::missing(); 256 - 32], - } - } - - /// Loads the IDT in the CPU using the `lidt` command. - pub fn load(&'static self) { - use x86_64::instructions::tables::{DescriptorTablePointer, lidt}; - use core::mem::size_of; - - let ptr = DescriptorTablePointer { - base: self as *const _ as u64, - limit: (size_of::() - 1) as u16, - }; - - unsafe { lidt(&ptr) }; - } -} - -impl Index for Idt { - type Output = IdtEntry; - fn index(&self, index: usize) -> &Self::Output { - match index { - 0 => &self.divide_by_zero, - 1 => &self.debug, - 2 => &self.non_maskable_interrupt, - 3 => &self.breakpoint, - 4 => &self.overflow, - 5 => &self.bound_range_exceeded, - 6 => &self.invalid_opcode, - 7 => &self.device_not_available, - 9 => &self.coprocessor_segment_overrun, - 16 => &self.x87_floating_point, - 18 => &self.machine_check, - 19 => &self.simd_floating_point, - 20 => &self.virtualization, - i @ 32...255 => &self.interrupts[i - 32], - i @ 15 | i @ 31 | i @ 21...29 => panic!("entry {} is reserved", i), - i @ 8 | i @ 10...14 | i @ 17 | i @ 30 => { - panic!("entry {} is an exception with error code", i) - } - i => panic!("no entry with index {}", i), - } - } -} - -impl IndexMut for Idt { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - match index { - 0 => &mut self.divide_by_zero, - 1 => &mut self.debug, - 2 => &mut self.non_maskable_interrupt, - 3 => &mut self.breakpoint, - 4 => &mut self.overflow, - 5 => &mut self.bound_range_exceeded, - 6 => &mut self.invalid_opcode, - 7 => &mut self.device_not_available, - 9 => &mut self.coprocessor_segment_overrun, - 16 => &mut self.x87_floating_point, - 18 => &mut self.machine_check, - 19 => &mut self.simd_floating_point, - 20 => &mut self.virtualization, - i @ 32...255 => &mut self.interrupts[i - 32], - i @ 15 | i @ 31 | i @ 21...29 => panic!("entry {} is reserved", i), - i @ 8 | i @ 10...14 | i @ 17 | i @ 30 => { - panic!("entry {} is an exception with error code", i) - } - i => panic!("no entry with index {}", i), - } - } -} - -/// An Interrupt Descriptor Table entry. -/// -/// The generic parameter can either be `HandlerFunc` or `HandlerFuncWithErrCode`, depending -/// on the interrupt vector. -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct IdtEntry { - pointer_low: u16, - gdt_selector: u16, - options: EntryOptions, - pointer_middle: u16, - pointer_high: u32, - reserved: u32, - phantom: PhantomData, -} - -/// A handler function for an interrupt or an exception without error code. -pub type HandlerFunc = extern "x86-interrupt" fn(&mut ExceptionStackFrame); -/// A handler function for an exception that pushes an error code. -pub type HandlerFuncWithErrCode = extern "x86-interrupt" fn(&mut ExceptionStackFrame, error_code: u64); -/// A page fault handler function that pushes a page fault error code. -pub type PageFaultHandlerFunc = extern "x86-interrupt" fn(&mut ExceptionStackFrame, error_code: PageFaultErrorCode); - -impl IdtEntry { - /// Creates a non-present IDT entry (but sets the must-be-one bits). - const fn missing() -> Self { - IdtEntry { - gdt_selector: 0, - pointer_low: 0, - pointer_middle: 0, - pointer_high: 0, - options: EntryOptions::minimal(), - reserved: 0, - phantom: PhantomData, - } - } - - /// Set the handler address for the IDT entry and sets the present bit. - /// - /// For the code selector field, this function uses the code segment selector currently - /// active in the CPU. - /// - /// The function returns a mutable reference to the entry's options that allows - /// further customization. - fn set_handler_addr(&mut self, addr: u64) -> &mut EntryOptions { - use x86_64::instructions::segmentation; - - self.pointer_low = addr as u16; - self.pointer_middle = (addr >> 16) as u16; - self.pointer_high = (addr >> 32) as u32; - - self.gdt_selector = segmentation::cs().0; - - self.options.set_present(true); - &mut self.options - } -} - -macro_rules! impl_set_handler_fn { - ($h:ty) => { - impl IdtEntry<$h> { - /// Set the handler function for the IDT entry and sets the present bit. - /// - /// For the code selector field, this function uses the code segment selector currently - /// active in the CPU. - /// - /// The function returns a mutable reference to the entry's options that allows - /// further customization. - pub fn set_handler_fn(&mut self, handler: $h) -> &mut EntryOptions { - self.set_handler_addr(handler as u64) - } - } - } -} - -impl_set_handler_fn!(HandlerFunc); -impl_set_handler_fn!(HandlerFuncWithErrCode); -impl_set_handler_fn!(PageFaultHandlerFunc); - -/// Represents the options field of an IDT entry. -#[derive(Debug, Clone, Copy)] -pub struct EntryOptions(u16); - -impl EntryOptions { - /// Creates a minimal options field with all the must-be-one bits set. - const fn minimal() -> Self { - // options.set_bits(9..12, 0b111); // 'must-be-one' bits - EntryOptions(0b111_000_000_000) - } - - /// Set or reset the preset bit. - pub fn set_present(&mut self, present: bool) -> &mut Self { - self.0.set_bit(15, present); - self - } - - /// Let the CPU disable hardware interrupts when the handler is invoked. By default, - /// interrupts are disabled on handler invocation. - pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self { - self.0.set_bit(8, !disable); - self - } - - /// Set the required privilege level (DPL) for invoking the handler. The DPL can be 0, 1, 2, - /// or 3, the default is 0. If CPL < DPL, a general protection fault occurs. - /// - /// This function panics for a DPL > 3. - pub fn set_privilege_level(&mut self, dpl: PrivilegeLevel) -> &mut Self { - self.0.set_bits(13..15, dpl as u16); - self - } - - /// Assigns a Interrupt Stack Table (IST) stack to this handler. The CPU will then always - /// switch to the specified stack before the handler is invoked. This allows kernels to - /// recover from corrupt stack pointers (e.g., on kernel stack overflow). - /// - /// An IST stack is specified by an IST index between 0 and 6 (inclusive). Using the same - /// stack for multiple interrupts can be dangerous when nested interrupts are possible. - /// - /// This function panics if the index is not in the range 0..7. - /// - /// ## Safety - /// This function is unsafe because the caller must ensure that the passed stack index is - /// valid and not used by other interrupts. Otherwise, memory safety violations are possible. - pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self { - // The hardware IST index starts at 1, but our software IST index - // starts at 0. Therefore we need to add 1 here. - self.0.set_bits(0..3, index + 1); - self - } -} - -/// Represents the exception stack frame pushed by the CPU on exception entry. -#[repr(C)] -pub struct ExceptionStackFrame { - /// This value points to the instruction that should be executed when the interrupt - /// handler returns. For most interrupts, this value points to the instruction immediately - /// following the last executed instruction. However, for some exceptions (e.g., page faults), - /// this value points to the faulting instruction, so that the instruction is restarted on - /// return. See the documentation of the `Idt` fields for more details. - pub instruction_pointer: VirtualAddress, - /// The code segment selector, padded with zeros. - pub code_segment: u64, - /// The flags register before the interrupt handler was invoked. - pub cpu_flags: u64, - /// The stack pointer at the time of the interrupt. - pub stack_pointer: VirtualAddress, - /// The stack segment descriptor at the time of the interrupt (often zero in 64-bit mode). - pub stack_segment: u64, -} - -impl fmt::Debug for ExceptionStackFrame { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct Hex(u64); - impl fmt::Debug for Hex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:#x}", self.0) - } - } - - let mut s = f.debug_struct("ExceptionStackFrame"); - s.field("instruction_pointer", &self.instruction_pointer); - s.field("code_segment", &self.code_segment); - s.field("cpu_flags", &Hex(self.cpu_flags)); - s.field("stack_pointer", &self.stack_pointer); - s.field("stack_segment", &self.stack_segment); - s.finish() - } -} - -bitflags! { - /// Describes an page fault error code. - pub flags PageFaultErrorCode: u64 { - /// If this flag is set, the page fault was caused by a page-protection violation, - /// else the page fault was caused by a not-present page. - const PROTECTION_VIOLATION = 1 << 0, - - /// If this flag is set, the memory access that caused the page fault was a write. - /// Else the access that caused the page fault is a memory read. This bit does not - /// necessarily indicate the cause of the page fault was a read or write violation. - const CAUSED_BY_WRITE = 1 << 1, - - /// If this flag is set, an access in user mode (CPL=3) caused the page fault. Else - /// an access in supervisor mode (CPL=0, 1, or 2) caused the page fault. This bit - /// does not necessarily indicate the cause of the page fault was a privilege violation. - const USER_MODE = 1 << 2, - - /// If this flag is set, the page fault is a result of the processor reading a 1 from - /// a reserved field within a page-translation-table entry. - const MALFORMED_TABLE = 1 << 3, - - /// If this flag is set, it indicates that the access that caused the page fault was an - /// instruction fetch. - const INSTRUCTION_FETCH = 1 << 4, - } -} \ No newline at end of file diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index f3203c1..a6322a3 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -1,6 +1,5 @@ pub mod driver; pub mod cpu; -pub mod idt; pub fn init() { cpu::enable_nxe_bit(); diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs index d0b0b8c..9befa8a 100644 --- a/src/interrupts/mod.rs +++ b/src/interrupts/mod.rs @@ -1,26 +1,17 @@ use x86_64::VirtualAddress; -use arch::idt::{Idt, ExceptionStackFrame, PageFaultErrorCode}; +use x86_64::structures::idt::{Idt, ExceptionStackFrame, PageFaultErrorCode}; use x86_64::structures::tss::TaskStateSegment; use memory::{MemoryController, as_ref_in_real}; use spin::Once; mod gdt; -static mut IDT: Idt = Idt::new(); - static TSS: Once = Once::new(); static GDT: Once = Once::new(); +static IDT: Once = Once::new(); const DOUBLE_FAULT_IST_INDEX: usize = 0; -pub unsafe fn init_idt() { - IDT.breakpoint.set_handler_fn(*as_ref_in_real(&breakpoint_handler)); - IDT.double_fault.set_handler_fn(*as_ref_in_real(&double_fault_handler)); - IDT.page_fault.set_handler_fn(*as_ref_in_real(&page_fault_handler)); - // .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); - IDT.load(); -} - pub fn init(memory_controller: &mut MemoryController) { use x86_64::structures::gdt::SegmentSelector; use x86_64::instructions::segmentation::set_cs; @@ -41,19 +32,29 @@ pub fn init(memory_controller: &mut MemoryController) { let gdt = GDT.call_once(|| { let mut gdt = gdt::Gdt::new(); code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment()); - tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss)); + tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(unsafe{as_ref_in_real(&tss)})); gdt }); gdt.load(); - unsafe { + unsafe { // reload code segment register set_cs(code_selector); // load TSS load_tss(tss_selector); } - // IDT.load(); + unsafe { + let idt = IDT.call_once(|| { + let mut idt = Idt::new(); + idt.breakpoint.set_handler_fn(*as_ref_in_real(&breakpoint_handler)); + idt.double_fault.set_handler_fn(*as_ref_in_real(&double_fault_handler)); + idt.page_fault.set_handler_fn(*as_ref_in_real(&page_fault_handler)) + .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); + idt + }); + as_ref_in_real(&idt).load(); + } } extern "x86-interrupt" fn breakpoint_handler( diff --git a/src/lib.rs b/src/lib.rs index 00c0c80..0c5aee5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,8 +48,6 @@ mod arch; pub extern "C" fn rust_main(multiboot_information_address: usize) { // ATTENTION: we have a very small stack and no guard page println!("Hello World{}", "!"); - unsafe{ interrupts::init_idt(); } - // unsafe{ let a = *(0xdeadbeaf as *const u8); } // page fault let boot_info = unsafe { multiboot2::load(multiboot_information_address) }; arch::init();