diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs new file mode 100644 index 0000000..2014323 --- /dev/null +++ b/src/arch/x86_64/idt.rs @@ -0,0 +1,44 @@ +use alloc::boxed::Box; +use x86_64::structures::idt::*; + +pub fn init() { + IDT.load(); +} + +lazy_static! { + static ref IDT: Idt = { + use arch::interrupt::{handler::*, consts::*}; + use arch::gdt::DOUBLE_FAULT_IST_INDEX; + use x86_64::PrivilegeLevel; + use core::mem::transmute; + + // 这里主要利用了x86_64库提供的IDT结构 + // 它进行了完善的封装,有强类型约束 + // 然而这里我们需要绕过一些限制,例如: + // * 依赖于 "x86-interrupt" 函数ABI,而我们的是裸函数 + // * 某些保留中断号不允许设置,会触发panic + // 于是下面用了一些trick绕过了它们 + + let ring3 = [T_SWITCH_TOK, T_SYSCALL, 0x80]; + + let mut idt = Idt::new(); + let entries = unsafe{ &mut *(&mut idt as *mut _ as *mut [IdtEntry; 256]) }; + for i in 0..256 { + let mut opt = entries[i].set_handler_fn(unsafe { transmute(__vectors[i]) }); + if ring3.contains(&(i as u8)) { + opt.set_privilege_level(PrivilegeLevel::Ring3); + } + if i == T_DBLFLT as usize { + unsafe{ opt.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); } + } + } + idt + }; +} + +extern { + /// 中断向量表 + /// 符号定义在 [trap.asm](boot/trap.asm) + //noinspection RsStaticConstNaming + static __vectors: [extern fn(); 256]; +} diff --git a/src/arch/x86_64/idt/idt.rs b/src/arch/x86_64/idt/idt.rs deleted file mode 100644 index 2d35123..0000000 --- a/src/arch/x86_64/idt/idt.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Following copied from crate `x86_64` - -use core::ops::{Index, IndexMut}; - -pub struct Idt { - entries: [IdtEntry; 256], -} - -impl Idt { - pub const fn new() -> Idt { - Idt {entries: [IdtEntry::new(); 256]} - } - 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: u8) -> &Self::Output { - &self.entries[index as usize] - } -} - -impl IndexMut for Idt { - fn index_mut(&mut self, index: u8) -> &mut Self::Output { - &mut self.entries[index as usize] - } -} - -// Following copied from Redox - -bitflags! { - pub struct IdtFlags: u8 { - const PRESENT = 1 << 7; - const RING_0 = 0 << 5; - const RING_1 = 1 << 5; - const RING_2 = 2 << 5; - const RING_3 = 3 << 5; - const SS = 1 << 4; - const INTERRUPT = 0xE; - const TRAP = 0xF; - } -} - -#[derive(Copy, Clone, Debug)] -#[repr(packed)] -pub struct IdtEntry { - offsetl: u16, - selector: u16, - ist: u8, - attribute: u8, - offsetm: u16, - offseth: u32, - zero2: u32 -} - -impl IdtEntry { - pub const fn new() -> IdtEntry { - IdtEntry { - offsetl: 0, - selector: 0, - ist: 0, - attribute: 0, - offsetm: 0, - offseth: 0, - zero2: 0 - } - } - - pub fn set_flags(&mut self, flags: IdtFlags) -> &mut Self { - self.attribute = flags.bits; - self - } - - pub fn set_offset(&mut self, selector: u16, base: usize) -> &mut Self { - self.selector = selector; - self.offsetl = base as u16; - self.offsetm = (base >> 16) as u16; - self.offseth = (base >> 32) as u32; - self - } - - // A function to set the offset more easily - pub fn set_handler_fn(&mut self, func: unsafe extern fn()) -> &mut Self { - self.set_flags(IdtFlags::PRESENT | IdtFlags::RING_0 | IdtFlags::INTERRUPT); - self.set_offset(8, func as usize); - self - } - - 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.ist = (index + 1) as u8; - self - } -} \ No newline at end of file diff --git a/src/arch/x86_64/idt/mod.rs b/src/arch/x86_64/idt/mod.rs deleted file mode 100644 index 80b275c..0000000 --- a/src/arch/x86_64/idt/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -use self::idt::*; -use spin::Once; -use alloc::boxed::Box; - -mod idt; - -/// Alloc IDT at kernel heap, then init and load it. -pub fn init() { - let idt = Box::new({ - use arch::interrupt::{handler::*, consts::*}; - use arch::gdt::DOUBLE_FAULT_IST_INDEX; - - let mut idt = Idt::new(); - for i in 0u8..=255 { - idt[i].set_handler_fn(unsafe { __vectors[i as usize] }); - } - - idt[T_SWITCH_TOK].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); - // TODO: Enable interrupt during syscall - idt[T_SYSCALL].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); - idt[0x80].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); - - unsafe { - idt[T_DBLFLT].set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); - } - idt - }); - let idt = unsafe{ &*Box::into_raw(idt) }; - - idt.load(); -} - -extern { - //noinspection RsStaticConstNaming - static __vectors: [extern fn(); 256]; -}