diff --git a/src/interrupts/gdt.rs b/src/interrupts/gdt.rs new file mode 100644 index 00000000..d25ae1ff --- /dev/null +++ b/src/interrupts/gdt.rs @@ -0,0 +1,96 @@ +use x86::bits64::task::TaskStateSegment; +use x86::shared::segmentation::SegmentSelector; +use x86::shared::PrivilegeLevel; + +pub struct Gdt { + table: [u64; 8], + next_free: usize, +} + +impl Gdt { + pub fn new() -> Gdt { + Gdt { + table: [0; 8], + next_free: 1, + } + } + + pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { + let index = match entry { + Descriptor::UserSegment(value) => self.push(value), + Descriptor::SystemSegment(value_low, value_high) => { + let index = self.push(value_low); + self.push(value_high); + index + } + }; + SegmentSelector::new(index as u16, PrivilegeLevel::Ring0) + } + + fn push(&mut self, value: u64) -> usize { + if self.next_free < self.table.len() { + let index = self.next_free; + self.table[index] = value; + self.next_free += 1; + index + } else { + panic!("GDT full"); + } + } + + pub fn load(&'static self) { + use x86::shared::dtables::{DescriptorTablePointer, lgdt}; + use x86::shared::segmentation; + use core::mem::size_of; + + let ptr = DescriptorTablePointer { + base: self.table.as_ptr() as *const segmentation::SegmentDescriptor, + limit: (self.table.len() * size_of::() - 1) as u16, + }; + + unsafe { lgdt(&ptr) }; + } +} + +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 core::mem::size_of; + use bit_field::BitField; + + let ptr = tss as *const _ as u64; + + let mut low = PRESENT.bits(); + // base + low.set_range(16..40, ptr.get_range(0..24)); + low.set_range(56..64, ptr.get_range(24..32)); + // limit (the `-1` in needed since the bound is inclusive) + low.set_range(0..16, (size_of::() - 1) as u64); + // type (0b1001 = available 64-bit tss) + low.set_range(40..44, 0b1001); + + let mut high = 0; + high.set_range(0..32, ptr.get_range(32..64)); + + Descriptor::SystemSegment(low, high) + } +} + +bitflags! { + flags 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/interrupts/mod.rs b/src/interrupts/mod.rs index 5c19c5c7..691dd38a 100644 --- a/src/interrupts/mod.rs +++ b/src/interrupts/mod.rs @@ -11,6 +11,7 @@ use memory::MemoryController; use x86::bits64::task::TaskStateSegment; mod idt; +mod gdt; macro_rules! save_scratch_registers { () => {