diff --git a/kernel/arch/x86_64/idt.c b/kernel/arch/x86_64/idt.c new file mode 100644 index 0000000..e6bd4e3 --- /dev/null +++ b/kernel/arch/x86_64/idt.c @@ -0,0 +1,115 @@ +/* Nadir IDT base: 32 CPU-exception gates + fault printer. + * + * Runs in 64-bit long mode at Ring 0 (CPL 0) with the stage-2 GDT + * (kernel code selector 0x18). Privileged primitive: `lidt` in + * idt_init(). Fault behavior: before idt_init() any fault + * triple-faults; after, vectors 0-31 print diagnostics and halt. + * Vectors 32-255 stay not-present until the PIC is remapped. + * IF stays cleared; exceptions fire regardless of IF. + */ + +#include + +#include "console.h" +#include "idt.h" + +/* 64-bit interrupt gate descriptor (Intel SDM Vol. 3, IDT gate). */ +struct idt_entry { + uint16_t offset_low; + uint16_t selector; + uint8_t ist; + uint8_t type_attr; + uint16_t offset_mid; + uint32_t offset_high; + uint32_t reserved; +} __attribute__((packed)); + +/* IDTR image for `lidt`. */ +struct idtr { + uint16_t limit; + uint64_t base; +} __attribute__((packed)); + +/* Gate flags: present, DPL 0, 64-bit interrupt gate (0xE). */ +#define IDT_FLAG_PRESENT_INT 0x8EU +/* Kernel code segment from the stage-2 GDT (entry.asm). */ +#define KERNEL_CS 0x18U + +/* Full 256-entry table, 16-byte aligned as the CPU prefers. BSS. */ +static struct idt_entry idt[256] __attribute__((aligned(16))); +static struct idtr idtr; + +/* Stub addresses from isr.asm, one per exception vector 0-31. */ +extern uint64_t isr_stub_table[IDT_EXCEPTION_COUNT]; + +/* Install one gate: handler address + segment + IST index + flags. */ +static void idt_set_gate(uint8_t vector, uint64_t handler, uint16_t selector, + uint8_t ist, uint8_t flags) +{ + struct idt_entry *e = &idt[vector]; + + e->offset_low = (uint16_t)(handler & 0xFFFFU); + e->selector = selector; + e->ist = ist & 0x07U; + e->type_attr = flags; + e->offset_mid = (uint16_t)((handler >> 16) & 0xFFFFU); + e->offset_high = (uint32_t)((handler >> 32) & 0xFFFFFFFFU); + e->reserved = 0; +} + +/* Human-readable names for vectors 0-31 (Intel SDM Vol. 3). */ +static const char *const exception_names[IDT_EXCEPTION_COUNT] = { + "Divide Error (#DE)", "Debug Exception (#DB)", "NMI", + "Breakpoint (#BP)", "Overflow (#OF)", "Bound Range (#BR)", + "Invalid Opcode (#UD)", "Device Not Available (#NM)", + "Double Fault (#DF)", "Coprocessor Segment Overrun", + "Invalid TSS (#TS)", "Segment Not Present (#NP)", + "Stack-Segment Fault (#SS)", "General Protection (#GP)", + "Page Fault (#PF)", "Reserved (15)", + "x87 Floating-Point (#MF)", "Alignment Check (#AC)", + "Machine Check (#MC)", "SIMD Floating-Point (#XM)", + "Virtualization (#VE)", "Control Protection (#CP)", + "Reserved (22)", "Reserved (23)", "Reserved (24)", "Reserved (25)", + "Reserved (26)", "Reserved (27)", "Hypervisor Injection (#HV)", + "VMM Communication (#VC)", "Security Exception (#SX)", "Reserved (31)", +}; + +void idt_init(void) +{ + for (uint16_t i = 0; i < IDT_EXCEPTION_COUNT; i++) { + idt_set_gate((uint8_t)i, isr_stub_table[i], KERNEL_CS, 0, + IDT_FLAG_PRESENT_INT); + } + + idtr.limit = (uint16_t)(sizeof(idt) - 1); + idtr.base = (uint64_t)&idt[0]; + __asm__ volatile("lidt %0" ::"m"(idtr) : "memory"); +} + +void exception_handler(struct interrupt_frame *frame) +{ + uint64_t vector = frame->vector; + const char *name = "Unknown Exception"; + + if (vector < IDT_EXCEPTION_COUNT) { + name = exception_names[vector]; + } + + console_puts("\n*** EXCEPTION: "); + console_puts(name); + console_puts(" (vector "); + console_puthex64(vector); + console_puts(") ***\nerror: "); + console_puthex64(frame->error); + console_puts(" rip: "); + console_puthex64(frame->rip); + console_puts(" cs: "); + console_puthex64(frame->cs); + console_puts(" rflags: "); + console_puthex64(frame->rflags); + console_puts("\nSystem halted.\n"); + + for (;;) { + __asm__ volatile("cli; hlt"); + } +}