X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2F9%2Fpc%2Ftrap.c;h=97931807faf37b02f75074b5021b976c610c007b;hb=e38f75fc45bba789ceea05d5e62f1d8662bf508b;hp=08033a9eedb8182693d4dc4f770eba4f9aaae53a;hpb=c6c2e04d4a700fe3982a4a72e768c69d6ace08a6;p=plan9front.git diff --git a/sys/src/9/pc/trap.c b/sys/src/9/pc/trap.c index 08033a9ee..97931807f 100644 --- a/sys/src/9/pc/trap.c +++ b/sys/src/9/pc/trap.c @@ -13,6 +13,7 @@ static int trapinited; void noted(Ureg*, ulong); +static void debugexc(Ureg*, void*); static void debugbpt(Ureg*, void*); static void fault386(Ureg*, void*); static void doublefault(Ureg*, void*); @@ -39,8 +40,22 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) irq, tbdf, name); return; } + if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0)){ + print("intrenable: got unassigned irq %d, tbdf 0x%uX for %s\n", + irq, tbdf, name); + irq = -1; + } + + /* + * IRQ2 doesn't really exist, it's used to gang the interrupt + * controllers together. A device set to IRQ2 will appear on + * the second interrupt controller as IRQ9. + */ + if(irq == 2) + irq = 9; - v = xalloc(sizeof(Vctl)); + if((v = xalloc(sizeof(Vctl))) == nil) + panic("intrenable: out of memory"); v->isintr = 1; v->irq = irq; v->tbdf = tbdf; @@ -69,75 +84,71 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) iunlock(&vctllock); } -int +void intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name) { Vctl **pv, *v; int vno; - /* - * For now, none of this will work with the APIC code, - * there is no mapping between irq and vector as the IRQ - * is pretty meaningless. - */ - if(arch->intrvecno == nil) - return -1; - vno = arch->intrvecno(irq); + if(irq == 2) + irq = 9; + if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){ + /* + * on APIC machine, irq is pretty meaningless + * and disabling a the vector is not implemented. + * however, we still want to remove the matching + * Vctl entry to prevent calling Vctl.f() with a + * stale Vctl.a pointer. + */ + irq = -1; + vno = VectorPIC; + } else { + vno = arch->intrvecno(irq); + } ilock(&vctllock); - pv = &vctl[vno]; - while (*pv && - ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a || - strcmp((*pv)->name, name))) - pv = &((*pv)->next); - assert(*pv); - - v = *pv; - *pv = (*pv)->next; /* Link out the entry */ - - if(vctl[vno] == nil && arch->intrdisable != nil) - arch->intrdisable(irq); + do { + for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){ + if(v->isintr && (v->irq == irq || irq == -1) + && v->tbdf == tbdf && v->f == f && v->a == a + && strcmp(v->name, name) == 0) + break; + } + if(v != nil){ + *pv = v->next; + xfree(v); + + if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil) + arch->intrdisable(irq); + break; + } + } while(irq == -1 && ++vno <= MaxVectorAPIC); iunlock(&vctllock); - xfree(v); - return 0; } static long -irqallocread(Chan*, void *vbuf, long n, vlong offset) +irqallocread(Chan*, void *a, long n, vlong offset) { - char *buf, *p, str[2*(11+1)+KNAMELEN+1+1]; - int m, vno; - long oldn; + char buf[2*(11+1)+KNAMELEN+1+1]; + int vno, m; Vctl *v; if(n < 0 || offset < 0) error(Ebadarg); - oldn = n; - buf = vbuf; for(vno=0; vnonext){ - m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, 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; - } + m = snprint(buf, sizeof(buf), "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name); + offset -= m; + if(offset >= 0) + continue; + if(n > -offset) + n = -offset; + offset += m; + memmove(a, buf+offset, n); + return n; } } - return oldn - n; + return 0; } void @@ -147,11 +158,12 @@ trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) if(vno < 0 || vno >= VectorPIC) panic("trapenable: vno %d", vno); - v = xalloc(sizeof(Vctl)); + if((v = xalloc(sizeof(Vctl))) == nil) + panic("trapenable: out of memory"); v->tbdf = BUSUNKNOWN; v->f = f; v->a = a; - strncpy(v->name, name, KNAMELEN); + strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; ilock(&vctllock); @@ -173,7 +185,7 @@ nmienable(void) outb(0x70, 0); x = inb(0x61) & 0x07; /* Enable NMI */ - outb(0x61, 0x08|x); + outb(0x61, 0x0C|x); outb(0x61, x); } @@ -220,6 +232,7 @@ trapinit(void) * Special traps. * Syscall() is called directly without going through trap(). */ + trapenable(VectorDE, debugexc, 0, "debugexc"); trapenable(VectorBPT, debugbpt, 0, "debugpt"); trapenable(VectorPF, fault386, 0, "fault386"); trapenable(Vector2F, doublefault, 0, "doublefault"); @@ -250,7 +263,7 @@ static char* excname[32] = { "coprocessor error", "alignment check", "machine check", - "19 (reserved)", + "simd error", "20 (reserved)", "21 (reserved)", "22 (reserved)", @@ -299,7 +312,7 @@ kexit(Ureg*) tos = (Tos*)(USTKTOP-sizeof(Tos)); cycles(&t); tos->kcycles += t - up->kentry; - tos->pcycles = up->pcycles; + tos->pcycles = t + up->pcycles; tos->pid = up->pid; } @@ -398,8 +411,8 @@ trap(Ureg* ureg) if(0)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<machno == mach->machno) @@ -420,49 +433,57 @@ trap(Ureg* ureg) * Don't re-enable, it confuses the crash dumps. nmienable(); */ - iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc); + iprint("cpu%d: nmi PC %#8.8lux, status %ux\n", + m->machno, ureg->pc, inb(0x61)); while(m->machno != 0) ; } - if(vno == VectorGPF || vno == VectorSNP){ - ulong *sp; - uchar *pc; + if(!user){ + void (*pc)(void); + ulong *sp; + + extern void _forkretpopgs(void); + extern void _forkretpopfs(void); + extern void _forkretpopes(void); + extern void _forkretpopds(void); + extern void _forkretiret(void); + extern void _rdmsrinst(void); + extern void _wrmsrinst(void); + extern void _peekinst(void); - /* l.s */ extern void load_fs(ulong); extern void load_gs(ulong); - /* - * CS, SS, DS and ES are initialized by strayintr - * in l.s. initialize the others too so we dont trap - * again when restoring the old context. - */ load_fs(NULLSEL); load_gs(NULLSEL); - pc = (uchar*)ureg->pc; - sp = (ulong*)&ureg->sp; - - /* - * we test for the instructions used by forkret() - * to load the segments. this needs to be changed - * if forkret changes! - */ - - /* POP */ - if((pc[0] == 0x0f && (pc[1] == 0xa9 /*GS*/ || - pc[1] == 0xa1 /*FS*/)) || (pc[0] == 0x07) /*ES*/ || - (pc[0] == 0x1f) /*DS*/){ - sp[0] = NULLSEL; - return; - } - - /* IRET */ - if(pc[0] == 0xcf){ - sp[1] = UESEL; /*CS*/ - sp[4] = UDSEL; /*SS*/ - return; + sp = (ulong*)&ureg->sp; /* kernel stack */ + pc = (void*)ureg->pc; + + if(pc == _forkretpopgs || pc == _forkretpopfs || + pc == _forkretpopes || pc == _forkretpopds){ + if(vno == VectorGPF || vno == VectorSNP){ + sp[0] = NULLSEL; + return; + } + } else if(pc == _forkretiret){ + if(vno == VectorGPF || vno == VectorSNP){ + sp[1] = UESEL; /* CS */ + sp[4] = UDSEL; /* SS */ + return; + } + } else if(pc == _rdmsrinst || pc == _wrmsrinst){ + if(vno == VectorGPF){ + ureg->bp = -1; + ureg->pc += 2; + return; + } + } else if(pc == _peekinst){ + if(vno == VectorGPF){ + ureg->pc += 2; + return; + } } } @@ -519,8 +540,6 @@ dumpregs2(Ureg* ureg) void dumpregs(Ureg* ureg) { - vlong mca, mct; - dumpregs2(ureg); /* @@ -532,13 +551,10 @@ dumpregs(Ureg* ureg) */ iprint(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux", getcr0(), getcr2(), getcr3()); - if(m->cpuiddx & 0x9A){ - iprint(" CR4 %8.8lux", getcr4()); - if((m->cpuiddx & 0xA0) == 0xA0){ - rdmsr(0x00, &mca); - rdmsr(0x01, &mct); - iprint("\n MCA %8.8llux MCT %8.8llux", mca, mct); - } + if(m->cpuiddx & (Mce|Tsc|Pse|Vmex)){ + iprint(" CR4 %8.8lux\n", getcr4()); + if(ureg->trap == 18) + dumpmcregs(); } iprint("\n ur %#p up %#p\n", ureg, up); } @@ -627,6 +643,40 @@ dumpstack(void) callwithureg(_dumpstack); } +static void +debugexc(Ureg *ureg, void *) +{ + u32int dr6, m; + char buf[ERRMAX]; + char *p, *e; + int i; + + dr6 = getdr6(); + if(up == nil) + panic("kernel debug exception dr6=%#.8ux", dr6); + putdr6(up->dr[6]); + if(userureg(ureg)) + qlock(&up->debug); + else if(!canqlock(&up->debug)) + return; + m = up->dr[7]; + m = (m >> 4 | m >> 3) & 8 | (m >> 3 | m >> 2) & 4 | (m >> 2 | m >> 1) & 2 | (m >> 1 | m) & 1; + m &= dr6; + if(m == 0){ + sprint(buf, "sys: debug exception dr6=%#.8ux", dr6); + postnote(up, 0, buf, NDebug); + }else{ + p = buf; + e = buf + sizeof(buf); + p = seprint(p, e, "sys: watchpoint "); + for(i = 0; i < 4; i++) + if((m & 1<> i + 1 != 0) ? "," : ""); + postnote(up, 0, buf, NDebug); + } + qunlock(&up->debug); +} + static void debugbpt(Ureg* ureg, void*) { @@ -668,6 +718,13 @@ fault386(Ureg* ureg, void*) if(!user){ if(vmapsync(addr)) return; + { + extern void _peekinst(void); + if((void(*)(void))ureg->pc == _peekinst){ + ureg->pc += 2; + return; + } + } if(addr >= USTKTOP) panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); if(up == nil) @@ -678,7 +735,7 @@ fault386(Ureg* ureg, void*) insyscall = up->insyscall; up->insyscall = 1; - n = fault(addr, read); + n = fault(addr, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); @@ -725,49 +782,33 @@ syscall(Ureg* ureg) scallnr = ureg->ax; up->scallnr = scallnr; - if(up->procctl == Proc_tracesyscall){ - /* - * Redundant validaddr. Do we care? - * Tracing syscalls is not exactly a fast path... - * Beware, validaddr currently does a pexit rather - * than an error if there's a problem; that might - * change in the future. - */ - if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) - validaddr(sp, sizeof(Sargs)+BY2WD, 0); - - syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD)); - up->procctl = Proc_stopme; - procctl(up); - if(up->syscalltrace) - free(up->syscalltrace); - up->syscalltrace = nil; - startns = todget(nil); - } - - if(scallnr == RFORK && up->fpstate == FPactive){ - fpsave(&up->fpsave); - up->fpstate = FPinactive; - } spllo(); up->nerrlab = 0; ret = -1; if(!waserror()){ + if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) + validaddr(sp, sizeof(Sargs)+BY2WD, 0); + + up->s = *((Sargs*)(sp+BY2WD)); + + if(up->procctl == Proc_tracesyscall){ + syscallfmt(scallnr, ureg->pc, (va_list)up->s.args); + s = splhi(); + up->procctl = Proc_stopme; + procctl(); + splx(s); + startns = todget(nil); + } + if(scallnr >= nsyscall || systab[scallnr] == 0){ pprint("bad sys call number %lud pc %lux\n", scallnr, ureg->pc); postnote(up, 1, "sys: bad sys call", NDebug); error(Ebadarg); } - - if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) - validaddr(sp, sizeof(Sargs)+BY2WD, 0); - - up->s = *((Sargs*)(sp+BY2WD)); up->psstate = sysctab[scallnr]; - - ret = systab[scallnr](up->s.args); + ret = systab[scallnr]((va_list)up->s.args); poperror(); }else{ /* failure: save the error buffer for errstr */ @@ -795,21 +836,18 @@ syscall(Ureg* ureg) if(up->procctl == Proc_tracesyscall){ stopns = todget(nil); - up->procctl = Proc_stopme; - sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns); + sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns); s = splhi(); - procctl(up); + up->procctl = Proc_stopme; + procctl(); splx(s); - if(up->syscalltrace) - free(up->syscalltrace); - up->syscalltrace = nil; } up->insyscall = 0; up->psstate = 0; if(scallnr == NOTED) - noted(ureg, *(ulong*)(sp+BY2WD)); + noted(ureg, *((ulong*)up->s.args)); if(scallnr!=RFORK && (up->procctl || up->nnote)){ splhi(); @@ -833,12 +871,12 @@ notify(Ureg* ureg) Note *n; if(up->procctl) - procctl(up); + procctl(); if(up->nnote == 0) return 0; if(up->fpstate == FPactive){ - fpsave(&up->fpsave); + fpsave(up->fpsave); up->fpstate = FPinactive; } up->fpstate |= FPillegal; @@ -855,9 +893,9 @@ notify(Ureg* ureg) } if(n->flag!=NUser && (up->notified || up->notify==0)){ + qunlock(&up->debug); if(n->flag == NDebug) pprint("suicide: %s\n", n->msg); - qunlock(&up->debug); pexit(n->msg, n->flag!=NDebug); } @@ -877,7 +915,7 @@ notify(Ureg* ureg) if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n", up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg); - if(!okaddr((ulong)up->notify, 1, 0) + if(!okaddr((uintptr)up->notify, 1, 0) || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){ qunlock(&up->debug); pprint("suicide: bad address in notify\n"); @@ -930,7 +968,7 @@ noted(Ureg* ureg, ulong arg0) /* sanity clause */ oureg = (ulong)nureg; - if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ + if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ qunlock(&up->debug); pprint("bad ureg in noted or call to noted when not notified\n"); pexit("Suicide", 0); @@ -973,29 +1011,23 @@ if(0) print("%s %lud: noted %.8lux %.8lux\n", break; default: - pprint("unknown noted arg 0x%lux\n", arg0); up->lastnote.flag = NDebug; /* fall through */ case NDFLT: - if(up->lastnote.flag == NDebug){ - qunlock(&up->debug); + qunlock(&up->debug); + if(up->lastnote.flag == NDebug) pprint("suicide: %s\n", up->lastnote.msg); - } else - qunlock(&up->debug); pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); } } -long -execregs(ulong entry, ulong ssize, ulong nargs) +uintptr +execregs(uintptr entry, ulong ssize, ulong nargs) { ulong *sp; Ureg *ureg; - up->fpstate = FPinit; - fpoff(); - sp = (ulong*)(USTKTOP - ssize); *--sp = nargs; @@ -1011,7 +1043,7 @@ execregs(ulong entry, ulong ssize, ulong nargs) /* * return the userpc the last exception happened at */ -ulong +uintptr userpc(void) { Ureg *ureg;