From 01c0c3b2ad7dd5c8f2646c3aabbb2e7c219d5cd4 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 16 Apr 2018 01:22:18 +0800 Subject: [PATCH] Move IDT & GDT to arch, as Redox did. --- src/{interrupts => arch/x86_64}/gdt.rs | 69 +++++++++++- src/arch/x86_64/idt.rs | 26 +++++ .../x86_64/interrupt}/irq.rs | 0 src/arch/x86_64/interrupt/mod.rs | 2 + src/arch/x86_64/mod.rs | 2 + src/interrupts/mod.rs | 100 ------------------ src/lib.rs | 7 +- 7 files changed, 102 insertions(+), 104 deletions(-) rename src/{interrupts => arch/x86_64}/gdt.rs (57%) create mode 100644 src/arch/x86_64/idt.rs rename src/{interrupts => arch/x86_64/interrupt}/irq.rs (100%) delete mode 100644 src/interrupts/mod.rs diff --git a/src/interrupts/gdt.rs b/src/arch/x86_64/gdt.rs similarity index 57% rename from src/interrupts/gdt.rs rename to src/arch/x86_64/gdt.rs index 2e8c685..8e87c56 100644 --- a/src/interrupts/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -2,7 +2,55 @@ use core::fmt; use core::fmt::Debug; use x86_64::structures::tss::TaskStateSegment; use x86_64::structures::gdt::SegmentSelector; -use x86_64::PrivilegeLevel; +use x86_64::{PrivilegeLevel, VirtualAddress}; +use spin::Once; + +static TSS: Once = Once::new(); +static GDT: Once = Once::new(); + +pub fn init(double_fault_stack_top: usize) { + use x86_64::structures::gdt::SegmentSelector; + use x86_64::instructions::segmentation::set_cs; + use x86_64::instructions::tables::load_tss; + + let tss = TSS.call_once(|| { + let mut tss = TaskStateSegment::new(); + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] + = 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(); + gdt.add_entry(GNULL); + code_selector = + gdt.add_entry(KCODE); + gdt.add_entry(UCODE); + gdt.add_entry(KDATA); + gdt.add_entry(UDATA); + tss_selector = gdt.add_entry(Descriptor::tss_segment(&tss)); + gdt + }); + gdt.load(); + + unsafe { + // reload code segment register + set_cs(code_selector); + // load TSS + load_tss(tss_selector); + } +} + +pub const DOUBLE_FAULT_IST_INDEX: usize = 0; + +// Copied from xv6 x86_64 +const GNULL: Descriptor = Descriptor::UserSegment(0); +const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE +const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE +const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT +const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT pub struct Gdt { table: [u64; 8], @@ -110,4 +158,23 @@ impl Debug for Descriptor { write!(f, "SystemSegment{:?}", (low, high)), } } +} + +pub mod test +{ + pub fn print_flags() { + use super::*; + // The following 4 GDT entries were copied from xv6 x86_64 + let list: [(&str, Descriptor); 4] = [ + ("KCODE", super::KCODE), // Code, DPL=0, R/X + ("UCODE", super::UCODE), // Code, DPL=3, R/X + ("KDATA", super::KDATA), // Data, DPL=0, W + ("UDATA", super::UDATA), // Data, DPL=3, W + ]; + // Let's see what that means + println!("GDT Segments from xv6 x86_64:"); + for (name, desc) in list.iter() { + println!(" {}: {:?}", name, desc); + } + } } \ No newline at end of file diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs new file mode 100644 index 0000000..225364b --- /dev/null +++ b/src/arch/x86_64/idt.rs @@ -0,0 +1,26 @@ +use x86_64::structures::idt::Idt; +use spin::Once; + +static IDT: Once = Once::new(); + +pub fn init() { + let idt = IDT.call_once(|| { + use arch::interrupt::irq::*; + use consts::irq::*; + use arch::gdt::DOUBLE_FAULT_IST_INDEX; + + let mut idt = Idt::new(); + idt.breakpoint.set_handler_fn(breakpoint_handler); + idt.double_fault.set_handler_fn(double_fault_handler); + idt[(T_IRQ0 + IRQ_COM1) as usize].set_handler_fn(serial_handler); + idt[(T_IRQ0 + IRQ_KBD) as usize].set_handler_fn(keyboard_handler); + idt[(T_IRQ0 + IRQ_TIMER) as usize].set_handler_fn(timer_handler); + unsafe { + idt.page_fault.set_handler_fn(page_fault_handler) + .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); + } + idt + }); + + idt.load(); +} \ No newline at end of file diff --git a/src/interrupts/irq.rs b/src/arch/x86_64/interrupt/irq.rs similarity index 100% rename from src/interrupts/irq.rs rename to src/arch/x86_64/interrupt/irq.rs diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index 136c296..6c01339 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -1,5 +1,7 @@ use x86_64; +pub mod irq; + #[inline(always)] pub unsafe fn enable() { x86_64::instructions::interrupts::enable(); diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 6bad638..b110f0f 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -2,6 +2,8 @@ pub mod driver; pub mod cpu; pub mod interrupt; pub mod paging; +pub mod gdt; +pub mod idt; pub fn init() { cpu::enable_nxe_bit(); diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs deleted file mode 100644 index eed2dcb..0000000 --- a/src/interrupts/mod.rs +++ /dev/null @@ -1,100 +0,0 @@ -use x86_64::VirtualAddress; -use x86_64::structures::idt::Idt; -use x86_64::structures::tss::TaskStateSegment; -use memory::MemoryController; -use spin::Once; - -mod gdt; -mod irq; - -// Copied from xv6 x86_64 -const GNULL: gdt::Descriptor = gdt::Descriptor::UserSegment(0); -const KCODE: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE -const UCODE: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE -const KDATA: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT -const UDATA: gdt::Descriptor = gdt::Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT - -static TSS: Once = Once::new(); -static GDT: Once = Once::new(); -static IDT: Once = Once::new(); - -const DOUBLE_FAULT_IST_INDEX: usize = 0; - -pub fn init(memory_controller: &mut MemoryController) { - - test::print_flags(); - - use x86_64::structures::gdt::SegmentSelector; - use x86_64::instructions::segmentation::set_cs; - use x86_64::instructions::tables::load_tss; - - let double_fault_stack = memory_controller.alloc_stack(1) - .expect("could not allocate double fault stack"); - - let tss = TSS.call_once(|| { - let mut tss = TaskStateSegment::new(); - tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = 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::Gdt::new(); - gdt.add_entry(GNULL); - code_selector = - gdt.add_entry(KCODE); - gdt.add_entry(UCODE); - gdt.add_entry(KDATA); - gdt.add_entry(UDATA); - tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss)); - gdt - }); - gdt.load(); - - unsafe { - // reload code segment register - set_cs(code_selector); - // load TSS - load_tss(tss_selector); - } - - let idt = IDT.call_once(|| { - use self::irq::*; - use consts::irq::*; - - let mut idt = Idt::new(); - idt.breakpoint.set_handler_fn(breakpoint_handler); - idt.double_fault.set_handler_fn(double_fault_handler); - idt[(T_IRQ0 + IRQ_COM1) as usize].set_handler_fn(serial_handler); - idt[(T_IRQ0 + IRQ_KBD) as usize].set_handler_fn(keyboard_handler); - idt[(T_IRQ0 + IRQ_TIMER) as usize].set_handler_fn(timer_handler); - unsafe { - idt.page_fault.set_handler_fn(page_fault_handler) - .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); - } - idt - }); - - idt.load(); -} - -pub mod test -{ - pub fn print_flags() { - use super::gdt::*; - // The following 4 GDT entries were copied from xv6 x86_64 - let list: [(&str, Descriptor); 4] = [ - ("KCODE", super::KCODE), // Code, DPL=0, R/X - ("UCODE", super::UCODE), // Code, DPL=3, R/X - ("KDATA", super::KDATA), // Data, DPL=0, W - ("UDATA", super::UDATA), // Data, DPL=3, W - ]; - // Let's see what that means - println!("GDT Segments from xv6 x86_64:"); - for (name, desc) in list.iter() { - println!(" {}: {:?}", name, desc); - } - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index dcbbb5a..666b7b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,6 @@ extern crate syscall; #[macro_use] // print! mod io; mod memory; -mod interrupts; mod lang; mod util; #[macro_use] // test! @@ -60,8 +59,10 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) { HEAP_ALLOCATOR.lock().init(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE); } - // initialize our IDT - interrupts::init(&mut memory_controller); + let double_fault_stack = memory_controller.alloc_stack(1) + .expect("could not allocate double fault stack"); + arch::gdt::init(double_fault_stack.top()); + arch::idt::init(); test!(global_allocator); test!(guard_page);