/* * Copyright (c) 2022, able * * SPDX-License-Identifier: MPL-2.0 */ use core::panic::PanicInfo; use crate::{ arch::gdt, devices::pci::{PciDevice, PCI_DEVICES}, println, rhai_shell::KEYBUFF, }; use cpuio::outb; use pic8259::ChainedPics; use qrcode::QrCode; use seq_macro::seq; use spin::Lazy; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use super::sloop; pub const PIC_1_OFFSET: u8 = 32; pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; pub static PICS: spin::Mutex = spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); /// Interrupt offsets. #[derive(Debug, Clone, Copy)] #[repr(u8)] pub enum InterruptIndex { Timer = PIC_1_OFFSET, Keyboard, /// Mouse offset Mouse = 44, /// Disk offset Disk = 46, // SecondInterrupt = PIC_2_OFFSET, Cmos = 0x70, } impl InterruptIndex { fn as_u8(self) -> u8 { self as u8 } fn as_usize(self) -> usize { usize::from(self.as_u8()) } } static IDT: Lazy = Lazy::new(|| { reset_pit_for_cpu(); let mut idt = InterruptDescriptorTable::new(); seq!(N in 32..=255 { idt[N].set_handler_fn(undefined_handler_~N); }); idt.breakpoint.set_handler_fn(breakpoint_handler); unsafe { idt.double_fault .set_handler_fn(double_fault_handler) .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); } idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler); idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler); idt[InterruptIndex::Mouse.as_usize()].set_handler_fn(crate::hardware::mouse_interrupt_handler); // run `a + b + l + e + o + s print;` in ablescript and its 54 thats why this seemingly arbitrary number was chosen idt[54].set_handler_fn(software_int_handler); idt }); seq!(N in 32..=255 { extern "x86-interrupt" fn undefined_handler_~N(stack_frame: InterruptStackFrame) { error!("INT {}: {:?}", N, stack_frame); unsafe { PICS.lock() .notify_end_of_interrupt(N); } } }); extern "x86-interrupt" fn software_int_handler(stack_frame: InterruptStackFrame) { trace!("EXCEPTION: SOFTWARE INT\n{:#?}", stack_frame); unsafe { PICS.lock().notify_end_of_interrupt(54); } } extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { trace!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); } extern "x86-interrupt" fn double_fault_handler( stack_frame: InterruptStackFrame, // NOTE(able): ignore this always is 0 _error_code: u64, ) -> ! { bsod(BSODSource::DoubleFault(&stack_frame)); // panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); } /* SAFETY * DO NOT TOUCH * The `#[naked]` macro removes various error/bounds checks that * the Rust compiler would normally add. * *Early return* and *enabling interrupts* in this function are * undefined behavior. * As long as nothing in this function does something that would * normally trigger an error, this function is relatively safe. */ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { crate::kmain::tick(); unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); } } extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { use pc_keyboard::{ layouts::Us104Key, DecodedKey, HandleControl, KeyCode, Keyboard, ScancodeSet1, }; use spin::Mutex; use x86_64::instructions::port::Port; static KEYBOARD: Lazy>> = Lazy::new(|| Mutex::new(Keyboard::new(Us104Key, ScancodeSet1, HandleControl::Ignore))); let mut keyboard = KEYBOARD.lock(); if let Ok(Some(key)) = keyboard .add_byte(unsafe { Port::new(0x60).read() }) .map(|x| x.and_then(|ev| keyboard.process_keyevent(ev))) { // trace!("{key:?}"); match key { DecodedKey::Unicode(chr) => match chr { '\n' => { KEYBUFF.lock().push('\n'); } // Backspace '\u{8}' => { // TODO: Fix this and apply to new term KEYBUFF.lock().push(8.into()); // trace!("8"); // print!("\u{8}"); } // '^' => KERNEL_STATE.lock().shutdown(), chr => { KEYBUFF.lock().push(chr); // trace!("{chr}"); // print!("{chr}"); } }, DecodedKey::RawKey(key) => { use KeyCode::*; match KeyCode::from(key) { AltLeft | AltRight => (), ArrowDown | ArrowRight | ArrowLeft | ArrowUp => { // warn!("ArrowKeys are unsupported currently"); } _kc => { // trace!("Unprintable key: {kc:?}"), } }; } } } unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); } } pub fn init_idt() { IDT.load(); } /// https://wiki.osdev.org/Pit /// const PIT_MAX_FREQ: u32 = 1193182; pub fn set_pit_frequency(pit: u16, freq: u32) { // Dividing the maximum frequency by the desired frequency // gives roughly what the maximum value for the timer // counter should be to run at the desired frequency. let ret = (PIT_MAX_FREQ / freq).try_into(); // Type-bounded counter maximum. let divisor: u16 = match ret { Ok(div) => div, Err(err) => { error!("{}", err); warn!("Defaulting to 1000 on PIT{}", pit); 1000 } }; unsafe { outb(0x36, 0x43); outb((divisor & 0xFF) as u8, 0x39 + pit); outb((divisor >> 8) as u8, 0x40 + pit); } } pub fn set_pit_1(freq: u32) { set_pit_frequency(1, freq); } pub fn set_pit_2(freq: u32) { set_pit_frequency(2, freq); } pub fn set_pit_3(freq: u32) { set_pit_frequency(3, freq); } pub fn reset_pit_for_cpu() { set_pit_1(1000); set_pit_2(1000); set_pit_3(1000); } pub fn bsod(src: BSODSource) -> ! { let src1 = match src { BSODSource::DoubleFault(_) => "DoubleFault".to_string(), BSODSource::Panic(panic_info) => { let strr = format!("PANIC: {}", panic_info); strr } }; let st = format!( "We fucked up ඞ : \n{}\nThe following qr code will link you to the wiki which hopefully solves your problems", src1 ); println!("\n{}", st); // let sf = format!("https://git.ablecorp.us/able/ableos/wiki/Double-Faults"); let sd = match src { BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults", BSODSource::Panic(_) => { trace!("panic"); "https://git.ablecorp.us/able/ableos/wiki/Panic" } }; let code = QrCode::new(sd).unwrap(); let image = code .render::() .quiet_zone(false) .module_dimensions(2, 1) .build(); println!("{}", image); sloop(); } #[derive(Debug)] pub enum BSODSource<'a> { DoubleFault(&'a InterruptStackFrame), Panic(&'a PanicInfo<'a>), }