diff --git a/src/bin/test-exception-double-fault-stack-overflow.rs b/src/bin/test-exception-double-fault-stack-overflow.rs new file mode 100644 index 00000000..5f366668 --- /dev/null +++ b/src/bin/test-exception-double-fault-stack-overflow.rs @@ -0,0 +1,83 @@ +#![feature(panic_implementation)] +#![feature(abi_x86_interrupt)] +#![no_std] +#![cfg_attr(not(test), no_main)] +#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))] + +#[macro_use] +extern crate blog_os; +extern crate x86_64; +#[macro_use] +extern crate lazy_static; + +use blog_os::exit_qemu; +use core::panic::PanicInfo; + +#[cfg(not(test))] +#[no_mangle] +#[allow(unconditional_recursion)] +pub extern "C" fn _start() -> ! { + blog_os::gdt::init(); + init_idt(); + + fn stack_overflow() { + stack_overflow(); // for each recursion, the return address is pushed + } + + // trigger a stack overflow + stack_overflow(); + + serial_println!("failed"); + serial_println!("No exception occured"); + + unsafe { + exit_qemu(); + } + + loop {} +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_implementation] +#[no_mangle] +pub fn panic(info: &PanicInfo) -> ! { + serial_println!("failed"); + serial_println!("{}", info); + + unsafe { + exit_qemu(); + } + + loop {} +} + + +use x86_64::structures::idt::{ExceptionStackFrame, Idt}; + +lazy_static! { + static ref IDT: Idt = { + let mut idt = Idt::new(); + unsafe { + idt.double_fault.set_handler_fn(double_fault_handler) + .set_stack_index(blog_os::gdt::DOUBLE_FAULT_IST_INDEX); + } + + idt + }; +} + +pub fn init_idt() { + IDT.load(); +} + +extern "x86-interrupt" fn double_fault_handler( + _stack_frame: &mut ExceptionStackFrame, _error_code: u64) +{ + serial_println!("ok"); + + unsafe { + exit_qemu(); + } + loop {} +} diff --git a/src/gdt.rs b/src/gdt.rs new file mode 100644 index 00000000..5a2f22b5 --- /dev/null +++ b/src/gdt.rs @@ -0,0 +1,44 @@ +use x86_64::{ + VirtAddr, + structures::gdt::{GlobalDescriptorTable, Descriptor, SegmentSelector}, + structures::tss::TaskStateSegment, + instructions::segmentation::set_cs, + instructions::tables::load_tss, +}; + +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; + static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + + let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); + let stack_end = stack_start + STACK_SIZE; + stack_end + }; + tss + }; + + static ref GDT: (GlobalDescriptorTable, Selectors) = { + let mut gdt = GlobalDescriptorTable::new(); + let code_selector = gdt.add_entry(Descriptor::kernel_code_segment()); + let tss_selector = gdt.add_entry(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 { + set_cs(GDT.1.code_selector); + load_tss(GDT.1.tss_selector); + } +} diff --git a/src/lib.rs b/src/lib.rs index d38dc5ba..faad4fc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ extern crate std; pub mod serial; pub mod vga_buffer; -pub mod tss; +pub mod gdt; pub unsafe fn exit_qemu() { use x86_64::instructions::port::Port; diff --git a/src/main.rs b/src/main.rs index 72a022a2..b0e89dda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ use core::panic::PanicInfo; pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); + blog_os::gdt::init(); init_idt(); fn stack_overflow() { @@ -47,7 +48,11 @@ lazy_static! { static ref IDT: Idt = { let mut idt = Idt::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); - idt.double_fault.set_handler_fn(double_fault_handler); + unsafe { + idt.double_fault.set_handler_fn(double_fault_handler) + .set_stack_index(blog_os::gdt::DOUBLE_FAULT_IST_INDEX); + } + idt }; } diff --git a/src/tss.rs b/src/tss.rs deleted file mode 100644 index 51c16f7a..00000000 --- a/src/tss.rs +++ /dev/null @@ -1,14 +0,0 @@ -use x86_64::structures::tss::TaskStateSegment; - -static DOUBLE_FAULT_STACK: [u8; 4096] = [0; 4096]; -const DOUBLE_FAULT_IST_INDEX: usize = 0; - -pub fn init() { - let mut tss = TaskStateSegment::new(); - tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = { - let stack_start = &DOUBLE_FAULT_STACK as *const [u8; _] as usize; - let stack_size = DOUBLE_FAULT_STACK.len(); - let stack_end = stack_start + stack_size; - stack_end - }; -}