#include #include "apic.h" #include "console.h" #include "cpu.h" #include "debug.h" #include "device_manager.h" #include "gdt.h" #include "interrupts.h" #include "io.h" #include "log.h" #include "scheduler.h" #include "syscall.h" static const uint16_t PIC1 = 0x20; static const uint16_t PIC2 = 0xa0; extern "C" { void _halt(); uintptr_t isr_handler(uintptr_t, cpu_state*); uintptr_t irq_handler(uintptr_t, cpu_state*); uintptr_t syscall_handler(uintptr_t, cpu_state); #define ISR(i, name) extern void name (); #define EISR(i, name) extern void name (); #define UISR(i, name) extern void name (); #define IRQ(i, q, name) extern void name (); #include "interrupt_isrs.inc" #undef IRQ #undef UISR #undef EISR #undef ISR } isr operator+(const isr &lhs, int rhs) { using under_t = std::underlying_type::type; return static_cast(static_cast(lhs) + rhs); } uint8_t get_irq(unsigned vector) { switch (vector) { #define ISR(i, name) #define EISR(i, name) #define UISR(i, name) #define IRQ(i, q, name) case i : return q; #include "interrupt_isrs.inc" #undef IRQ #undef UISR #undef EISR #undef ISR default: return 0xff; } } static void disable_legacy_pic() { // Mask all interrupts outb(PIC2+1, 0xfc); outb(PIC1+1, 0xff); // Start initialization sequence outb(PIC1, 0x11); io_wait(); outb(PIC2, 0x11); io_wait(); // Remap into ignore ISRs outb(PIC1+1, static_cast(isr::isrIgnore0)); io_wait(); outb(PIC2+1, static_cast(isr::isrIgnore8)); io_wait(); // Tell PICs about each other outb(PIC1+1, 0x04); io_wait(); outb(PIC2+1, 0x02); io_wait(); } static void enable_serial_interrupts() { uint8_t ier = inb(COM1+1); outb(COM1+1, ier | 0x1); } void interrupts_init() { #define ISR(i, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0x8e); #define EISR(i, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0x8e); #define UISR(i, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0xee); #define IRQ(i, q, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0x8e); #include "interrupt_isrs.inc" #undef IRQ #undef UISR #undef EISR #undef ISR disable_legacy_pic(); enable_serial_interrupts(); log::info(logs::boot, "Interrupts enabled."); } uintptr_t isr_handler(uintptr_t return_rsp, cpu_state *regs) { console *cons = console::get(); switch (static_cast(regs->interrupt & 0xff)) { case isr::isrGPFault: { cons->set_color(9); cons->puts("\nGeneral Protection Fault:\n"); cons->set_color(); cons->printf(" errorcode: %lx", regs->errorcode); if (regs->errorcode & 0x01) cons->puts(" external"); int index = (regs->errorcode & 0xffff) >> 4; if (index) { switch ((regs->errorcode & 0x07) >> 1) { case 0: cons->printf(" GDT[%x]\n", index); gdt_dump(); break; case 1: case 3: cons->printf(" IDT[%x]\n", index); idt_dump(); break; default: cons->printf(" LDT[%x]??\n", index); break; } } else { cons->putc('\n'); } print_regs(*regs); /* print_stacktrace(2); print_stack(*regs); */ } _halt(); break; case isr::isrPageFault: { cons->set_color(11); cons->puts("\nPage Fault:\n"); cons->set_color(); cons->puts(" flags:"); if (regs->errorcode & 0x01) cons->puts(" present"); if (regs->errorcode & 0x02) cons->puts(" write"); if (regs->errorcode & 0x04) cons->puts(" user"); if (regs->errorcode & 0x08) cons->puts(" reserved"); if (regs->errorcode & 0x10) cons->puts(" ip"); cons->puts("\n"); uint64_t cr2 = 0; __asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2)); print_reg("cr2", cr2); print_reg("rsp", regs->user_rsp); print_reg("rip", regs->rip); cons->puts("\n"); print_stacktrace(2); } _halt(); break; case isr::isrTimer: { scheduler &s = scheduler::get(); return_rsp = s.tick(return_rsp); } break; case isr::isrLINT0: cons->puts("\nLINT0\n"); break; case isr::isrLINT1: cons->puts("\nLINT1\n"); break; case isr::isrAssert: { cons->set_color(); print_regs(*regs); print_stacktrace(2); } _halt(); break; case isr::isrSyscall: { return_rsp = syscall_dispatch(return_rsp, *regs); } break; case isr::isrSpurious: // No EOI for the spurious interrupt return return_rsp; case isr::isrIgnore0: case isr::isrIgnore1: case isr::isrIgnore2: case isr::isrIgnore3: case isr::isrIgnore4: case isr::isrIgnore5: case isr::isrIgnore6: case isr::isrIgnore7: //cons->printf("\nIGNORED: %02x\n", regs->interrupt); outb(PIC1, 0x20); break; case isr::isrIgnore8: case isr::isrIgnore9: case isr::isrIgnoreA: case isr::isrIgnoreB: case isr::isrIgnoreC: case isr::isrIgnoreD: case isr::isrIgnoreE: case isr::isrIgnoreF: //cons->printf("\nIGNORED: %02x\n", regs->interrupt); outb(PIC1, 0x20); outb(PIC2, 0x20); break; default: cons->set_color(9); cons->printf("\nReceived %02x interrupt:\n", (static_cast(regs->interrupt))); cons->set_color(); cons->printf(" ISR: %02lx ERR: %lx\n\n", regs->interrupt, regs->errorcode); print_regs(*regs); //print_stacktrace(2); _halt(); } *reinterpret_cast(0xffffff80fee000b0) = 0; return return_rsp; } uintptr_t irq_handler(uintptr_t return_rsp, cpu_state *regs) { console *cons = console::get(); uint8_t irq = get_irq(regs->interrupt); if (! device_manager::get().dispatch_irq(irq)) { cons->set_color(11); cons->printf("\nReceived unknown IRQ: %d (vec %d)\n", irq, regs->interrupt); cons->set_color(); print_regs(*regs); _halt(); } *reinterpret_cast(0xffffff80fee000b0) = 0; return return_rsp; } uintptr_t syscall_handler(uintptr_t return_rsp, cpu_state regs) { return syscall_dispatch(return_rsp, regs); }