#![cfg(test)] use core::panic::PanicInfo; #[panic_handler] fn panic(info: &PanicInfo) -> ! { serial_println!("[failed]\n"); serial_println!("Error: {}", info); exit_qemu(QemuExitCode::Failed); loop {} } /// This function is hooked up to the #![test_runner] attribute made possible by the /// https://doc.rust-lang.org/unstable-book/language-features/custom-test-frameworks.html unstable /// feature. cf. https://os.phil-opp.com/testing/ pub fn test_runner(tests: &[&dyn TestFunction]) { serial_println!("Running {} test(s)", tests.len()); for test in tests { test.run(); } exit_qemu(QemuExitCode::Success); } pub trait TestFunction { fn run(&self) -> (); } impl TestFunction for T where T: Fn(), { fn run(&self) { serial_print!("{}...\t", core::any::type_name::()); self(); serial_println!("[ok]"); } } /// Exits qemu by writing to a special qemu emulated port. pub fn exit_qemu(exit_code: QemuExitCode) { use x86_64::instructions::port::Port; unsafe { let mut port = Port::new(0xf4); // isa-debug-exit port, see Cargo.toml port.write(exit_code as u32); } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum QemuExitCode { Success = 0x10, Failed = 0x11, }