/* ============================================================================ * Pactor64 — IDT + PIC Initialization (x86-64) * 256-entry IDT, PIC remapping to IRQ 0x20-0x2F, interrupt dispatch * ============================================================================ */ #include "../include/pactor64.h" /* === IDT Data === */ static struct idt_entry idt[256]; static struct idtr idtr_reg; /* === Interrupt handler table === */ typedef void (*irq_handler_t)(registers_t *regs); static irq_handler_t irq_handlers[256]; /* === Set a single IDT entry === */ static void idt_set_entry(int index, uint64_t handler, uint16_t sel, uint8_t flags) { idt[index].offset_low = handler & 0xFFFF; idt[index].offset_mid = (handler >> 16) & 0xFFFF; idt[index].offset_high = (handler >> 32) & 0xFFFFFFFF; idt[index].selector = sel; idt[index].ist = 0; idt[index].type_attr = flags; idt[index].reserved = 0; } /* === PIC Remap === */ void pic_remap(int offset1, int offset2) { /* ICW1: begin init, expect ICW4 */ outb(PIC1_CMD, 0x11); io_wait(); outb(PIC2_CMD, 0x11); io_wait(); /* ICW2: vector offsets */ outb(PIC1_DATA, offset1); io_wait(); outb(PIC2_DATA, offset2); io_wait(); /* ICW3: master has slave on IR2, slave is cascade identity 2 */ outb(PIC1_DATA, 0x04); io_wait(); outb(PIC2_DATA, 0x02); io_wait(); /* ICW4: 8086 mode */ outb(PIC1_DATA, 0x01); io_wait(); outb(PIC2_DATA, 0x01); io_wait(); /* Mask all IRQs */ outb(PIC1_DATA, 0xFF); outb(PIC2_DATA, 0xFF); } void pic_mask_all(void) { outb(PIC1_DATA, 0xFF); outb(PIC2_DATA, 0xFF); } void pic_unmask_irq(int irq) { uint16_t port; if (irq < 8) { port = PIC1_DATA; } else { port = PIC2_DATA; irq -= 8; } uint8_t mask = inb(port) & ~(1 << irq); outb(port, mask); } void pic_send_eoi(int irq) { if (irq >= 8) { outb(PIC2_CMD, PIC_EOI); } outb(PIC1_CMD, PIC_EOI); } /* === Install an IRQ handler === */ void irq_install(int irq, irq_handler_t handler) { irq_handlers[irq] = handler; } /* === Interrupt Dispatch (called from isr_common in asm) === */ void isr_dispatch(registers_t *regs) { uint64_t int_no = regs->int_no; /* Call registered handler if any */ if (irq_handlers[int_no]) { irq_handlers[int_no](regs); } else if (int_no < 32) { /* Unhandled CPU exception */ kprintf("\n [EXCEPTION] Interrupt %d, Error: %d\n", int_no, regs->err_code); kprintf(" RIP=%x CS=%x RFLAGS=%x\n", regs->rip, regs->cs, regs->rflags); if (int_no == 14) { uint64_t cr2; __asm__ volatile("mov %%cr2, %0" : "=r"(cr2)); kprintf(" CR2 (fault addr)=%x\n", cr2); } kprintf(" RAX=%x RBX=%x RCX=%x RDX=%x\n", regs->rax, regs->rbx, regs->rcx, regs->rdx); kprintf(" RSP=%x RBP=%x\n", regs->rsp, regs->rbp); kprintf(" System halted.\n"); cli(); hlt(); for (;;) hlt(); } /* Send EOI for hardware IRQs (0x20-0x2F) */ if (int_no >= 0x20 && int_no <= 0x2F) { pic_send_eoi(int_no - 0x20); } } /* === Initialize the full 256-entry IDT === */ void idt_init(void) { /* Zero the IDT */ kmemset(idt, 0, sizeof(idt)); /* Populate all 256 entries from the assembly stub table */ for (int i = 0; i < 256; i++) { idt_set_entry(i, isr_stub_table[i], 0x08, 0x8E); /* 0x08 = kernel code segment selector * 0x8E = Present, DPL=0, 64-bit interrupt gate */ } /* Load IDTR */ idtr_reg.limit = sizeof(idt) - 1; idtr_reg.base = (uint64_t)&idt; idt_load(&idtr_reg); }