#include #include #include #include #include #include "debugger.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)); } // Intel manual vol 3 ch 6.3.1 char *EXCEPTIONS[] = { "0x00 Division Error", "0x01 Debug", "0x02 NMI", "0x03 Breakpoint", "0x04 Overflow", "0x05 BOUND Range Exceeded", "0x06 Invalid Opcode", "0x07 Device Not Available", "0x08 Double Fault", "0x09 Coprocessor Segment Overrun", "0x0A Invalid TSS", "0x0B Segment Not Present", "0x0C Stack-Segment Fault", "0x0D General Protection Fault", "0x0E Page Fault", "0x0F Reserved", "0x10 x87 Floating-Point Error", "0x11 Alignment Check", "0x12 Machine Check", "0x13 SIMD Floaing-Point Exception", "0x14 Virtualization Exception", "0x15 Control Protection Exception", "0x16 Reserved", "0x17 Reserved", "0x18 Reserved", "0x19 Reserved", "0x1A Reserved", "0x1B Reserved", "0x1C Hypervisor Injection Exception", "0x1D VMM Communication Exception", "0x1E Security Exception", "0x1F Reserved", }; void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) { // breakpoint interrupt if (exception == 0x03) { debugger(state, DEBUG_INT3); return; } else if (exception == 0x01) { debugger(state, DEBUG_DBG); return; } char custom[64]; *custom = '\0'; // page faults store the offending address in cr2 if (exception == 0x0E) { strcat(custom, "\nPage fault address: 0x"); void *addr; __asm__ volatile ("mov %%cr2, %0" : "=r"(addr)); ultoa((size_t)addr, custom + 23, 16); } _panic_interrupt( (void *)state->rip, (void *)state->rbp, "Exception %s\nError code 0x%lu%s", EXCEPTIONS[exception], code, custom ); } void idt_pic_eoi(uint8_t exception) { pic_eoi(exception - PIC_REMAP_OFFSET); } int counter = 0; void idt_pic_timer(void) { // print a message once we know the timer works // but avoid spamming the logs if (counter == 3) { serial_out_str("pic timer!\n"); } if (counter <= 3) { counter++; } } void idt_pic_keyboard(void) {} void idt_pic_mouse(void) {}