//! Writing an [OS] in Rust: [Double Faults] //! //! [os]: https://os.phil-opp.com //! [double faults]: https://os.phil-opp.com/double-fault-exceptions/ #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(rustos::test_runner)] #![reexport_test_harness_main = "test_main"] #![feature(abi_x86_interrupt)] extern crate rustos; use core::panic::PanicInfo; use rustos::println; #[no_mangle] pub extern "C" fn _start() -> ! { println!("Welcome to the real world!"); init(); #[cfg(not(test))] stack_overflow(); #[cfg(test)] test_main(); println!("It did not crash!!!"); loop {} } #[cfg(not(test))] #[allow(unconditional_recursion)] fn stack_overflow() { stack_overflow(); } #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); loop {} } #[cfg(test)] #[panic_handler] fn panic(info: &PanicInfo) -> ! { rustos::test_panic_handler(info) } extern crate lazy_static; extern crate x86_64; use lazy_static::lazy_static; #[allow(unused_imports)] use x86_64::{ structures::{ gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}, idt::{InterruptDescriptorTable, InterruptStackFrame}, tss::TaskStateSegment, }, VirtAddr, }; pub fn init() { use x86_64::instructions::segmentation::set_cs; use x86_64::instructions::tables::load_tss; GDT.0.load(); unsafe { set_cs(GDT.1.code_selector); load_tss(GDT.1.tss_selector); } IDT.load(); } lazy_static! { 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, } 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 }); stack_start + STACK_SIZE }; tss }; } lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); unsafe { idt.double_fault .set_handler_fn(double_fault_handler) .set_stack_index(DOUBLE_FAULT_IST_INDEX); } idt }; } extern "x86-interrupt" fn double_fault_handler( stack_frame: &mut InterruptStackFrame, _error_code: u64, ) -> ! { panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); }