#![no_main] #![no_std] #![feature(abi_x86_interrupt)] use core::{cell::UnsafeCell, mem::offset_of}; use kernel::{ sync::LazyLock, x86_64::{ gdt::{DF_STACK, GlobalDescriptorTable, RING0}, idt::{self, Entry, InterruptDescriptorTable}, }, }; pub static GDT: LazyLock = LazyLock::new(GlobalDescriptorTable::new); #[unsafe(export_name = "_start")] pub extern "C" fn main() -> ! { kernel::serial_println!("Hello, world!"); GDT.load(); kernel::serial_println!("[ok] GDT loaded"); extern "x86-interrupt" fn double_fault_handler( _stack_frame: &mut idt::InterruptStackFrame, _error_code: u64, ) -> ! { kernel::serial_println!("[ok] Double fault handler called"); kernel::testing::exit_qemu(kernel::testing::QemuExitCode::Success) } static IDT: LazyLock = LazyLock::new(|| { let mut idt = InterruptDescriptorTable::new_default(); idt.double_fault = unsafe { Entry::new( double_fault_handler as *const (), offset_of!(GlobalDescriptorTable, kernel_code) as u16, idt::EntryOptions::empty_interrupt_gate() .with_present(true) .with_privilege_level(RING0) .with_interrupt_stack_table_index(DF_STACK), ) }; idt }); IDT.load(); stack_overflow(); panic!("Triggering a stack overflow to test double fault handling"); } #[allow(unconditional_recursion)] fn stack_overflow() { stack_overflow(); // for each recursion, the return address is pushed unsafe { let cell = UnsafeCell::new(0); cell.get().write_volatile(0); }; // prevent tail recursion optimizations } #[panic_handler] fn panic_thunk(info: &core::panic::PanicInfo) -> ! { kernel::testing::test_panic_handler(info) }