summaryrefslogtreecommitdiff
path: root/kernel/src/arch/i686/idt.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/arch/i686/idt.c')
-rw-r--r--kernel/src/arch/i686/idt.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/kernel/src/arch/i686/idt.c b/kernel/src/arch/i686/idt.c
new file mode 100644
index 0000000..04fd5f8
--- /dev/null
+++ b/kernel/src/arch/i686/idt.c
@@ -0,0 +1,140 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys.h>
+#include <print.h>
+#include <panic.h>
+#include <arch/i686/pic.h>
+#include <arch/i686/idt.h>
+#include <time.h>
+#include <drivers/ps2kb.h>
+#include <drivers/ps2mouse.h>
+
+#include "tty/term.h"
+
+struct IdtEntry {
+ uint16_t isr_low;
+ uint16_t kernel_cs;
+ uint8_t _reserved;
+ uint8_t attributes;
+ uint16_t isr_high;
+} __attribute__((packed));
+
+struct Idtr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+enum IDTFlags {
+ IDT_FLAG_GATE_TASK = 0x5,
+ IDT_FLAG_GATE_16BIT_INT = 0x6,
+ IDT_FLAG_GATE_16BIT_TRAP = 0x7,
+ IDT_FLAG_GATE_32BIT_INT = 0xE,
+ IDT_FLAG_GATE_32BIT_TRAP = 0xF,
+
+ IDT_FLAG_RING0 = (0 << 5),
+ IDT_FLAG_RING1 = (1 << 5),
+ IDT_FLAG_RING2 = (2 << 5),
+ IDT_FLAG_RING3 = (3 << 5),
+
+ IDT_FLAG_PRESENT = 0x80,
+};
+
+#define WIDTH 30
+static char buf[WIDTH];
+static int timer = -1;
+
+void idt_pic_eoi(uint8_t exception) {
+ pic_eoi(exception - PIC_REMAP_OFFSET);
+}
+
+void idt_pic_timer(void) {
+
+ timer += 1;
+ if (timer % 20 != 0) return;
+
+ uint32_t state = term_save();
+
+ term_setfg(VGA_LIGHT_GREEN);
+ term_setpos(TERM_W - WIDTH - 1, 0);
+ for (size_t i = 0; i < WIDTH; i++) putchar(' ');
+ term_setpos(TERM_W - WIDTH - 1, 0);
+
+ struct Time t = get_localtime();
+ timetostr(&t, "%a %b %d %Y %H:%M:%S", buf, WIDTH);
+ printk("%s", buf);
+
+ term_load(state);
+}
+
+void idt_pic_keyboard(void) {
+ ps2kb_recv();
+}
+
+void idt_pic_mouse(void) {
+ ps2mouse_recv();
+}
+
+void idt_exception_handler(uint8_t exception) {
+ char* msg;
+ switch(exception) {
+ case 0x00:
+ msg = "Division by zero";
+ break;
+ case 0x02:
+ msg = "NMI";
+ break;
+ case 0x04:
+ msg = "Overflow";
+ break;
+ case 0x06:
+ msg = "invalid opcode";
+ break;
+ case 0x08:
+ msg = "double fault";
+ break;
+ case 0x0A:
+ msg = "invalid task state segment";
+ break;
+ case 0x0C:
+ msg = "stack segment fault";
+ break;
+ case 0x0D:
+ msg = "general protection fault";
+ break;
+ case 0x0E:
+ msg = "page fault";
+ break;
+ default:
+ msg = "unknown exception";
+ break;
+ }
+ panic("E%u: %s", exception, msg);
+}
+
+__attribute__((aligned(0x10)))
+static struct IdtEntry idt[256];
+static struct Idtr idtr;
+extern void* isr_stub_table[];
+
+static void set_descriptor(uint8_t vector, void* isr, uint8_t flags) {
+ struct IdtEntry* entry = &idt[vector];
+ entry->isr_low = (size_t)isr & 0xffff;
+ entry->kernel_cs = 0x08;
+ entry->attributes = flags;
+ entry->isr_high = (size_t)isr >> 16;
+ entry->_reserved = 0;
+}
+
+void idt_init(void) {
+ idtr.base = (uintptr_t)&idt[0];
+ idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1;
+
+ for(int i = 0; i < IDT_INTERRUPTS; i++) {
+ set_descriptor(i, isr_stub_table[i], 0x8e);
+ }
+
+ __asm__ volatile ("lidt %0" : : "m"(idtr));
+}
+