void hzclock(Ureg *ur) { Proc *up = externup(); uintptr_t pc; machp()->ticks++; if(machp()->machno == 0) sys->ticks = machp()->ticks; pc = userpc(ur); if(machp()->proc) machp()->proc->pc = pc; if(machp()->mmuflush){ if(up) mmuflush(); machp()->mmuflush = 0; } accounttime(); kmapinval(); if(kproftimer != nil) kproftimer(pc); oprof_alarm_handler(ur); if(machp()->online == 0) return; if(active.exiting) { print("someone's exiting\n"); exit(0); } if(machp()->machno == 0) { /* since sys->ticks is only updated if machp()->machno == 0 */ checkalarms(); } if(up && up->state == Running) hzsched(); /* in proc.c */ }
/* * All traps come here. It is slower to have all traps call trap() * rather than directly vectoring the handler. However, this avoids a * lot of code duplication and possible bugs. The only exception is * VectorSYSCALL. * Trap is called with interrupts disabled via interrupt-gates. */ void trap(Ureg* ureg) { int clockintr, vno, user; // cache the previous vno to see what might be causing // trouble vno = ureg->type; uint64_t gsbase = rdmsr(GSbase); //if (sce > scx) iprint("===================="); lastvno = vno; if (gsbase < 1ULL<<63) die("bogus gsbase"); Proc *up = externup(); char buf[ERRMAX]; Vctl *ctl, *v; machp()->perf.intrts = perfticks(); user = userureg(ureg); if(user && (machp()->NIX.nixtype == NIXTC)) { up->dbgreg = ureg; cycles(&up->kentry); } clockintr = 0; //_pmcupdate(machp()); if(ctl = vctl[vno]) { if(ctl->isintr) { machp()->intr++; if(vno >= VectorPIC && vno != VectorSYSCALL) machp()->lastintr = ctl->Vkey.irq; } else if(up) up->nqtrap++; if(ctl->isr) { ctl->isr(vno); if(islo())print("trap %d: isr %p enabled interrupts\n", vno, ctl->isr); } for(v = ctl; v != nil; v = v->next) { if(v->f) { v->f(ureg, v->a); if(islo())print("trap %d: ctlf %p enabled interrupts\n", vno, v->f); } } if(ctl->eoi) { ctl->eoi(vno); if(islo())print("trap %d: eoi %p enabled interrupts\n", vno, ctl->eoi); } intrtime(vno); if(ctl->isintr) { if(ctl->Vkey.irq == IrqCLOCK || ctl->Vkey.irq == IrqTIMER) clockintr = 1; if (ctl->Vkey.irq == IrqTIMER) oprof_alarm_handler(ureg); if(up && !clockintr) preempted(); } } else if(vno < nelem(excname) && user) { spllo(); snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]); postnote(up, 1, buf, NDebug); } else if(vno >= VectorPIC && vno != VectorSYSCALL) { /* * An unknown interrupt. * Check for a default IRQ7. This can happen when * the IRQ input goes away before the acknowledge. * In this case, a 'default IRQ7' is generated, but * the corresponding bit in the ISR isn't set. * In fact, just ignore all such interrupts. */ /* clear the interrupt */ i8259isr(vno); iprint("cpu%d: spurious interrupt %d, last %d\n", machp()->machno, vno, machp()->lastintr); intrtime(vno); if(user) kexit(ureg); return; } else { if(vno == VectorNMI) { nmienable(); if(machp()->machno != 0) { iprint("cpu%d: PC %#llx\n", machp()->machno, ureg->ip); for(;;); } } dumpregs(ureg); if(!user) { ureg->sp = PTR2UINT(&ureg->sp); dumpstackwithureg(ureg); } if(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d\n", vno); } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr) { if(0) if(user && up->ac == nil && up->nqtrap == 0 && up->nqsyscall == 0) { if(!waserror()) { up->ac = getac(up, -1); poperror(); runacore(); return; } } sched(); splhi(); } if(user) { if(up && up->procctl || up->nnote) notify(ureg); kexit(ureg); } }