use super::Interrupts; use crate::io::qemu; use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode}; macro_rules! exception_default { ($stack_frame: expr) => { format_args!( "instruction addr: 0x{:08x}\nstack addr: 0x{:08x}\nflags: 0x{:x}", $stack_frame.instruction_pointer.as_u64(), $stack_frame.stack_pointer.as_u64(), $stack_frame.cpu_flags, ) }; } static mut expected_fault: Interrupts = Interrupts::None; pub unsafe fn expect_fault(int: Interrupts) { if expected_fault == Interrupts::None { expected_fault = int; } } fn get_expected_fault() -> Interrupts { unsafe { expected_fault } } pub extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) { match get_expected_fault() { Interrupts::Breakpoint => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( "BREAKPOINT exception thrown\n\n{}", exception_default!(stack_frame) ), } } pub extern "x86-interrupt" fn general_protection_fault_handler( stack_frame: &mut InterruptStackFrame, error_code: u64, ) { match get_expected_fault() { Interrupts::GeneralProtectionFault => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( "GENERAL PROTECTION exception thrown\nerror code: {:x}\n{}", error_code, exception_default!(stack_frame) ), } } pub extern "x86-interrupt" fn page_fault_handler( stack_frame: &mut InterruptStackFrame, error_code: PageFaultErrorCode, ) { use x86_64::registers::control::Cr2; match get_expected_fault() { Interrupts::PageFault => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( "PAGE FAULT while accessing address: 0x{:08x}\nerror code: {:?}(0x{:x})\n{}", Cr2::read().as_u64(), error_code, error_code.bits(), exception_default!(stack_frame) ), } } pub extern "x86-interrupt" fn segment_not_present_handler( stack_frame: &mut InterruptStackFrame, error_code: u64, ) { match get_expected_fault() { Interrupts::NotPresent => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( "SEGMENT NOT PRESENT exception\nerror code: 0x{:x}\n{}", error_code, exception_default!(stack_frame) ), } } pub extern "x86-interrupt" fn double_fault_handler( stack_frame: &mut InterruptStackFrame, _error_code: u64, // code is always zero ) { match get_expected_fault() { Interrupts::DoubleFault => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( "DOUBLE FAULT\nthis is a fatal exception\n{}", exception_default!(stack_frame) ), } }