2025-06-13 18:03:39 -05:00
|
|
|
|
#include <stdio.h>
|
2025-05-28 14:41:02 -05:00
|
|
|
|
#include <port_io.h>
|
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
#include <drivers/idt.h>
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
#define IDT_MAX_DESCRIPTORS 256
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
#define PIC1_COMMAND 0x20
|
|
|
|
|
#define PIC1_DATA 0x21
|
|
|
|
|
#define PIC2_COMMAND 0xA0
|
|
|
|
|
#define PIC2_DATA 0xA1
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
/*
|
|
|
|
|
Most of the code is this file (and idt.h) are taken from the osdev wiki: https://wiki.osdev.org/Interrupts_Tutorial, though not all of it.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
2025-07-01 20:39:38 -05:00
|
|
|
|
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
|
|
|
|
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
|
|
|
|
uint8_t reserved; // Set to zero
|
|
|
|
|
uint8_t attributes; // Type and attributes; see the IDT page
|
|
|
|
|
uint16_t isr_high; // The higher 16 bits of the ISR's address
|
2025-06-13 18:03:39 -05:00
|
|
|
|
} __attribute__((packed)) idt_entry_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
2025-07-01 20:39:38 -05:00
|
|
|
|
uint16_t limit;
|
|
|
|
|
uint32_t base;
|
2025-06-13 18:03:39 -05:00
|
|
|
|
} __attribute__((packed)) idtr_t;
|
|
|
|
|
|
|
|
|
|
__attribute__((aligned(0x10)))
|
|
|
|
|
|
|
|
|
|
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
|
|
|
|
|
|
|
|
|
|
static idtr_t idtr;
|
|
|
|
|
|
|
|
|
|
static bool vectors[IDT_MAX_DESCRIPTORS];
|
|
|
|
|
|
|
|
|
|
extern void* isr_stub_table[];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((noreturn))
|
|
|
|
|
void exception_dispatcher(uint32_t int_no, uint32_t err_code)
|
2025-05-28 14:41:02 -05:00
|
|
|
|
{
|
2025-06-13 18:03:39 -05:00
|
|
|
|
switch (int_no)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
printf("Divide by zero exception\n");
|
|
|
|
|
break;
|
|
|
|
|
case 13:
|
|
|
|
|
printf("General Protection Fault: err=0x%x\n", err_code);
|
|
|
|
|
break;
|
|
|
|
|
case 14:
|
|
|
|
|
{
|
|
|
|
|
uint32_t cr2;
|
2025-06-27 14:48:06 -05:00
|
|
|
|
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
|
2025-06-13 18:03:39 -05:00
|
|
|
|
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
printf("Unhandled exception #%u, err=0x%x\n", int_no, err_code);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t cs, ds, es, ss;
|
|
|
|
|
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
|
|
|
|
asm volatile ("mov %%ds, %0" : "=r"(ds));
|
|
|
|
|
asm volatile ("mov %%es, %0" : "=r"(es));
|
|
|
|
|
asm volatile ("mov %%ss, %0" : "=r"(ss));
|
|
|
|
|
|
|
|
|
|
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
|
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
asm volatile ("cli; hlt");
|
|
|
|
|
|
|
|
|
|
/* Will never be reached */
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
asm volatile ("hlt" ::: "memory");
|
|
|
|
|
}
|
2025-06-13 18:03:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
|
|
|
|
|
2025-07-01 20:39:38 -05:00
|
|
|
|
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags)
|
|
|
|
|
{
|
2025-06-13 18:03:39 -05:00
|
|
|
|
idt_entry_t* descriptor = &idt[vector];
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
descriptor->isr_low = (uint32_t)isr & 0xFFFF;
|
|
|
|
|
descriptor->kernel_cs = 0x08;
|
|
|
|
|
descriptor->attributes = flags;
|
|
|
|
|
descriptor->isr_high = (uint32_t)isr >> 16;
|
|
|
|
|
descriptor->reserved = 0;
|
2025-05-28 14:41:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pic_remap(void)
|
|
|
|
|
{
|
2025-06-13 18:03:39 -05:00
|
|
|
|
uint8_t a1, a2;
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Save masks */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
a1 = inb(PIC1_DATA);
|
|
|
|
|
a2 = inb(PIC2_DATA);
|
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Start initialization sequence (in cascade mode) */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
outb(PIC1_COMMAND, 0x11);
|
|
|
|
|
outb(PIC2_COMMAND, 0x11);
|
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Set vector offset */
|
|
|
|
|
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */
|
|
|
|
|
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
outb(PIC1_DATA, 0x04);
|
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Tell Slave PIC its cascade identity (0000 0010) */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
outb(PIC2_DATA, 0x02);
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Set 8086/88 mode */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
outb(PIC1_DATA, 0x01);
|
|
|
|
|
outb(PIC2_DATA, 0x01);
|
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
/* Restore saved masks */
|
2025-06-13 18:03:39 -05:00
|
|
|
|
outb(PIC1_DATA, a1);
|
|
|
|
|
outb(PIC2_DATA, a2);
|
2025-05-28 14:41:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
void idt_init(void)
|
2025-05-28 14:41:02 -05:00
|
|
|
|
{
|
2025-06-13 18:03:39 -05:00
|
|
|
|
idtr.base = (uintptr_t)&idt[0];
|
|
|
|
|
idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1;
|
|
|
|
|
|
|
|
|
|
for (uint8_t vector = 0; vector < 32; vector++)
|
|
|
|
|
{
|
2025-06-27 14:48:06 -05:00
|
|
|
|
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
|
|
|
|
vectors[vector] = true;
|
2025-06-13 18:03:39 -05:00
|
|
|
|
}
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
extern void* irq_stub_table[];
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
for (uint8_t i = 0; i < 16; i++)
|
|
|
|
|
{
|
2025-06-27 14:48:06 -05:00
|
|
|
|
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
|
2025-06-13 18:03:39 -05:00
|
|
|
|
}
|
2025-05-28 14:41:02 -05:00
|
|
|
|
|
2025-06-13 18:03:39 -05:00
|
|
|
|
|
2025-06-27 14:48:06 -05:00
|
|
|
|
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
|
|
|
|
asm volatile ("sti"); /* set the interrupt flag */
|
2025-05-28 14:41:02 -05:00
|
|
|
|
}
|
2025-06-13 18:03:39 -05:00
|
|
|
|
|