#include #include #include #include #include #include #include #include enum { Nmi = 0x02, GpFault = 0x0d, PageFault = 0x0e, }; typedef struct { uint64_t ip, cs, flags; /* only valid if switching from/into user mode */ uint64_t sp, ss; } IretFrame; void (*irq_fn[16])(void) = {0}; static uint64_t getcr2(void) { uint64_t cr2; asm("mov %%cr2, %0" : "=r"(cr2)); return cr2; } static void log_interrupt(uint8_t inr, void *stackframe) { IretFrame *iret = stackframe; uint64_t *errcode = ((uint64_t*)stackframe) - 1; kprintf("interrupt %d, rip = k/%08x, cs 0x%x, code 0x%x\n", inr, iret->ip, iret->cs, *errcode); if ((iret->cs & 0x3) == 0) { /* ring 0? */ uint64_t *stack = (void*)iret->sp; kprintf("kernel rsp = %p, *rsp = %p\n", stack, *stack); } if (inr == PageFault) { kprintf("addr 0x%x\n", getcr2()); } } void isr_stage3(uint8_t inr, void *stackframe) { IretFrame *iret = stackframe; uint8_t irqn = inr - IRQ_IBASE; if (irqn < 16) { if (irq_fn[irqn]) { irq_fn[irqn](); irq_eoi(irqn); return; } } if (inr == Nmi) { /* print some debugging information */ log_interrupt(inr, stackframe); mem_debugprint(); return; } if ((iret->cs & 0x3) == 0) { /* ring 0? */ log_interrupt(inr, stackframe); cpu_halt(); } else { /* in user */ proc_kill(proc_cur, inr); proc_switch_any(); } }