kern/kernel/cpu/idt.c
2025-04-20 19:56:27 -04:00

166 lines
3.3 KiB
C

#include <lib.h>
#include <comus/memory.h>
#include <comus/asm.h>
#include <comus/cpu.h>
#include <comus/drivers/pit.h>
#include "idt.h"
#include "pic.h"
#define IDT_SIZE 256
struct idt_entry {
uint16_t isr_low; // low 16 bits of isr
uint16_t kernel_cs; // kernel segment selector
uint8_t ist; // interrupt stack table
uint8_t flags; // gate type, privilege level, present bit
uint16_t isr_mid; // middle 16 bits of isr
uint32_t isr_high; // high 32 bits of isr
uint32_t reserved;
} __attribute__((packed));
struct idtr {
uint16_t size;
uint64_t address;
} __attribute__((packed));
// interrupt gate
#define GATE_64BIT_INT 0x0E
// trap gate
#define GATE_64BIT_TRAP 0x0F
// privilege ring allowed to call interrupt
#define RING0 0x00
#define RING1 0x20
#define RING2 0x40
#define RING3 0x60
// interrupt is present in IDT
#define PRESENT 0x80
__attribute__((aligned(0x10))) static struct idt_entry idt[256];
static struct idtr idtr;
// from idt.S
extern void *isr_stub_table[];
// initialize and load the IDT
void idt_init(void)
{
// initialize idtr
idtr.address = (uint64_t)&idt;
idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1;
// initialize idt
for (size_t vector = 0; vector < IDT_SIZE; vector++) {
struct idt_entry *entry = &idt[vector];
uint64_t isr = (uint64_t)isr_stub_table[vector];
// interrupts before 0x20 are for cpu exceptions
uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT;
entry->kernel_cs = 0x08; // offset of 1 into GDT
entry->ist = 0;
entry->flags = PRESENT | RING0 | gate_type;
entry->isr_low = isr & 0xffff;
entry->isr_mid = (isr >> 16) & 0xffff;
entry->isr_high = (isr >> 32) & 0xffffffff;
entry->reserved = 0;
}
__asm__ volatile("lidt %0" : : "m"(idtr));
}
#define EX_DEBUG 0x01
#define EX_BREAKPOINT 0x03
#define EX_PAGE_FAULT 0x0e
// Intel manual vol 3 ch 6.3.1
char *EXCEPTIONS[] = {
"Division Error",
"Debug",
"NMI",
"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",
"Reserved",
"x87 Floating-Point Error",
"Alignment Check",
"Machine Check",
"SIMD Floaing-Point Exception",
"Virtualization Exception",
"Control Protection Exception",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Hypervisor Injection Exception",
"VMM Communication Exception",
"Security Exception",
"Reserved",
};
void idt_exception_handler(uint64_t exception, uint64_t code,
struct cpu_regs *state)
{
uint64_t cr2;
switch (exception) {
case EX_PAGE_FAULT:
// page faults store the offending address in cr2
__asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
if (!kload_page((void *)cr2))
return;
}
kputs("\n\n!!! EXCEPTION !!!\n");
kprintf("%#02lX %s\n", exception, EXCEPTIONS[exception]);
kprintf("Error code %#lX\n", code);
if (exception == EX_PAGE_FAULT) {
kprintf("Page fault address: %#016lx\n", cr2);
}
kputs("\n");
cpu_print_regs(state);
kputs("\n");
log_backtrace_ex((void *)state->rip, (void *)state->rbp);
while (1) {
halt();
}
}
void idt_pic_eoi(uint8_t exception)
{
pic_eoi(exception - PIC_REMAP_OFFSET);
}
int counter = 0;
void idt_pic_timer(void)
{
ticks++;
}
void idt_pic_keyboard(void)
{
}
void idt_pic_mouse(void)
{
}