use core::panic::PanicInfo; use crate::{ arch::{drivers::vga::WRITER, gdt}, image::mono_bitmap::bruh, kernel_state::KERNEL_STATE, print, println, rhai_shell::KEYBUFF, VgaBuffer, SCREEN_BUFFER, }; use cpuio::outb; use pic8259::ChainedPics; use qrcode::{ render::{string, unicode}, QrCode, }; use spin::Lazy; use vga::colors::Color16; 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, // 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(|| { let mut idt = InterruptDescriptorTable::new(); 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); } reset_pit_for_cpu(); 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 }); extern "x86-interrupt" fn software_int_handler(stack_frame: InterruptStackFrame) { println!("EXCEPTION: SOFTWARE INT\n{:#?}", stack_frame); } extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { println!("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); } #[naked] extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { use super::task_switcher; unsafe { // print!("."); asm!( // Kernel tick "call {tick}", // Push task's state onto stack // and save task pointer into scheduler task_switcher::save_tasks_state!(), "mov rdi, rsp", "call {save}", // Switch to next task (interrupt'll be returned there) "jmp {switch_to_next}", tick = sym crate::kmain::tick, save = sym task_switcher::save_and_enqueue, switch_to_next = sym task_switcher::switch_to_next, options(noreturn), ); } } 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 { // Backspace '\u{8}' => { // TODO: Fix this and apply to new term WRITER.lock().backspace(); KEYBUFF.lock().push(8.into()); } // '^' => KERNEL_STATE.lock().shutdown(), chr => { KEYBUFF.lock().push(chr); print!("{chr}"); } }, DecodedKey::RawKey(key) => { use KeyCode::*; match KeyCode::from(key) { AltLeft | AltRight => (), ArrowDown | ArrowRight | ArrowLeft | ArrowUp => { warn!("ArrowKeys are unsupported currently"); } kc => print!("{kc:?}"), }; } } } unsafe { PICS.lock() .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8()); } } pub fn init_idt() { IDT.load(); } pub fn set_pit_frequency(pit: u16, freq: u32) { let ret = (1193180 / freq).try_into(); 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(50); set_pit_2(1000); set_pit_3(1000); } pub fn bsod(src: BSODSource) -> ! { trace!("{src:?}"); let mut mode = SCREEN_BUFFER.lock(); mode.force_redraw(); /* for y in 0..480 { for x in 0..640 { mode.set_pixel(x, y, 0x0000ff00); } } */ let mut x = 1; let mut y = 0; 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 ); for current in st.chars() { if current == '\n' || x == 40 { y += 1; x = 1; } else { mode.draw_char( (x * 14).try_into().unwrap(), (y * 22).try_into().unwrap(), current, 0xffff0000, ); } x += 1; } let mut x = 1; let mut y = 34; // 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(); for current in image.chars() { if current == '\n' { y += 1; x = 0; } else { if current == '█' { mode.draw_filled_rect(x * 6, y * 7, (x * 6) + 6, (y * 7) + 7, 0xffffff00); } } x += 1; } mode.copy_to_buffer(); sloop(); } #[derive(Debug)] pub enum BSODSource<'a> { DoubleFault(&'a InterruptStackFrame), Panic(&'a PanicInfo<'a>), }