aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/core/idt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/core/idt.c')
-rw-r--r--src/kernel/core/idt.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/kernel/core/idt.c b/src/kernel/core/idt.c
new file mode 100644
index 0000000..2f244e3
--- /dev/null
+++ b/src/kernel/core/idt.c
@@ -0,0 +1,253 @@
+#include <idt.h>
+#include <gdt.h>
+#include <sys.h>
+#include <string.h>
+#include <dbglog.h>
+
+struct idt_entry {
+ uint16_t base_lo; //Low part of address to jump to
+ uint16_t sel; //Kernel segment selector
+ uint8_t always0;
+ uint8_t type_attr; //Type
+ uint16_t base_hi; //High part of address to jump to
+} __attribute__((packed));
+typedef struct idt_entry idt_entry_t;
+
+struct idt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+typedef struct idt_ptr idt_ptr_t;
+
+#define GATE_TYPE_INTERRUPT 14 // IF is cleared on interrupt
+#define GATE_TYPE_TRAP 15 // IF stays as is
+
+#define GATE_PRESENT (1<<7)
+#define GATE_DPL_SHIFT 5
+
+
+void isr0();
+void isr1();
+void isr2();
+void isr3();
+void isr4();
+void isr5();
+void isr6();
+void isr7();
+void isr8();
+void isr9();
+void isr10();
+void isr11();
+void isr12();
+void isr13();
+void isr14();
+void isr15();
+void isr16();
+void isr17();
+void isr18();
+void isr19();
+void isr20();
+void isr21();
+void isr22();
+void isr23();
+void isr24();
+void isr25();
+void isr26();
+void isr27();
+void isr28();
+void isr29();
+void isr30();
+void isr31();
+
+void irq0();
+void irq1();
+void irq2();
+void irq3();
+void irq4();
+void irq5();
+void irq6();
+void irq7();
+void irq8();
+void irq9();
+void irq10();
+void irq11();
+void irq12();
+void irq13();
+void irq14();
+void irq15();
+
+void syscall64();
+
+// ************************************************************
+// Handler code
+
+static idt_entry_t idt_entries[256];
+static idt_ptr_t idt_ptr;
+
+static isr_handler_t irq_handlers[16] = {0};
+static isr_handler_t ex_handlers[32] = {0};
+
+/* Called in interrupt.s when an exception fires (interrupt 0 to 31) */
+void idt_exHandler(registers_t *regs) {
+ if (ex_handlers[regs->int_no] != 0) {
+ ex_handlers[regs->int_no](regs);
+ } else {
+ //TODO: make sure all exceptions happenning in userspace do not cause kernel panic...
+ dbg_printf("Unhandled exception: %i\n", regs->int_no);
+ dbg_dump_registers(regs);
+ PANIC("Unhandled exception");
+ }
+}
+
+/* Called in interrupt.s when an IRQ fires (interrupt 32 to 47) */
+void idt_irqHandler(registers_t *regs) {
+ if (regs->err_code > 7) {
+ outb(0xA0, 0x20);
+ }
+ outb(0x20, 0x20);
+
+ dbg_printf("IRQ %i\n", regs->err_code);
+ if (irq_handlers[regs->err_code] != 0) {
+ irq_handlers[regs->err_code](regs);
+ }
+}
+
+/* Caled in interrupt.s when a syscall is called */
+void idt_syscallHandler(registers_t *regs) {
+ dbg_printf("Syscall %i\n", regs->int_no);
+ // do nothing, yet.
+}
+
+/* For internal use only. Sets up an entry of the IDT with given parameters. */
+static void idt_set_gate(uint8_t num, void (*fun)(), uint8_t type) {
+ uint32_t base = (uint32_t)fun;
+
+ idt_entries[num].base_lo = base & 0xFFFF;
+ idt_entries[num].base_hi = (base >> 16) & 0xFFFF;
+
+ idt_entries[num].sel = K_CODE_SEGMENT;
+ idt_entries[num].always0 = 0;
+ idt_entries[num].type_attr = GATE_PRESENT
+ | (3 << GATE_DPL_SHIFT) // accessible from user mode
+ | type;
+}
+
+static const struct {
+ uint8_t num;
+ void (*fun)();
+ uint8_t type;
+} gates[] = {
+ // Most processor exceptions are traps and handling them
+ // should be preemptible
+ { 0, isr0, GATE_TYPE_TRAP },
+ { 1, isr1, GATE_TYPE_TRAP },
+ { 2, isr2, GATE_TYPE_TRAP },
+ { 3, isr3, GATE_TYPE_TRAP },
+ { 4, isr4, GATE_TYPE_TRAP },
+ { 5, isr5, GATE_TYPE_TRAP },
+ { 6, isr6, GATE_TYPE_TRAP },
+ { 7, isr7, GATE_TYPE_TRAP },
+ { 8, isr8, GATE_TYPE_TRAP },
+ { 9, isr9, GATE_TYPE_TRAP },
+ { 10, isr10, GATE_TYPE_TRAP },
+ { 11, isr11, GATE_TYPE_TRAP },
+ { 12, isr12, GATE_TYPE_TRAP },
+ { 13, isr13, GATE_TYPE_TRAP },
+ { 14, isr14, GATE_TYPE_INTERRUPT }, // reenables interrupts later on
+ { 15, isr15, GATE_TYPE_TRAP },
+ { 16, isr16, GATE_TYPE_TRAP },
+ { 17, isr17, GATE_TYPE_TRAP },
+ { 18, isr18, GATE_TYPE_TRAP },
+ { 19, isr19, GATE_TYPE_TRAP },
+ { 20, isr20, GATE_TYPE_TRAP },
+ { 21, isr21, GATE_TYPE_TRAP },
+ { 22, isr22, GATE_TYPE_TRAP },
+ { 23, isr23, GATE_TYPE_TRAP },
+ { 24, isr24, GATE_TYPE_TRAP },
+ { 25, isr25, GATE_TYPE_TRAP },
+ { 26, isr26, GATE_TYPE_TRAP },
+ { 27, isr27, GATE_TYPE_TRAP },
+ { 28, isr28, GATE_TYPE_TRAP },
+ { 29, isr29, GATE_TYPE_TRAP },
+ { 30, isr30, GATE_TYPE_TRAP },
+ { 31, isr31, GATE_TYPE_TRAP },
+
+ // IRQs are not preemptible ; an IRQ handler should do the bare minimum
+ // (communication with the hardware), and then pass a message to a worker
+ // process in order to do further processing
+ { 32, irq0, GATE_TYPE_INTERRUPT },
+ { 33, irq1, GATE_TYPE_INTERRUPT },
+ { 34, irq2, GATE_TYPE_INTERRUPT },
+ { 35, irq3, GATE_TYPE_INTERRUPT },
+ { 36, irq4, GATE_TYPE_INTERRUPT },
+ { 37, irq5, GATE_TYPE_INTERRUPT },
+ { 38, irq6, GATE_TYPE_INTERRUPT },
+ { 39, irq7, GATE_TYPE_INTERRUPT },
+ { 40, irq8, GATE_TYPE_INTERRUPT },
+ { 41, irq9, GATE_TYPE_INTERRUPT },
+ { 42, irq10, GATE_TYPE_INTERRUPT },
+ { 43, irq11, GATE_TYPE_INTERRUPT },
+ { 44, irq12, GATE_TYPE_INTERRUPT },
+ { 45, irq13, GATE_TYPE_INTERRUPT },
+ { 46, irq14, GATE_TYPE_INTERRUPT },
+ { 47, irq15, GATE_TYPE_INTERRUPT },
+
+ // Of course, syscalls are preemptible
+ { 64, syscall64, GATE_TYPE_TRAP },
+
+ { 0, 0, 0 }
+};
+
+/* Remaps the IRQs. Sets up the IDT. */
+void idt_init() {
+ memset((uint8_t*)&idt_entries, 0, sizeof(idt_entry_t) * 256);
+
+ //Remap the IRQ table
+ outb(0x20, 0x11);
+ outb(0xA0, 0x11);
+ outb(0x21, 0x20);
+ outb(0xA1, 0x28);
+ outb(0x21, 0x04);
+ outb(0xA1, 0x02);
+ outb(0x21, 0x01);
+ outb(0xA1, 0x01);
+ outb(0x21, 0x0);
+ outb(0xA1, 0x0);
+
+ for (int i = 0; gates[i].type != 0; i++) {
+ idt_set_gate(gates[i].num, gates[i].fun, gates[i].type);
+ }
+
+ idt_ptr.limit = (sizeof(idt_entry_t) * 256) - 1;
+ idt_ptr.base = (uint32_t)&idt_entries;
+
+ asm volatile ("lidt %0"::"m"(idt_ptr):"memory");
+
+ // Some setup calls that come later on are not preemptible,
+ // so we wait until then to enable interrupts.
+}
+
+/* Sets up an IRQ handler for given IRQ. */
+void idt_set_irq_handler(int number, isr_handler_t func) {
+ if (number < 16 && number >= 0) {
+ irq_handlers[number] = func;
+ }
+}
+
+/* Sets up a handler for a processor exception */
+void idt_set_ex_handler(int number, isr_handler_t func) {
+ if (number >= 0 && number < 32) {
+ ex_handlers[number] = func;
+ }
+}
+
+void dbg_dump_registers(registers_t *regs) {
+ dbg_printf("/ Exception %i\n", regs->int_no);
+ dbg_printf("| EAX: 0x%p EBX: 0x%p ECX: 0x%p EDX: 0x%p\n", regs->eax, regs->ebx, regs->ecx, regs->edx);
+ dbg_printf("| EDI: 0x%p ESI: 0x%p ESP: 0x%p EBP: 0x%p\n", regs->edi, regs->esi, regs->esp, regs->ebp);
+ dbg_printf("| EIP: 0x%p CS : 0x%p DS : 0x%p SS : 0x%p\n", regs->eip, regs->cs, regs->ds, regs->ss);
+ dbg_printf("\\ EFl: 0x%p I# : 0x%p Err: 0x%p\n", regs->eflags, regs->int_no, regs->err_code);
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
+