#include "u.h"#include "tos.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h"#include <trace.h> static int trapinited; void noted(Ureg*, ulong); static void debugbpt(Ureg*, void*);static void fault386(Ureg*, void*);static void doublefault(Ureg*, void*);static void unexpected(Ureg*, void*);static void _dumpstack(Ureg*); static Lock vctllock;static Vctl *vctl[256]; enum{ Ntimevec = 20 /* number of time buckets for each intr */};//ulong intrtimes[256][Ntimevec];uvlong intrtimetot[256];uvlong intrcountx[256]; int (*traplapiceoi)(int); intintrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name){ Vctl *v; if(f == nil){ print("intrenable: nil handler for %d, tbdf %#ux for %s\n", irq, tbdf, name); return -1; } v = xalloc(sizeof(Vctl)); v->isintr = 1; v->irq = irq; v->tbdf = tbdf; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; ilock(&vctllock); v->vno = arch->intrenable(v); if(v->vno == -1){ iunlock(&vctllock); print("intrenable: couldn't enable irq %d, tbdf %#ux for %s\n", irq, tbdf, v->name); xfree(v); return -1; } if(vctl[v->vno]){ if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi) panic("intrenable: handler: %s %s %#p %#p %#p %#p", vctl[v->vno]->name, v->name, vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi); v->next = vctl[v->vno]; } vctl[v->vno] = v; if(v->mask) v->mask(v, 0); iunlock(&vctllock); return 0;} intintrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name){ Vctl **pv, *v; int vno; ilock(&vctllock); for(vno = 0; vno < 256; vno++) for(pv = vctl + vno; v = *pv; pv = &v->next) if(v->irq == irq) if(v->f == f) if(v->tbdf == tbdf) if(v->a == a) if(strcmp(name, v->name) == 0) goto found; print("bad intrdisable: %d %s\n", irq, name); iunlock(&vctllock); return -1;found: *pv = v->next; if(v->mask) v->mask(v, 1); if(vctl[vno] == nil && arch->intrdisable != nil) arch->intrdisable(v); iunlock(&vctllock); xfree(v); return 0;} static longirqallocread(Chan*, void *vbuf, long n, vlong offset){ char *buf, *p, str[2*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+1)+1]; int m, vno; long oldn; Vctl *v; if(n < 0 || offset < 0) error(Ebadarg); oldn = n; buf = vbuf; for(vno=0; vno<nelem(vctl); vno++){ for(v=vctl[vno]; v; v=v->next){ m = snprint(str, sizeof str, "%11d %11d %20llud %20llud %-*.*s %.*s\n", vno, v->irq, intrcountx[vno], intrtimetot[vno], 8, 8, v->type, KNAMELEN, v->name); if(m <= offset) /* if do not want this, skip entry */ offset -= m; else{ /* skip offset bytes */ m -= offset; p = str+offset; offset = 0; /* write at most max(n,m) bytes */ if(m > n) m = n; memmove(buf, p, m); n -= m; buf += m; if(n == 0) return oldn; } } } return oldn - n;} voidtrapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name){ Vctl *v; if(vno < 0 || vno >= VectorPIC) panic("trapenable: vno %d", vno); v = xalloc(sizeof(Vctl)); v->type = "trap"; v->tbdf = BUSUNKNOWN; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN); v->name[KNAMELEN-1] = 0; ilock(&vctllock); if(vctl[vno]) v->next = vctl[vno]->next; vctl[vno] = v; iunlock(&vctllock);} static voidnmienable(void){ int x; /* * Hack: should be locked with NVRAM access. */ outb(0x70, 0x80); /* NMI latch clear */ outb(0x70, 0); x = inb(0x61) & 0x07; /* Enable NMI */ outb(0x61, 0x08|x); outb(0x61, x);} /* * Minimal trap setup. Just enough so that we can panic * on traps (bugs) during kernel initialization. * Called very early - malloc is not yet available. */voidtrapinit0(void){ int d1, v; ulong vaddr; Segdesc *idt; idt = (Segdesc*)IDTADDR; vaddr = (ulong)vectortable; for(v = 0; v < 256; v++){ d1 = (vaddr & 0xFFFF0000)|SEGP; switch(v){ case VectorBPT: d1 |= SEGPL(3)|SEGIG; break; case VectorSYSCALL: d1 |= SEGPL(3)|SEGIG; break; default: d1 |= SEGPL(0)|SEGIG; break; } idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16); idt[v].d1 = d1; vaddr += 6; }} voidtrapinit(void){ /* * Special traps. * Syscall() is called directly without going through trap(). */ trapenable(VectorBPT, debugbpt, 0, "debugpt"); trapenable(VectorPF, fault386, 0, "fault386"); trapenable(Vector2F, doublefault, 0, "doublefault"); trapenable(Vector15, unexpected, 0, "unexpected"); nmienable(); addarchfile("irqalloc", 0444, irqallocread, nil); trapinited = 1;} static char* excname[32] = { "divide error", "debug exception", "nonmaskable interrupt", "breakpoint", "overflow", "bounds check", "invalid opcode", "coprocessor not available", "double fault", "coprocessor segment overrun", "invalid TSS", "segment not present", "stack exception", "general protection violation", "page fault", "15 (reserved)", "coprocessor error", "alignment check", "machine check", "SIMD exception", "20 (reserved)", "21 (reserved)", "22 (reserved)", "23 (reserved)", "24 (reserved)", "25 (reserved)", "26 (reserved)", "27 (reserved)", "28 (reserved)", "29 (reserved)", "30 (reserved)", "31 (reserved)",}; /* * keep histogram of interrupt service times */voidintrtime(Mach*, int vno){ ulong diff; ulong x; x = perfticks(); diff = x - m->perf.intrts; m->perf.intrts = x; m->perf.inintr += diff; if(up == nil && m->perf.inidle > diff) m->perf.inidle -= diff; intrtimetot[vno] += diff;// diff /= m->cpumhz*100; /* quantum = 100µsec */// if(diff >= Ntimevec)// diff = Ntimevec-1;// intrtimes[vno][diff]++; intrcountx[vno]++;} /* go to user space */voidkexit(Ureg*){ uvlong t; Tos *tos; /* precise time accounting, kernel exit */ tos = (Tos*)(USTKTOP-sizeof(Tos)); cycles(&t); tos->kcycles += t - up->kentry; tos->pcycles = up->pcycles; tos->pid = up->pid;} /* * 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. */voidtrap(Ureg* ureg){ int clockintr, i, vno, user; char buf[ERRMAX]; Proc *uprock; Vctl *ctl, *v; Mach *mach; if(!trapinited){ /* fault386 can give a better error message */ if(ureg->trap == VectorPF) fault386(ureg, nil); panic("trap %lud: not ready", ureg->trap); } m->perf.intrts = perfticks(); user = (ureg->cs & 0xFFFF) == UESEL; if(user){ up->dbgreg = ureg; cycles(&up->kentry); } clockintr = 0; vno = ureg->trap; if(ctl = vctl[vno]){ uprock = nil; if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER){ clockintr = 1; m->intr++; }else if(ctl->isintr){ uprock = up; up = nil; m->intr++; if(vno >= VectorPIC && vno != VectorSYSCALL) m->lastintr = ctl->irq; } if(ctl->isr) ctl->isr(vno); for(v = ctl; v != nil; v = v->next){ if(v->f != nil) v->f(ureg, v->a); } if(ctl->eoi) ctl->eoi(vno); intrtime(m, vno); if(uprock != nil){ up = uprock; 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. */ /* call all interrupt routines, just in case */ for(i = VectorPIC; i <= MaxIrqLAPIC; i++){ ctl = vctl[i]; if(ctl == nil) continue; if(!ctl->isintr) continue; for(v = ctl; v != nil; v = v->next){ if(v->f) v->f(ureg, v->a); } /* should we do this? */ if(vno < VectorAPIC) if(ctl->eoi) ctl->eoi(i); } /* clear the interrupt */ if(vno >= VectorAPIC){ if(traplapiceoi != nil) traplapiceoi(0); }else i8259isr(vno); if(1)print("cpu%d: spurious interrupt %d, last %d\n", m->machno, vno, m->lastintr); if(0)if(conf.nmach > 1){ for(i = 0; i < 32; i++){ if(!(active.machs & (1<<i))) continue; mach = MACHP(i); if(m->machno == mach->machno) continue; print(" cpu%d: last %d", mach->machno, mach->lastintr); } print("\n"); } m->spuriousintr++; intrtime(m, vno); if(user) kexit(ureg); return; } else{ if(vno == VectorNMI){ /* * Don't re-enable, it confuses the crash dumps. nmienable(); */ iprint("cpu%d: NMI PC %#p\n", m->machno, ureg->pc); while(m->machno != 0) ; } dumpregs(ureg); if(!user){ ureg->sp = (ulong)&ureg->sp; _dumpstack(ureg); } if(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d", vno); } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ sched(); splhi(); } if(user){ if(up->procctl || up->nnote) notify(ureg); kexit(ureg); }} /* * dump registers */voiddumpregs2(Ureg* ureg){ if(up) iprint("cpu%d: registers for %s %lud\n", m->machno, up->text, up->pid); else iprint("cpu%d: registers for kernel\n", m->machno); iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", ureg->flags, ureg->trap, ureg->ecode, ureg->pc); iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", ureg->ax, ureg->bx, ureg->cx, ureg->dx); iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n", ureg->si, ureg->di, ureg->bp); iprint(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n", ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF, ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);} voiddumpregs(Ureg* ureg){ vlong mca, mct; dumpregs2(ureg); /* * Processor control registers.Lines 1–500 of 1103. Load more
#include "u.h" #include "tos.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "../port/error.h" #include <trace.h> static int trapinited; void noted(Ureg*, ulong); static void debugbpt(Ureg*, void*); static void fault386(Ureg*, void*); static void doublefault(Ureg*, void*); static void unexpected(Ureg*, void*); static void _dumpstack(Ureg*); static Lock vctllock; static Vctl *vctl[256]; enum { Ntimevec = 20 /* number of time buckets for each intr */ }; //ulong intrtimes[256][Ntimevec]; uvlong intrtimetot[256]; uvlong intrcountx[256]; int (*traplapiceoi)(int); int intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) { Vctl *v; if(f == nil){ print("intrenable: nil handler for %d, tbdf %#ux for %s\n", irq, tbdf, name); return -1; } v = xalloc(sizeof(Vctl)); v->isintr = 1; v->irq = irq; v->tbdf = tbdf; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; ilock(&vctllock); v->vno = arch->intrenable(v); if(v->vno == -1){ iunlock(&vctllock); print("intrenable: couldn't enable irq %d, tbdf %#ux for %s\n", irq, tbdf, v->name); xfree(v); return -1; } if(vctl[v->vno]){ if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi) panic("intrenable: handler: %s %s %#p %#p %#p %#p", vctl[v->vno]->name, v->name, vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi); v->next = vctl[v->vno]; } vctl[v->vno] = v; if(v->mask) v->mask(v, 0); iunlock(&vctllock); return 0; } int intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name) { Vctl **pv, *v; int vno; ilock(&vctllock); for(vno = 0; vno < 256; vno++) for(pv = vctl + vno; v = *pv; pv = &v->next) if(v->irq == irq) if(v->f == f) if(v->tbdf == tbdf) if(v->a == a) if(strcmp(name, v->name) == 0) goto found; print("bad intrdisable: %d %s\n", irq, name); iunlock(&vctllock); return -1; found: *pv = v->next; if(v->mask) v->mask(v, 1); if(vctl[vno] == nil && arch->intrdisable != nil) arch->intrdisable(v); iunlock(&vctllock); xfree(v); return 0; } static long irqallocread(Chan*, void *vbuf, long n, vlong offset) { char *buf, *p, str[2*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+1)+1]; int m, vno; long oldn; Vctl *v; if(n < 0 || offset < 0) error(Ebadarg); oldn = n; buf = vbuf; for(vno=0; vno<nelem(vctl); vno++){ for(v=vctl[vno]; v; v=v->next){ m = snprint(str, sizeof str, "%11d %11d %20llud %20llud %-*.*s %.*s\n", vno, v->irq, intrcountx[vno], intrtimetot[vno], 8, 8, v->type, KNAMELEN, v->name); if(m <= offset) /* if do not want this, skip entry */ offset -= m; else{ /* skip offset bytes */ m -= offset; p = str+offset; offset = 0; /* write at most max(n,m) bytes */ if(m > n) m = n; memmove(buf, p, m); n -= m; buf += m; if(n == 0) return oldn; } } } return oldn - n; } void trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) { Vctl *v; if(vno < 0 || vno >= VectorPIC) panic("trapenable: vno %d", vno); v = xalloc(sizeof(Vctl)); v->type = "trap"; v->tbdf = BUSUNKNOWN; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN); v->name[KNAMELEN-1] = 0; ilock(&vctllock); if(vctl[vno]) v->next = vctl[vno]->next; vctl[vno] = v; iunlock(&vctllock); } static void nmienable(void) { int x; /* * Hack: should be locked with NVRAM access. */ outb(0x70, 0x80); /* NMI latch clear */ outb(0x70, 0); x = inb(0x61) & 0x07; /* Enable NMI */ outb(0x61, 0x08|x); outb(0x61, x); } /* * Minimal trap setup. Just enough so that we can panic * on traps (bugs) during kernel initialization. * Called very early - malloc is not yet available. */ void trapinit0(void) { int d1, v; ulong vaddr; Segdesc *idt; idt = (Segdesc*)IDTADDR; vaddr = (ulong)vectortable; for(v = 0; v < 256; v++){ d1 = (vaddr & 0xFFFF0000)|SEGP; switch(v){ case VectorBPT: d1 |= SEGPL(3)|SEGIG; break; case VectorSYSCALL: d1 |= SEGPL(3)|SEGIG; break; default: d1 |= SEGPL(0)|SEGIG; break; } idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16); idt[v].d1 = d1; vaddr += 6; } } void trapinit(void) { /* * Special traps. * Syscall() is called directly without going through trap(). */ trapenable(VectorBPT, debugbpt, 0, "debugpt"); trapenable(VectorPF, fault386, 0, "fault386"); trapenable(Vector2F, doublefault, 0, "doublefault"); trapenable(Vector15, unexpected, 0, "unexpected"); nmienable(); addarchfile("irqalloc", 0444, irqallocread, nil); trapinited = 1; } static char* excname[32] = { "divide error", "debug exception", "nonmaskable interrupt", "breakpoint", "overflow", "bounds check", "invalid opcode", "coprocessor not available", "double fault", "coprocessor segment overrun", "invalid TSS", "segment not present", "stack exception", "general protection violation", "page fault", "15 (reserved)", "coprocessor error", "alignment check", "machine check", "SIMD exception", "20 (reserved)", "21 (reserved)", "22 (reserved)", "23 (reserved)", "24 (reserved)", "25 (reserved)", "26 (reserved)", "27 (reserved)", "28 (reserved)", "29 (reserved)", "30 (reserved)", "31 (reserved)", }; /* * keep histogram of interrupt service times */ void intrtime(Mach*, int vno) { ulong diff; ulong x; x = perfticks(); diff = x - m->perf.intrts; m->perf.intrts = x; m->perf.inintr += diff; if(up == nil && m->perf.inidle > diff) m->perf.inidle -= diff; intrtimetot[vno] += diff; // diff /= m->cpumhz*100; /* quantum = 100µsec */ // if(diff >= Ntimevec) // diff = Ntimevec-1; // intrtimes[vno][diff]++; intrcountx[vno]++; } /* go to user space */ void kexit(Ureg*) { uvlong t; Tos *tos; /* precise time accounting, kernel exit */ tos = (Tos*)(USTKTOP-sizeof(Tos)); cycles(&t); tos->kcycles += t - up->kentry; tos->pcycles = up->pcycles; tos->pid = up->pid; } /* * 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, i, vno, user; char buf[ERRMAX]; Proc *uprock; Vctl *ctl, *v; Mach *mach; if(!trapinited){ /* fault386 can give a better error message */ if(ureg->trap == VectorPF) fault386(ureg, nil); panic("trap %lud: not ready", ureg->trap); } m->perf.intrts = perfticks(); user = (ureg->cs & 0xFFFF) == UESEL; if(user){ up->dbgreg = ureg; cycles(&up->kentry); } clockintr = 0; vno = ureg->trap; if(ctl = vctl[vno]){ uprock = nil; if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER){ clockintr = 1; m->intr++; }else if(ctl->isintr){ uprock = up; up = nil; m->intr++; if(vno >= VectorPIC && vno != VectorSYSCALL) m->lastintr = ctl->irq; } if(ctl->isr) ctl->isr(vno); for(v = ctl; v != nil; v = v->next){ if(v->f != nil) v->f(ureg, v->a); } if(ctl->eoi) ctl->eoi(vno); intrtime(m, vno); if(uprock != nil){ up = uprock; 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. */ /* call all interrupt routines, just in case */ for(i = VectorPIC; i <= MaxIrqLAPIC; i++){ ctl = vctl[i]; if(ctl == nil) continue; if(!ctl->isintr) continue; for(v = ctl; v != nil; v = v->next){ if(v->f) v->f(ureg, v->a); } /* should we do this? */ if(vno < VectorAPIC) if(ctl->eoi) ctl->eoi(i); } /* clear the interrupt */ if(vno >= VectorAPIC){ if(traplapiceoi != nil) traplapiceoi(0); }else i8259isr(vno); if(1)print("cpu%d: spurious interrupt %d, last %d\n", m->machno, vno, m->lastintr); if(0)if(conf.nmach > 1){ for(i = 0; i < 32; i++){ if(!(active.machs & (1<<i))) continue; mach = MACHP(i); if(m->machno == mach->machno) continue; print(" cpu%d: last %d", mach->machno, mach->lastintr); } print("\n"); } m->spuriousintr++; intrtime(m, vno); if(user) kexit(ureg); return; } else{ if(vno == VectorNMI){ /* * Don't re-enable, it confuses the crash dumps. nmienable(); */ iprint("cpu%d: NMI PC %#p\n", m->machno, ureg->pc); while(m->machno != 0) ; } dumpregs(ureg); if(!user){ ureg->sp = (ulong)&ureg->sp; _dumpstack(ureg); } if(vno < nelem(excname)) panic("%s", excname[vno]); panic("unknown trap/intr: %d", vno); } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ sched(); splhi(); } if(user){ if(up->procctl || up->nnote) notify(ureg); kexit(ureg); } } /* * dump registers */ void dumpregs2(Ureg* ureg) { if(up) iprint("cpu%d: registers for %s %lud\n", m->machno, up->text, up->pid); else iprint("cpu%d: registers for kernel\n", m->machno); iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", ureg->flags, ureg->trap, ureg->ecode, ureg->pc); iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", ureg->ax, ureg->bx, ureg->cx, ureg->dx); iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n", ureg->si, ureg->di, ureg->bp); iprint(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n", ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF, ureg->fs & 0xFFFF, ureg->gs & 0xFFFF); } void dumpregs(Ureg* ureg) { vlong mca, mct; dumpregs2(ureg); /* * Processor control registers.