//! Overflows the stack and passes if the double-fault handler (running on //! its own IST stack) gets control instead of the CPU triple-faulting. #![no_std] #![no_main] #![feature(abi_x86_interrupt)] use core::panic::PanicInfo; use lazy_static::lazy_static; use rust_kernel::{QemuExitCode, exit_qemu, serial_print, serial_println}; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { serial_print!("stack_overflow::stack_overflow...\t"); rust_kernel::gdt::init(); TEST_IDT.load(); // our own IDT whose double-fault handler reports success stack_overflow(); panic!("Execution continued after stack overflow"); } #[allow(unconditional_recursion)] fn stack_overflow() { stack_overflow(); // each call pushes a return address unsafe { core::ptr::read_volatile(&0u8) }; // prevent tail-call optimisation } lazy_static! { static ref TEST_IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); unsafe { idt.double_fault .set_handler_fn(test_double_fault_handler) .set_stack_index(rust_kernel::gdt::DOUBLE_FAULT_IST_INDEX); } idt }; } extern "x86-interrupt" fn test_double_fault_handler( _stack_frame: InterruptStackFrame, _error_code: u64, ) -> ! { serial_println!("[ok]"); exit_qemu(QemuExitCode::Success); rust_kernel::hlt_loop(); } #[panic_handler] fn panic(info: &PanicInfo) -> ! { rust_kernel::test_panic_handler(info) }