~kernel/archive/c/idt.c
.c
C
(text/x-csrc)
#include <stdint.h>
#include "module.h"
#include "idt.h"

extern void vga_write(const char*);

/* IDT definition */
struct idt_entry idt[IDT_ENTRIES];
struct idt_ptr   idt_descriptor;

/* Load IDT */
static inline void lidt(struct idt_ptr* p) {
    asm volatile ("lidt (%0)" : : "r"(p));
}

/* IRQ handler registration */
static void (*irq_handlers[IDT_ENTRIES])(void) = {0};

void register_irq(int irq, void (*handler)(void)) {
    if (irq >= 0 && irq < IDT_ENTRIES) {
        irq_handlers[irq] = handler;
    }
}

/* Initialize IDT with a generic handler for all vectors */
void idt_init(void) {
    for (int i = 0; i < IDT_ENTRIES; ++i) {
        uint64_t addr = (uint64_t)isr_handler_common;
        idt[i].offset_low  = addr & 0xFFFF;
        idt[i].selector    = 0x08;               /* Code segment selector */
        idt[i].ist         = 0;
        idt[i].type_attr   = 0x8E;               /* Interrupt gate */
        idt[i].offset_mid  = (addr >> 16) & 0xFFFF;
        idt[i].offset_high = (addr >> 32) & 0xFFFFFFFF;
        idt[i].zero        = 0;
    }
    /* Set IRQ1 (keyboard) to use the same handler; the C handler will dispatch */
    /* No special entry needed; all vectors use isr_handler_common */

    idt_descriptor.limit = sizeof(idt) - 1;
    idt_descriptor.base  = (uint64_t)&idt;

    lidt(&idt_descriptor);
    vga_write("IDT initialized\n");
}

/* ISR entry point defined in assembly */
extern void isr_handler_common(void);

/* C ISR handler that prints the interrupt number and dispatches IRQ handlers */
void isr_c_handler(uint64_t int_no) {
    char buf[32];
    int len = 0;
    uint64_t n = int_no;
    if (n == 0) {
        buf[len++] = '0';
    } else {
        char rev[32];
        int rev_len = 0;
        while (n > 0 && rev_len < 32) {
            rev[rev_len++] = '0' + (n % 10);
            n /= 10;
        }
        while (rev_len > 0) {
            buf[len++] = rev[--rev_len];
        }
    }
    buf[len++] = '\n';
    buf[len] = 0;
    vga_write(buf);

    /* Dispatch registered IRQ handler if present */
    if (int_no < IDT_ENTRIES && irq_handlers[int_no]) {
        irq_handlers[int_no]();
    }
}

/* Enable interrupts */
void irq_enable(void) { asm volatile ("sti"); }