You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.1 KiB

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;
lazy_static! {
static ref IDT: Idt = {
use self::irq::*;
let mut idt = Idt::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.page_fault.set_handler_fn(page_fault_handler);
unsafe {
idt.double_fault.set_handler_fn(double_fault_handler)
.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
}
idt
};
}
// 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<TaskStateSegment> = Once::new();
static GDT: Once<gdt::Gdt> = 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);
}
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);
}
}
}