From cfe95a098fd354466a53aeb2048dcb9ed76ee9d4 Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 31 Oct 2017 22:12:28 -0500 Subject: [PATCH] +x86_64::interrupts, x86_64::interrupts::gdt --- src/arch/x86_64/interrupts.rs | 1 - src/arch/x86_64/interrupts/gdt.rs | 104 ++++++++++++++++++++++++++++++++++++++ src/arch/x86_64/interrupts/mod.rs | 80 +++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 1 deletion(-) delete mode 100644 src/arch/x86_64/interrupts.rs create mode 100644 src/arch/x86_64/interrupts/gdt.rs create mode 100644 src/arch/x86_64/interrupts/mod.rs diff --git a/src/arch/x86_64/interrupts.rs b/src/arch/x86_64/interrupts.rs deleted file mode 100644 index f0d7e29..0000000 --- a/src/arch/x86_64/interrupts.rs +++ /dev/null @@ -1 +0,0 @@ -//! Controls Sparkle's IDT. diff --git a/src/arch/x86_64/interrupts/gdt.rs b/src/arch/x86_64/interrupts/gdt.rs new file mode 100644 index 0000000..ebea0b3 --- /dev/null +++ b/src/arch/x86_64/interrupts/gdt.rs @@ -0,0 +1,104 @@ +use core::mem::size_of; +use x86::structures::tss::TaskStateSegment; +use x86::structures::gdt::SegmentSelector; +use x86::PrivilegeLevel; + +pub struct Gdt { + table: [u64; 8], + next_free: usize, +} + +impl Gdt { + pub fn new() -> Gdt { + Gdt { + table: [0; 8], + next_free: 1, // 0th entry is always 0 + } + } + + pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { + let idx = match entry { + Descriptor::UserSegment(value) => self.push(value), + Descriptor::SystemSegment(low, high) => { + let idx = self.push(low); + self.push(high); + + idx + } + }; + + SegmentSelector::new(idx as u16, PrivilegeLevel::Ring0) + } + + pub fn load(&'static self) { + use x86::instructions::tables::{DescriptorTablePointer, lgdt}; + + let ptr = DescriptorTablePointer { + base: self.table.as_ptr() as u64, + limit: (self.table.len() * size_of::() - 1) as u16, + }; + + unsafe { + lgdt(&ptr); + } + } + + fn push(&mut self, value: u64) -> usize { + if self.next_free < self.table.len() { + let idx = self.next_free; + self.table[idx] = value; + self.next_free += 1; + + idx + } else { + // we don't need more than a handful of GDT entries. + // hitting this would indicate dev error + panic!("gdt: tried to push() but it's full!"); + } + } +} + +pub enum Descriptor { + UserSegment(u64), + SystemSegment(u64, u64), +} + +impl Descriptor { + pub fn kernel_code_segment() -> Descriptor { + let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE; + + Descriptor::UserSegment(flags.bits()) + } + + pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor { + use bit_field::BitField; + + let ptr = tss as *const _ as u64; + + let mut low = PRESENT.bits(); + // point to the TSS (low) + low.set_bits(16..40, ptr.get_bits(0..24)); + low.set_bits(56..64, ptr.get_bits(24..32)); + + // limit of the TSS + low.set_bits(0..16, (size_of::() - 1) as u64); + + // type. 0b1001 => available, 64 bit, tss + low.set_bits(40..44, 0b1001); + + let mut high = 0; + high.set_bits(0..32, ptr.get_bits(32..64)); + + Descriptor::SystemSegment(low, high) + } +} + +bitflags! { + struct DescriptorFlags: u64 { + const CONFORMING = 1 << 42; + const EXECUTABLE = 1 << 43; + const USER_SEGMENT = 1 << 44; + const PRESENT = 1 << 47; + const LONG_MODE = 1 << 53; + } +} diff --git a/src/arch/x86_64/interrupts/mod.rs b/src/arch/x86_64/interrupts/mod.rs new file mode 100644 index 0000000..ae33a3a --- /dev/null +++ b/src/arch/x86_64/interrupts/mod.rs @@ -0,0 +1,80 @@ +//! Controls Sparkle's IDT. + +use x86::structures::idt::{Idt, ExceptionStackFrame}; +use x86::structures::tss::TaskStateSegment; +use x86::structures::gdt::SegmentSelector; +use x86::VirtualAddress; +use spin::Once; + +use arch::x86_64::memory::MemoryController; + +mod gdt; + +use self::gdt::Gdt; + + +const IST_DOUBLE_FAULT: usize = 0; + +lazy_static! { + static ref IDT: Idt = { + let mut idt = Idt::new(); + + idt.breakpoint.set_handler_fn(breakpoint_handler); + unsafe { + idt.double_fault.set_handler_fn(double_fault_handler) + .set_stack_index(IST_DOUBLE_FAULT as u16); + } + + idt + }; +} + +static TSS: Once = Once::new(); +static GDT: Once = Once::new(); + +pub fn init(memory_controller: &mut MemoryController) { + use x86::instructions::segmentation::set_cs; + use x86::instructions::tables::load_tss; + + let double_fault_stack = memory_controller.alloc_stack(1) + .expect("could not allocate stack for double faulting"); + + let tss = TSS.call_once(|| { + let mut tss = TaskStateSegment::new(); + tss.interrupt_stack_table[IST_DOUBLE_FAULT] = + VirtualAddress(double_fault_stack.top()); + + tss + }); + + let mut code_selector = SegmentSelector(0); + let mut tss_selector = SegmentSelector(0); + let gdt = GDT.call_once(|| { + let mut gdt = Gdt::new(); + + code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment()); + tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss)); + + gdt + }); + gdt.load(); + + unsafe { + set_cs(code_selector); + load_tss(tss_selector); + } + + IDT.load(); +} + +extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut ExceptionStackFrame) { + println!("int[3]: trap breakpoint:\n{:#?}", stack_frame); +} + +extern "x86-interrupt" fn double_fault_handler( + stack_frame: &mut ExceptionStackFrame, _error_code: u64) +{ + println!("int[8]: fault: double:\n{:#?}", stack_frame); + + loop {} +}