// ... includes ...
#include "io.h"
#include "debug.h"
#include "arch/x86_64/isr.h"
#include "idt.h"
#define MODULE "ISR"


ISRHandler g_ISRHandlers[256];
static const char* const g_Exceptions[] = {
    "Divide by zero error",
    "Debug",
    "Non-maskable Interrupt",
    "Breakpoint",
    "Overflow",
    "Bound Range Exceeded",
    "Invalid Opcode",
    "Device Not Available",
    "Double Fault",
    "Coprocessor Segment Overrun",
    "Invalid TSS",
    "Segment Not Present",
    "Stack-Segment Fault",
    "General Protection Fault",
    "Page Fault",
    "",
    "x87 Floating-Point Exception",
    "Alignment Check",
    "Machine Check",
    "SIMD Floating-Point Exception",
    "Virtualization Exception",
    "Control Protection Exception ",
    "",
    "",
    "",
    "",
    "",
    "",
    "Hypervisor Injection Exception",
    "VMM Communication Exception",
    "Security Exception",
    ""
};

extern void x86_64_ISR_InitializeGates(void);   // defined in isrs_gen.c

void x86_64_ISR_Initialize(void)
{
    x86_64_ISR_InitializeGates();
    for (int i = 0; i < 256; i++)
        x86_64_IDT_EnableGate(i);
    x86_64_IDT_DisableGate(0x80);   // syscall gate if you want
}

void __attribute__((used)) x86_64_ISR_Handler(Registers* regs)
{
    if (g_ISRHandlers[regs->interrupt])
        g_ISRHandlers[regs->interrupt](regs);
    else if (regs->interrupt >= 32)
        log_err(MODULE, "Unhandled interrupt %d!", regs->interrupt);
    else {
        // panic log (use regs->rax etc. now)
        log_crit(MODULE, "KERNEL PANIC! Exception %d (%s)", regs->interrupt, g_Exceptions[regs->interrupt]);
        // ... print registers with rax/rbx etc. ...
        log_crit(MODULE, "  rax=%x  rbx=%x  rcx=%x  rdx=%x  rsi=%x  rdi=%x",
               regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi);

        log_crit(MODULE, "  rsp=%x  rbp=%x  rip=%x  rflags=%x  cs=%x  ss=%x",
               regs->rsp, regs->rbp, regs->rip, regs->rflags, regs->cs, regs->ss);

        log_crit(MODULE, "  interrupt=%x  errorcode=%x", regs->interrupt, regs->error);

        log_crit(MODULE, "KERNEL PANIC!");
        x86_64_Panic();
    }
}

void x86_64_ISR_RegisterHandler(int interrupt, ISRHandler handler)
{
    g_ISRHandlers[interrupt] = handler;
    x86_64_IDT_EnableGate(interrupt);
}