181 lines
4.3 KiB
C

#include <lcrash/irq.h>
#include <lcrash/util.h>
#include <lcrash/debug/debug.h>
#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;
}