//! Writing an [OS] in Rust: [Double Faults] //! //! [os]: https://os.phil-opp.com //! [double faults]: https://os.phil-opp.com/double-fault-exceptions/ #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(rustos::test_runner)] #![reexport_test_harness_main = "test_main"] #![feature(abi_x86_interrupt)] extern crate rustos; extern crate x86_64; use core::panic::PanicInfo; use rustos::{print, println}; #[no_mangle] pub extern "C" fn _start() -> ! { println!("Welcome to the real world!"); init(); #[cfg(test)] test_main(); println!("It did not crash!!!"); loop { x86_64::instructions::hlt(); } } #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); loop { x86_64::instructions::hlt(); } } #[cfg(test)] #[panic_handler] fn panic(info: &PanicInfo) -> ! { rustos::test_panic_handler(info) } extern crate lazy_static; extern crate pc_keyboard; extern crate pic8259_simple; extern crate spin; use lazy_static::lazy_static; use pic8259_simple::ChainedPics; use spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; fn init() { IDT.load(); // Initialize the interrupt controller. unsafe { PICS.lock().initialize() }; // Enable the hardware interrupts. x86_64::instructions::interrupts::enable(); } lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler); idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler); idt }; } extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptStackFrame) { print!("."); unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); } } extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) { use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; use x86_64::instructions::port::Port; lazy_static! { static ref KEYBOARD: Mutex> = Mutex::new( Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore), ); } let mut keyboard = KEYBOARD.lock(); let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { if let Some(key) = keyboard.process_keyevent(key_event) { match key { DecodedKey::Unicode(character) => print!("{}", character), DecodedKey::RawKey(key) => print!("{:?}", key), } } } unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); } } #[allow(dead_code)] extern "x86-interrupt" fn tenkey_interrupt_handler(_stack_frame: &mut InterruptStackFrame) { use x86_64::instructions::port::Port; let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; let key = match scancode { 0x02 => Some('1'), 0x03 => Some('2'), 0x04 => Some('3'), 0x05 => Some('4'), 0x06 => Some('5'), 0x07 => Some('6'), 0x08 => Some('7'), 0x09 => Some('8'), 0x0a => Some('9'), 0x0b => Some('0'), _ => None, }; if let Some(key) = key { print!("{}", key); } unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] enum InterruptIndex { Timer = PIC_1_OFFSET, Keyboard, } impl InterruptIndex { fn as_u8(self) -> u8 { self as u8 } fn as_usize(self) -> usize { usize::from(self.as_u8()) } } const PIC_1_OFFSET: u8 = 32; const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });