143 lines
4.2 KiB
C
143 lines
4.2 KiB
C
#include "idt.h"
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#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 <vector_no>*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;
|
|
} |