lib.rs
1 #![no_std] 2 #![cfg_attr(test, no_main)] 3 #![feature(custom_test_frameworks)] 4 #![test_runner(crate::test_runner)] 5 #![reexport_test_harness_main = "test_main"] 6 #![feature(abi_x86_interrupt)] 7 8 use core::panic::PanicInfo; 9 10 #[cfg(test)] 11 use bootloader::{entry_point, BootInfo}; 12 13 pub mod serial; 14 pub mod vga_buffer; 15 pub mod interrupts; 16 pub mod gdt; 17 pub mod memory; 18 pub mod allocator; 19 pub mod task; 20 21 extern crate alloc; 22 23 pub fn init() { 24 gdt::init(); 25 interrupts::init_idt(); 26 unsafe { interrupts::PICS.lock().initialize() }; 27 x86_64::instructions::interrupts::enable(); 28 } 29 30 pub trait Testable { 31 fn run(&self) -> (); 32 } 33 34 impl<T> Testable for T 35 where 36 T: Fn(), 37 { 38 fn run(&self) { 39 serial_print!("{}...\t", core::any::type_name::<T>()); 40 self(); 41 serial_println!("[ok]"); 42 } 43 } 44 45 pub fn test_runner(tests: &[&dyn Testable]) { 46 serial_println!("Running {} tests", tests.len()); 47 for test in tests { 48 test.run(); 49 } 50 exit_qemu(QemuExitCode::Success); 51 } 52 53 pub fn test_panic_handler(info: &PanicInfo) -> ! { 54 serial_println!("[failed]\n"); 55 serial_println!("Error: {}\n", info); 56 exit_qemu(QemuExitCode::Failed); 57 hlt_loop(); 58 } 59 60 pub fn hlt_loop() -> ! { 61 loop { 62 x86_64::instructions::hlt(); 63 } 64 } 65 66 #[cfg(test)] 67 entry_point!(test_kernel_main); 68 69 #[cfg(test)] 70 fn test_kernel_main(_boot_info: &'static BootInfo) -> ! { 71 init(); 72 test_main(); 73 hlt_loop(); 74 } 75 76 #[cfg(test)] 77 #[panic_handler] 78 fn panic(info: &PanicInfo) -> ! { 79 test_panic_handler(info) 80 } 81 82 83 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 84 #[repr(u32)] 85 pub enum QemuExitCode { 86 Success = 0x10, 87 Failed = 0x11, 88 } 89 90 pub fn exit_qemu(exit_code: QemuExitCode) { 91 use x86_64::instructions::port::Port; 92 93 unsafe { 94 let mut port = Port::new(0xf4); 95 port.write(exit_code as u32); 96 } 97 }