/ src / lib.rs
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  }