#include "idt.h" #include #include #include "../io/serial.h" #include "../kbd/ps2.h" struct interrupt_descriptor idt[256]; struct idtr idt_reg; // Address to our first interrupt handler extern char vector_0_handler[]; // Timer ticks extern uint64_t ticks; void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl) { uint64_t handler_addr = (uint64_t)handler; struct interrupt_descriptor* entry = &idt[vector]; // Address is split in three parts so we right-shift progressively to get it all entry->address_low = handler_addr & 0xFFFF; entry->address_mid = (handler_addr >> 16) & 0xFFFF; entry->address_high = handler_addr >> 32; // Kernel code selector (as set in GDT) entry->selector = 0x8; // Interrupt gate, present, DPL (having: max DPL = 3) entry->flags = 0b1110 | ((dpl & 0b11) << 5) | (1 << 7); // We won't use IST for now entry->ist = 0; } void idt_load(void* idt_addr) { // "limit" = "size" = Size of the IDT - 1 byte = (16*256)-1 = 0xFFF idt_reg.limit = 0xFFF; idt_reg.base = (uint64_t)idt_addr; asm volatile("lidt %0" :: "m"(idt_reg)); } void idt_init() { // We set 256 entries, but we have only the first few stubs. // Undefined behavior? for (size_t i=0; i<256; i++) { // Each vector handler is 16-byte aligned, so *16 = address of that handler idt_set_entry(i, vector_0_handler + (i*16), 0); } idt_load(&idt); serial_kputs("kernel: idt: Initialized IDT!\n"); } struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) { switch(context->vector_number) { case 0: serial_kputs("kernel: idt: Divide Error!\n"); break; case 1: serial_kputs("kernel: idt: Debug Exception!\n"); break; case 2: serial_kputs("kernel: idt: NMI Interrupt!\n"); break; case 3: serial_kputs("kernel: idt: Breakpoint Interrupt!\n"); break; case 4: serial_kputs("kernel: idt: Overflow Trap!\n"); break; case 5: serial_kputs("kernel: idt: BOUND Range Exceeded!\n"); break; case 6: serial_kputs("kernel: idt: Invalid Opcode!\n"); break; case 7: serial_kputs("kernel: idt: Device Not Available!\n"); break; case 8: serial_kputs("kernel: idt: Double Fault!\n"); break; case 9: serial_kputs("kernel: idt: Coprocessor Segment Overrun!\n"); break; case 10: serial_kputs("kernel: idt: Invalid TSS!\n"); break; case 11: serial_kputs("kernel: idt: Segment Not Present!\n"); break; case 12: serial_kputs("kernel: idt: Stack-Segment Fault!\n"); break; case 13: serial_kputs("kernel: idt: General Protection Fault!\n"); break; case 14: serial_kputs("kernel: idt: Page Fault!\n"); break; case 15: serial_kputs("kernel: idt: Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)\n"); break; case 16: serial_kputs("kernel: idt: x87 Floating-Point Error!\n"); break; case 17: serial_kputs("kernel: idt: Alignment Check Fault!\n"); break; case 18: serial_kputs("kernel: idt: Machine Check!\n"); break; case 19: serial_kputs("kernel: idt: SIMD Floating-Point Exception!\n"); break; case 20: serial_kputs("kernel: idt: Virtualization Exception!\n"); break; case 21: serial_kputs("kernel: idt: Control Protection Exception!\n"); break; case 32: //serial_kputs("Tick!"); ticks++; // Send an EOI so that we can continue having interrupts outb(0x20, 0x20); break; case 33: keyboard_handler(); break; default: serial_kputs("kernel: idt: Unexpected interrupt\n"); break; } return context; }