#include #include #include #define PICMCMD 0x0020 #define PICMDAT 0x0021 #define PICSCMD 0x00A0 #define PICSDAT 0x00A1 struct IrqHandlerGate { /// Gate number u8 GateNumber; /// Hooks struct IrqHandlerHook* Hooks; }; struct [[gnu::packed]] IrqHandlerDescriptor { u16 Offset0; u16 Segment; u16 Flags; u16 Offset1; u32 Offset2; u32 Reserved; }; struct [[gnu::packed]] IrqHandlerIDTR { u16 Length; struct IrqHandlerDescriptor* Offset; }; struct IrqHandlerInterruptFrame { u64 PrevInstructionAddress; u64 PrevInstructionSegment; u64 PrevFlags; u64 PrevStackAddress; u64 PrevStackSegment; }; struct IrqHandlerGate IrqHandlerGates[256] = {}; [[gnu::aligned(16)]] struct IrqHandlerDescriptor IrqHandlerDescriptors[256] = {}; /// Check for spurious IRQs bool IrqHandlerCheckRealIRQ(u64 Interrupt) { if (Interrupt == 0x27) { PortWrite8(PICMCMD, 0x0B); // RDISR if (PortRead8(PICMDAT) & 0x80) return false; } if (Interrupt >= 0x28 && Interrupt <= 0x2f) { PortWrite8(PICSCMD, 0x0B); // RDISR if (PortRead8(PICSDAT) & 0x80) { PortWrite8(PICMCMD, 0x20); return false; } } return true; } /// Send an EOI to the PIC void IrqHandlerSendEOI(u64 Interrupt) { if (Interrupt >= 0x20 && Interrupt < 0x30) { if (Interrupt >= 0x28) PortWrite8(PICSCMD, 0x20); // EOI PortWrite8(PICMCMD, 0x20); // EOI } } /// Handle an interrupt [[gnu::target("general-regs-only")]] void IrqHandlerHandleInterrupt(struct IrqHandlerInterruptFrame* Frame, u64 Interrupt) { // Panic("Got interrupt"); IrqHandlerSendEOI(Interrupt); return; } /// Handle an exception [[gnu::target("general-regs-only")]] void IrqHandlerHandleException(struct IrqHandlerInterruptFrame* Frame, u64 ErrorCode, u64 Interrupt) { //Panic("Got exception"); IrqHandlerSendEOI(Interrupt); return; } s32 IrqHandlerInitialize() { extern int IrqHandlerISRTable; void* ISRTable = &IrqHandlerISRTable; // Table stating if an interrupt is an error or not bool Error[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; // Fill IDT for (int i = 0; i < 256; i++) { u64 Offset = (u64)ISRTable; IrqHandlerDescriptors[i].Segment = 0x10; // TODO: This shouldnt be hardcoded IrqHandlerDescriptors[i].Flags = Error[i] ? 0x8F00 : 0x8E00; IrqHandlerDescriptors[i].Offset0 = Offset & 0xffff; IrqHandlerDescriptors[i].Offset1 = (Offset >> 16) & 0xffff; IrqHandlerDescriptors[i].Offset2 = Offset >> 32 & 0xffffffff; ISRTable += 0x20; } // Load the IDT struct IrqHandlerIDTR IDTR; IDTR.Offset = IrqHandlerDescriptors; IDTR.Length = 256 * 16 - 1; asm ("lidt %0" :: "m" (IDTR)); // Drop to assembly and do a long jump to get our IRQ's working asm ("call IrqHandlerApplyStateChange"); // TODO: Disable APIC until APIC support is added // Reconfigure legacy PIC (TODO: Switch to APIC) PortWrite8(PICMCMD, 0x11); // Initialize / cascade PortWrite8(PICSCMD, 0x11); PortWrite8(PICMDAT, 0x20); // Map master PIC IRQs to 0x20-0x27 PortWrite8(PICSDAT, 0x28); // Map slave PIC IRQS to 0x28-0x2f PortWrite8(PICMDAT, 0x04); // Slave at IRQ2 PortWrite8(PICSDAT, 0x02); // Slave ID 2 PortWrite8(PICMDAT, 0x01); // Switch to 8086 mode PortWrite8(PICSDAT, 0x01); PortWrite8(PICMDAT, 0x01); // Respect all external interrupts except the PIC timer because its fucking stupid PortWrite8(PICSDAT, 0x00); return 0; } void IrqHandlerEnableInterrupts() { asm ("sti"); } void IrqHandlerDisableInterrupts() { asm ("cli"); } s32 IrqHandlerAttach(u8 Gate, struct IrqHandlerHook* Hook) { return -1; } s32 IrqHandlerDetach(struct IrqHandlerHook* Hook) { return -1; }