summaryrefslogtreecommitdiffhomepage
path: root/src/loader/interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/loader/interrupt.c')
-rw-r--r--src/loader/interrupt.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/loader/interrupt.c b/src/loader/interrupt.c
new file mode 100644
index 0000000..e05b4e0
--- /dev/null
+++ b/src/loader/interrupt.c
@@ -0,0 +1,132 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#include <interrupt.h>
+#include <log.h>
+#include <pic.h>
+#include <panic.h>
+
+/**
+ * IDT
+ */
+
+extern u32 interrupt_table[];
+static struct idt_entry idt_entries[256] = { 0 };
+REAL static struct idt_ptr idt = { .size = sizeof(idt_entries) - 1, .base = idt_entries };
+
+void idt_install(void)
+{
+ for (u8 i = 0; i < 3; i++)
+ idt_entries[i] = IDT_ENTRY(interrupt_table[i], 0x18, INTERRUPT_GATE);
+
+ idt_entries[3] = IDT_ENTRY(interrupt_table[3], 0x18, INTERRUPT_TRAP);
+ idt_entries[4] = IDT_ENTRY(interrupt_table[4], 0x18, INTERRUPT_TRAP);
+
+ for (u8 i = 5; i < 48; i++)
+ idt_entries[i] = IDT_ENTRY(interrupt_table[i], 0x18, INTERRUPT_GATE);
+
+ // Load table
+ __asm__ volatile("lidt %0" : : "m"(idt) : "memory");
+}
+
+/**
+ * Exception (trap) handling
+ */
+
+static const char *interrupt_trap_names[32] = {
+ "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",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+};
+
+static void interrupt_trap_handler(struct interrupt_frame *frame)
+{
+ static u8 faulting = 0;
+ faulting++;
+
+ if (faulting == 2) {
+ // Fall back to serial driver
+ serial_print("Double fault, halting immediatly\n");
+ while (1)
+ __asm__ volatile("cli\nhlt");
+ }
+
+ log("%s Exception (code %x) at 0x%x!\n", interrupt_trap_names[frame->interrupt_no], frame->err_code,
+ frame->eip);
+
+ while (1)
+ __asm__ volatile("cli\nhlt");
+}
+
+/**
+ * Event handling
+ */
+
+static void (*interrupt_event_handlers[16])(void) = { 0 };
+
+void interrupt_event_handler_add(u32 interrupt_no, void (*handler)(void))
+{
+ assert(interrupt_no < COUNT(interrupt_event_handlers));
+ interrupt_event_handlers[interrupt_no] = handler;
+}
+
+static u32 interrupt_event_handler(struct interrupt_frame *frame)
+{
+ u32 interrupt_no = frame->interrupt_no - 32;
+ assert(interrupt_no < COUNT(interrupt_event_handlers));
+ void (*handler)(void) = interrupt_event_handlers[interrupt_no];
+ if (handler)
+ handler();
+
+ return (u32)frame;
+}
+
+/**
+ * Universal handler
+ */
+
+u32 interrupt_handler(u32 esp);
+u32 interrupt_handler(u32 esp)
+{
+ struct interrupt_frame *frame = (struct interrupt_frame *)esp;
+ if (frame->interrupt_no < 32)
+ interrupt_trap_handler(frame);
+ else if (frame->interrupt_no < 48)
+ esp = interrupt_event_handler(frame);
+ else
+ panic("Unknown interrupt\n");
+
+ pic_ack(frame->interrupt_no);
+ return esp;
+}