| 1 |
/* ============================================================================ |
| 2 |
* Pactor64 — IDT + PIC Initialization (x86-64) |
| 3 |
* 256-entry IDT, PIC remapping to IRQ 0x20-0x2F, interrupt dispatch |
| 4 |
* ============================================================================ */ |
| 5 |
#include "../include/pactor64.h" |
| 6 |
|
| 7 |
/* === IDT Data === */ |
| 8 |
static struct idt_entry idt[256]; |
| 9 |
static struct idtr idtr_reg; |
| 10 |
|
| 11 |
/* === Interrupt handler table === */ |
| 12 |
typedef void (*irq_handler_t)(registers_t *regs); |
| 13 |
static irq_handler_t irq_handlers[256]; |
| 14 |
|
| 15 |
/* === Set a single IDT entry === */ |
| 16 |
static void idt_set_entry(int index, uint64_t handler, uint16_t sel, uint8_t flags) { |
| 17 |
idt[index].offset_low = handler & 0xFFFF; |
| 18 |
idt[index].offset_mid = (handler >> 16) & 0xFFFF; |
| 19 |
idt[index].offset_high = (handler >> 32) & 0xFFFFFFFF; |
| 20 |
idt[index].selector = sel; |
| 21 |
idt[index].ist = 0; |
| 22 |
idt[index].type_attr = flags; |
| 23 |
idt[index].reserved = 0; |
| 24 |
} |
| 25 |
|
| 26 |
/* === PIC Remap === */ |
| 27 |
void pic_remap(int offset1, int offset2) { |
| 28 |
/* ICW1: begin init, expect ICW4 */ |
| 29 |
outb(PIC1_CMD, 0x11); io_wait(); |
| 30 |
outb(PIC2_CMD, 0x11); io_wait(); |
| 31 |
|
| 32 |
/* ICW2: vector offsets */ |
| 33 |
outb(PIC1_DATA, offset1); io_wait(); |
| 34 |
outb(PIC2_DATA, offset2); io_wait(); |
| 35 |
|
| 36 |
/* ICW3: master has slave on IR2, slave is cascade identity 2 */ |
| 37 |
outb(PIC1_DATA, 0x04); io_wait(); |
| 38 |
outb(PIC2_DATA, 0x02); io_wait(); |
| 39 |
|
| 40 |
/* ICW4: 8086 mode */ |
| 41 |
outb(PIC1_DATA, 0x01); io_wait(); |
| 42 |
outb(PIC2_DATA, 0x01); io_wait(); |
| 43 |
|
| 44 |
/* Mask all IRQs */ |
| 45 |
outb(PIC1_DATA, 0xFF); |
| 46 |
outb(PIC2_DATA, 0xFF); |
| 47 |
} |
| 48 |
|
| 49 |
void pic_mask_all(void) { |
| 50 |
outb(PIC1_DATA, 0xFF); |
| 51 |
outb(PIC2_DATA, 0xFF); |
| 52 |
} |
| 53 |
|
| 54 |
void pic_unmask_irq(int irq) { |
| 55 |
uint16_t port; |
| 56 |
if (irq < 8) { |
| 57 |
port = PIC1_DATA; |
| 58 |
} else { |
| 59 |
port = PIC2_DATA; |
| 60 |
irq -= 8; |
| 61 |
} |
| 62 |
uint8_t mask = inb(port) & ~(1 << irq); |
| 63 |
outb(port, mask); |
| 64 |
} |
| 65 |
|
| 66 |
void pic_send_eoi(int irq) { |
| 67 |
if (irq >= 8) { |
| 68 |
outb(PIC2_CMD, PIC_EOI); |
| 69 |
} |
| 70 |
outb(PIC1_CMD, PIC_EOI); |
| 71 |
} |
| 72 |
|
| 73 |
/* === Install an IRQ handler === */ |
| 74 |
void irq_install(int irq, irq_handler_t handler) { |
| 75 |
irq_handlers[irq] = handler; |
| 76 |
} |
| 77 |
|
| 78 |
/* === Interrupt Dispatch (called from isr_common in asm) === */ |
| 79 |
void isr_dispatch(registers_t *regs) { |
| 80 |
uint64_t int_no = regs->int_no; |
| 81 |
|
| 82 |
/* Call registered handler if any */ |
| 83 |
if (irq_handlers[int_no]) { |
| 84 |
irq_handlers[int_no](regs); |
| 85 |
} else if (int_no < 32) { |
| 86 |
/* Unhandled CPU exception */ |
| 87 |
kprintf("\n [EXCEPTION] Interrupt %d, Error: %d\n", int_no, regs->err_code); |
| 88 |
kprintf(" RIP=%x CS=%x RFLAGS=%x\n", regs->rip, regs->cs, regs->rflags); |
| 89 |
if (int_no == 14) { |
| 90 |
uint64_t cr2; __asm__ volatile("mov %%cr2, %0" : "=r"(cr2)); |
| 91 |
kprintf(" CR2 (fault addr)=%x\n", cr2); |
| 92 |
} |
| 93 |
kprintf(" RAX=%x RBX=%x RCX=%x RDX=%x\n", regs->rax, regs->rbx, regs->rcx, regs->rdx); |
| 94 |
kprintf(" RSP=%x RBP=%x\n", regs->rsp, regs->rbp); |
| 95 |
kprintf(" System halted.\n"); |
| 96 |
cli(); |
| 97 |
hlt(); |
| 98 |
for (;;) hlt(); |
| 99 |
} |
| 100 |
|
| 101 |
/* Send EOI for hardware IRQs (0x20-0x2F) */ |
| 102 |
if (int_no >= 0x20 && int_no <= 0x2F) { |
| 103 |
pic_send_eoi(int_no - 0x20); |
| 104 |
} |
| 105 |
} |
| 106 |
|
| 107 |
/* === Initialize the full 256-entry IDT === */ |
| 108 |
void idt_init(void) { |
| 109 |
/* Zero the IDT */ |
| 110 |
kmemset(idt, 0, sizeof(idt)); |
| 111 |
|
| 112 |
/* Populate all 256 entries from the assembly stub table */ |
| 113 |
for (int i = 0; i < 256; i++) { |
| 114 |
idt_set_entry(i, isr_stub_table[i], 0x08, 0x8E); |
| 115 |
/* 0x08 = kernel code segment selector |
| 116 |
* 0x8E = Present, DPL=0, 64-bit interrupt gate */ |
| 117 |
} |
| 118 |
|
| 119 |
/* Load IDTR */ |
| 120 |
idtr_reg.limit = sizeof(idt) - 1; |
| 121 |
idtr_reg.base = (uint64_t)&idt; |
| 122 |
idt_load(&idtr_reg); |
| 123 |
} |
| 124 |
|