diff --git a/nel_os_kernel/src/interrupt/gdt.rs b/nel_os_kernel/src/interrupt/gdt.rs new file mode 100644 index 0000000..df4e767 --- /dev/null +++ b/nel_os_kernel/src/interrupt/gdt.rs @@ -0,0 +1,57 @@ +use lazy_static::lazy_static; +use x86_64::{ + instructions::tables::load_tss, + registers::segmentation::{Segment, CS}, + structures::{ + gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}, + tss::TaskStateSegment, + }, + VirtAddr, +}; + +pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; + +lazy_static! { + static ref TSS: TaskStateSegment = { + let mut tss = TaskStateSegment::new(); + tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = { + const STACK_SIZE: usize = 4096 * 5; + + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + + let stack_start = VirtAddr::from_ptr(&raw const STACK); + stack_start + STACK_SIZE as u64 + }; + tss + }; +} + +lazy_static! { + static ref GDT: (GlobalDescriptorTable, Selectors) = { + let mut gdt = GlobalDescriptorTable::new(); + let code_selector = gdt.append(Descriptor::kernel_code_segment()); + let tss_selector = gdt.append(Descriptor::tss_segment(&TSS)); + + ( + gdt, + Selectors { + code_selector, + tss_selector, + }, + ) + }; +} + +struct Selectors { + code_selector: SegmentSelector, + tss_selector: SegmentSelector, +} + +pub fn init() { + GDT.0.load(); + + unsafe { + CS::set_reg(GDT.1.code_selector); + load_tss(GDT.1.tss_selector); + } +} diff --git a/nel_os_kernel/src/interrupt/idt.rs b/nel_os_kernel/src/interrupt/idt.rs index d20cc1e..1442e57 100644 --- a/nel_os_kernel/src/interrupt/idt.rs +++ b/nel_os_kernel/src/interrupt/idt.rs @@ -1,12 +1,18 @@ use lazy_static::lazy_static; -use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; -use crate::warn; +use crate::{interrupt::gdt, warn}; lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); + unsafe { + idt.double_fault + .set_handler_fn(double_fault_handler) + .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); + } + idt.page_fault.set_handler_fn(page_fault_handler); idt }; } @@ -18,3 +24,23 @@ pub fn init_idt() { extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { warn!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); } + +extern "x86-interrupt" fn double_fault_handler( + stack_frame: InterruptStackFrame, + _error_code: u64, +) -> ! { + panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); +} + +extern "x86-interrupt" fn page_fault_handler( + stack_frame: InterruptStackFrame, + _error_code: PageFaultErrorCode, +) { + use x86_64::registers::control::Cr2; + + panic!( + "EXCEPTION: PAGE FAULT\n{:#?}\nAccessed address: {:#x}", + stack_frame, + Cr2::read().unwrap().as_u64() + ); +} diff --git a/nel_os_kernel/src/interrupt/mod.rs b/nel_os_kernel/src/interrupt/mod.rs index 2f024d2..ba7d073 100644 --- a/nel_os_kernel/src/interrupt/mod.rs +++ b/nel_os_kernel/src/interrupt/mod.rs @@ -1 +1,2 @@ +pub mod gdt; pub mod idt; diff --git a/nel_os_kernel/src/main.rs b/nel_os_kernel/src/main.rs index 9ac7025..f8985cb 100644 --- a/nel_os_kernel/src/main.rs +++ b/nel_os_kernel/src/main.rs @@ -68,6 +68,7 @@ fn hlt_loop() -> ! { #[unsafe(no_mangle)] pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) { + interrupt::gdt::init(); interrupt::idt::init_idt(); let virt = VirtAddr::new( @@ -142,5 +143,9 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) { x86_64::instructions::interrupts::int3(); + unsafe { + *(0xffdeadbeaf as *mut u8) = 0x43; + } + hlt_loop(); }