2022-11-20 22:17:13 +03:00

147 lines
2.9 KiB
C

#include "isr.h"
#include "../drivers/port.h"
#include "../console.h"
enum {
IDT_HANDLERS = 256,
};
typedef struct {
uint16_t low_offset;
uint16_t selector;
uint8_t always0;
uint8_t flags;
uint16_t high_offset;
} __attribute__((packed)) idt_gate_t;
idt_gate_t idt[IDT_HANDLERS];
#define low_16(address) (uint16_t)((address) & 0xFFFF)
#define high_16(address) (uint16_t)(((address) >> 16) & 0xFFFF)
void set_idt_gate(int n, uint32_t handler) {
idt[n].low_offset = low_16(handler);
idt[n].selector = 0x08; // see GDT
idt[n].always0 = 0;
// 0x8E = 1 00 0 1 110
// P DPL 0 D Type
idt[n].flags = 0x8E;
idt[n].high_offset = high_16(handler);
}
// defined in vectors.S
extern uint32_t default_handlers[];
void init_idt() {
if (default_handlers[0] == 0) {
panic("handler table empty\n");
}
for (int i = 0; i < IDT_HANDLERS; i++) {
set_idt_gate(i, default_handlers[i]);
}
}
const char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
};
#define ARRLEN(a) (sizeof(a) / sizeof(a[0]))
static isr_t interrupt_handlers[IDT_HANDLERS];
void register_interrupt_handler(uint8_t i, isr_t handler) {
interrupt_handlers[i] = handler;
}
void trap(registers_t *r) {
if (r->int_no < 32) {
const char* msg = "Reserved";
if (r->int_no < ARRLEN(exception_messages)) {
msg = exception_messages[r->int_no];
}
printk(msg);
printk("\n");
}
/* Handle the interrupt in a more modular way */
if (interrupt_handlers[r->int_no] != 0) {
isr_t handler = interrupt_handlers[r->int_no];
handler(r);
}
// EOI
if (r->int_no >= 40) {
port_byte_out(0xA0, 0x20); /* follower */
}
if (r->int_no >= 32) {
port_byte_out(0x20, 0x20); /* leader */
}
}
static void init_pic() {
// ICW1
port_byte_out(0x20, 0x11);
port_byte_out(0xA0, 0x11);
// ICW2
port_byte_out(0x21, 0x20);
port_byte_out(0xA1, 0x28);
// ICW3
port_byte_out(0x21, 0x04);
port_byte_out(0xA1, 0x02);
// ICW4
port_byte_out(0x21, 0x01);
port_byte_out(0xA1, 0x01);
// OCW1
port_byte_out(0x21, 0x0);
port_byte_out(0xA1, 0x0);
}
typedef struct {
uint16_t limit;
void* base;
} __attribute__((packed)) idt_register_t;
static idt_register_t idt_reg;
void load_idt() {
init_idt();
idt_reg.base = &idt;
idt_reg.limit = sizeof(idt) - 1;
asm("lidt (%0)" : : "r"(&idt_reg));
init_pic();
}
void cli() {
asm("cli");
}
void sti() {
asm("sti");
}