summaryrefslogtreecommitdiff
path: root/stage3/interrupts.c
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2023-12-10 16:21:05 +0100
committerLizzy Fleckenstein <lizzy@vlhl.dev>2023-12-10 16:21:05 +0100
commit7ecfb1b21cf00d7c622cb5be9b4e149e0971a49b (patch)
tree053a09ec799b19033a23eba8247512ea2c205d7d /stage3/interrupts.c
parent0451ead172447528ece5fb0fcbb461a986962532 (diff)
downloadcuddles-7ecfb1b21cf00d7c622cb5be9b4e149e0971a49b.tar.xz
handle interrupts
Diffstat (limited to 'stage3/interrupts.c')
-rw-r--r--stage3/interrupts.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/stage3/interrupts.c b/stage3/interrupts.c
new file mode 100644
index 0000000..fa4e59d
--- /dev/null
+++ b/stage3/interrupts.c
@@ -0,0 +1,148 @@
+#include "def.h"
+#include "halt.h"
+#include "font.h"
+#include "heap.h"
+
+extern u64 idt_entries[256]; // isr.asm
+
+typedef struct {
+ u64 which;
+ u64 error_code;
+ // automatically pushed
+ u64 rip;
+ u64 cs;
+ u64 rflags;
+ u64 rsp;
+ u64 ss;
+} interrupt_frame;
+
+static const char *exception[32] = {
+ "Division 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",
+ nil,
+ "x87 Floating-Point Exception",
+ "Alignment Check",
+ "Machine Check",
+ "SIMD Floating-Point Exception",
+ "Virtualization Exception",
+ "Control Protection Exception",
+ nil, nil, nil, nil, nil, nil,
+ "Hypervisor Injection Exception",
+ "VMM Communication Exception",
+ "Security Exception",
+ nil,
+};
+
+static void dump_frame(interrupt_frame *frame)
+{
+ print("rip = "); print_num(frame->rip, 16, 0); print("\n");
+ print("cs = "); print_num(frame->cs, 16, 0); print("\n");
+ print("rflags = "); print_num(frame->rflags, 16, 0); print("\n");
+ print("rsp = "); print_num(frame->rsp, 16, 0); print("\n");
+ print("ss = "); print_num(frame->ss, 16, 0); print("\n");
+}
+
+void interrupt_handler(interrupt_frame *frame)
+{
+ if (frame->which < 32) {
+ if (exception[frame->which] == nil) {
+ print("Unknown Exception ");
+ print_num(frame->which, 10, 0);
+ } else {
+ print(exception[frame->which]);
+ }
+ print("\n");
+
+ if (frame->which == 13) {
+ const char *bits[8] = {
+ "present",
+ "write",
+ "user",
+ "reserved_write",
+ "instruction_fetch",
+ "protection_key",
+ "shadow_stack",
+ "software_guard_extensions",
+ };
+
+ u8 err = frame->error_code;
+
+ for (int i = 0; i < 8; i++) {
+ print(bits[i]); print(" = "); print((err & 1) ? "true\n" : "false\n");
+ err >>= 1;
+ }
+ } else {
+ print("error_code = "); print_num(frame->error_code, 10, 0); print("\n");
+ }
+
+ dump_frame(frame);
+
+ halt();
+ } else {
+ print("Spurious Interrupt "); print_num(frame->which, 10, 0); print("\n");
+ dump_frame(frame);
+ }
+}
+
+void init_interrupts()
+{
+ typedef struct {
+ u16 offset_1;
+ u16 selector;
+ u8 ist;
+ u8 type_attrs;
+ u16 offset_2;
+ u32 offset_3;
+ u32 zero;
+ } __attribute__((packed)) interrupt_descriptor;
+
+ interrupt_descriptor *idt = malloc(256 * sizeof *idt);
+
+ for (int i = 0; i < 255; i++) {
+ union {
+ struct {
+ u16 offset_1;
+ u16 offset_2;
+ u32 offset_3;
+ } __attribute__((packed)) off;
+ u64 addr;
+ } __attribute__((packed)) isr = {
+ .addr = idt_entries[i],
+ };
+
+ idt[i] = (interrupt_descriptor) {
+ .offset_1 = isr.off.offset_1,
+ .selector = 0x8,
+ .ist = 0,
+ .type_attrs = 0x8E,
+ .offset_2 = isr.off.offset_2,
+ .offset_3 = isr.off.offset_3,
+ .zero = 0,
+ };
+ }
+
+ typedef struct {
+ u16 size;
+ u64 addr;
+ } __attribute__((packed)) idt_descriptor;
+
+ idt_descriptor idtr = {
+ .size = 256 * sizeof *idt - 1,
+ .addr = (u64) &idt[0],
+ };
+
+ asm("lidt %0" : : "m"(idtr));
+}