/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "ureg.h"#include "../port/error.h"#include "tos.h"#include <trace.h> static Lock vctllock;Vctl *vctl[256]; int intrstack[5];uvlong intrtime[5];vlong lastoffset;int inintr;int nintr[10];int nintro;int dblintr[64];ulong thisto[32];ulong thistoo;vlong vnot[64];ulong vnon[64]; voidintrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name){ int vno; Vctl *v; if(f == nil){ print("intrenable: nil handler for %d for %s\n", irq, name); return; } v = xalloc(sizeof(Vctl)); v->isintr = 1; v->irq = irq; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; ilock(&vctllock); vno = vectorenable(v); if(vno == -1){ iunlock(&vctllock); print("intrenable: couldn't enable irq %d for %s\n", irq, v->name); xfree(v); return; } v->next = vctl[vno]; vctl[vno] = v; iunlock(&vctllock);} voidintrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name){ Vctl **pv, *v; ilock(&vctllock); pv = &vctl[irq]; while (*pv && ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a || strcmp((*pv)->name, name))) pv = &((*pv)->next); if(*pv == nil){ print("intrdisable: irq %d not found\n", irq); iunlock(&vctllock); return; } v = *pv; *pv = (*pv)->next; /* Link out the entry */ if(vctl[irq] == nil) vectordisable(v); iunlock(&vctllock); xfree(v);} void syscall(Ureg*);void noted(Ureg*, ulong);static void _dumpstack(Ureg*); char *excname[] ={ "reserved 0", "system reset", "machine check", "data access", "instruction access", "external interrupt", "alignment", "program exception", "floating-point unavailable", "decrementer", "reserved A", "reserved B", "system call", "trace trap", "floating point assist", "reserved F", "reserved 10", "data load translation miss", "data store translation miss", "instruction address breakpoint", "system management interrupt",}; char *fpcause[] ={ "inexact operation", "division by zero", "underflow", "overflow", "invalid operation",};char *fpexcname(Ureg*, ulong, char*);#define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */ char *regname[]={ "CAUSE", "SRR1", "PC", "GOK", "LR", "CR", "XER", "CTR", "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31", "DCMP", "ICMP", "DMISS", "IMISS", "HASH1", "HASH2", "DAR", "DSISR",}; 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;} voidtrap(Ureg *ureg){ int ecode, user; char buf[ERRMAX], *s; extern FPsave initfp; ecode = (ureg->cause >> 8) & 0xff; user = (ureg->srr1 & MSR_PR) != 0; if(user){ cycles(&up->kentry); up->dbgreg = ureg; } if(ureg->status & MSR_RI == 0) print("double fault?: ecode = %d\n", ecode); switch(ecode) { case CEI: m->intr++; intr(ureg); break; case CDEC: clockintr(ureg); break; case CDSI: m->pfault++; if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0); break; case CISI: m->pfault++; if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->pc, 1); break; case CIMISS: /* instruction miss */ if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->imiss, 1); break; case CLMISS: /* data load miss */ if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->dmiss, 1); break; case CSMISS: /* data store miss */ if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->dmiss, 0); break; case CSYSCALL: if(!user) panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1); syscall(ureg); if (up->delaysched){ sched(); splhi(); } kexit(ureg); return; /* syscall() calls notify itself, don't do it again */ case CFPU: if(!user || up == nil) { dumpregs(ureg); panic("floating point in kernel"); } switch(up->fpstate){ case FPinit: fprestore(&initfp); up->fpstate = FPactive; break; case FPinactive: fprestore(&up->fpsave); up->fpstate = FPactive; break; case FPactive: print("up->fpstate %d\n", up->fpstate); delay(100); dumpregs(ureg); delay(200); panic("fpstate"); break; default: if(user){ spllo(); sprint(buf, "sys: floating point in note handler:"); postnote(up, 1, buf, NDebug); break; } panic("kernel fpstate illegal"); } ureg->srr1 |= MSR_FP; break; case CPROG: if(ureg->status & (1<<19)) s = "floating point exception"; else if(ureg->status & (1<<18)) s = "illegal instruction"; else if(ureg->status & (1<<17)) s = "privileged instruction"; else s = "undefined program exception"; if(user){ spllo(); sprint(buf, "sys: trap: %s", s); postnote(up, 1, buf, NDebug); break; } dumpregs(ureg); panic(s); break; default: if(ecode < nelem(excname) && user){ spllo(); sprint(buf, "sys: trap: %s", excname[ecode]); postnote(up, 1, buf, NDebug); break; } dumpregs(ureg); if(ecode < nelem(excname)) panic("%s", excname[ecode]); panic("unknown trap/intr: %d\n", ecode); } /* restoreureg must execute at high IPL */ splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && ecode == CDEC){ sched(); splhi(); } if(user) { if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){ postnote(up, 1, buf, NDebug); } notify(ureg); if(up->fpstate != FPactive) ureg->srr1 &= ~MSR_FP; kexit(ureg); }} voidfaultpower(Ureg *ureg, ulong addr, int read){ int user, insyscall, n; char buf[ERRMAX]; user = (ureg->srr1 & MSR_PR) != 0; insyscall = up->insyscall; up->insyscall = 1; n = fault(addr, read); if(n < 0){ if(!user){ dumpregs(ureg); panic("fault: 0x%lux", addr); } sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr); postnote(up, 1, buf, NDebug); } up->insyscall = insyscall;} voidsethvec(int v, void (*r)(void)){ ulong *vp, pa, o; vp = KADDR(v); vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ pa = PADDR(r); o = pa >> 25; if(o != 0 && o != 0x7F){ /* a branch too far */ vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ vp[5] = 0x7c0803a6; /* MOVW R0, LR */ vp[6] = 0x4e800021; /* BL (LR) */ }else vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */} voidsetmvec(int v, void (*r)(void), void (*t)(void)){ ulong *vp, pa, o, n; vp = KADDR(v); n = 0; vp[n++] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ vp[n++] = 0x7c0802a6; /* MOVW LR, R0 */ vp[n++] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ pa = PADDR(r); o = pa >> 25; if(o != 0 && o != 0x7F){ /* a branch too far */ vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ vp[n++] = 0x7c0803a6; /* MOVW R0, LR */ vp[n++] = 0x4e800021; /* BL (LR) */ }else vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ pa = PADDR(t); o = pa >> 25; if(o != 0 && o != 0x7F){ /* a branch too far */ vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ vp[n++] = 0x7c0803a6; /* MOVW R0, LR */ vp[n] = 0x4e800021; /* BL (LR) */ }else vp[n] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */} voidintr(Ureg *ureg){ int vno, pvno, i; Vctl *ctl, *v; void (*pt)(Proc*, int, vlong); uvlong tt, x; cycles(&tt); pt = proctrace; pvno = -1; for(i = 0; i < 64; i++){ vno = intvec(); if(vno == 0) break; cycles(&x); vnot[vno] -= x; if(vno == pvno) dblintr[vno]++; pvno = vno; if(pt && up && up->trace) pt(up, (vno << 16) | SInts, 0); if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) { iprint("spurious intr %d\n", vno); return; } for(v = ctl; v != nil; v = v->next) if(v->f) v->f(ureg, v->a); intend(vno); /* reenable the interrupt */ if(pt && up && up->trace) pt(up, (vno << 16) | SInte, 0); cycles(&x); vnot[vno] += x; vnon[vno]++; } if(i < nelem(nintr)) nintr[i]++; else nintro++; cycles(&x); tt = x - tt; i = tt / 3600; /* 100 microseconds units */ if(i < nelem(thisto)) thisto[i]++; else thistoo++; if(up) preempted();} char*fpexcname(Ureg *ur, ulong fpscr, char *buf){ int i; char *s; ulong fppc; fppc = ur->pc; s = 0; fpscr >>= 3; /* trap enable bits */ fpscr &= (fpscr>>22); /* anded with exceptions */ for(i=0; i<5; i++) if(fpscr & (1<<i)) s = fpcause[i]; if(s == 0) return "no floating point exception"; sprint(buf, "%s fppc=0x%lux", s, fppc); return buf;} /* * Fill in enough of Ureg to get a stack trace, and call a function. * Used by debugging interface rdb. */ static voidgetpcsp(ulong *pc, ulong *sp){ *pc = getcallerpc(&pc); *sp = (ulong)&pc-4;}Lines 1–500 of 935. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "ureg.h" #include "../port/error.h" #include "tos.h" #include <trace.h> static Lock vctllock; Vctl *vctl[256]; int intrstack[5]; uvlong intrtime[5]; vlong lastoffset; int inintr; int nintr[10]; int nintro; int dblintr[64]; ulong thisto[32]; ulong thistoo; vlong vnot[64]; ulong vnon[64]; void intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name) { int vno; Vctl *v; if(f == nil){ print("intrenable: nil handler for %d for %s\n", irq, name); return; } v = xalloc(sizeof(Vctl)); v->isintr = 1; v->irq = irq; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; ilock(&vctllock); vno = vectorenable(v); if(vno == -1){ iunlock(&vctllock); print("intrenable: couldn't enable irq %d for %s\n", irq, v->name); xfree(v); return; } v->next = vctl[vno]; vctl[vno] = v; iunlock(&vctllock); } void intrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name) { Vctl **pv, *v; ilock(&vctllock); pv = &vctl[irq]; while (*pv && ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a || strcmp((*pv)->name, name))) pv = &((*pv)->next); if(*pv == nil){ print("intrdisable: irq %d not found\n", irq); iunlock(&vctllock); return; } v = *pv; *pv = (*pv)->next; /* Link out the entry */ if(vctl[irq] == nil) vectordisable(v); iunlock(&vctllock); xfree(v); } void syscall(Ureg*); void noted(Ureg*, ulong); static void _dumpstack(Ureg*); char *excname[] = { "reserved 0", "system reset", "machine check", "data access", "instruction access", "external interrupt", "alignment", "program exception", "floating-point unavailable", "decrementer", "reserved A", "reserved B", "system call", "trace trap", "floating point assist", "reserved F", "reserved 10", "data load translation miss", "data store translation miss", "instruction address breakpoint", "system management interrupt", }; char *fpcause[] = { "inexact operation", "division by zero", "underflow", "overflow", "invalid operation", }; char *fpexcname(Ureg*, ulong, char*); #define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */ char *regname[]={ "CAUSE", "SRR1", "PC", "GOK", "LR", "CR", "XER", "CTR", "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31", "DCMP", "ICMP", "DMISS", "IMISS", "HASH1", "HASH2", "DAR", "DSISR", }; 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; } void trap(Ureg *ureg) { int ecode, user; char buf[ERRMAX], *s; extern FPsave initfp; ecode = (ureg->cause >> 8) & 0xff; user = (ureg->srr1 & MSR_PR) != 0; if(user){ cycles(&up->kentry); up->dbgreg = ureg; } if(ureg->status & MSR_RI == 0) print("double fault?: ecode = %d\n", ecode); switch(ecode) { case CEI: m->intr++; intr(ureg); break; case CDEC: clockintr(ureg); break; case CDSI: m->pfault++; if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0); break; case CISI: m->pfault++; if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->pc, 1); break; case CIMISS: /* instruction miss */ if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->imiss, 1); break; case CLMISS: /* data load miss */ if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->dmiss, 1); break; case CSMISS: /* data store miss */ if (up == nil){ dumpregs(ureg); panic("kernel fault"); } up->mmureg = ureg; faultpower(ureg, ureg->dmiss, 0); break; case CSYSCALL: if(!user) panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1); syscall(ureg); if (up->delaysched){ sched(); splhi(); } kexit(ureg); return; /* syscall() calls notify itself, don't do it again */ case CFPU: if(!user || up == nil) { dumpregs(ureg); panic("floating point in kernel"); } switch(up->fpstate){ case FPinit: fprestore(&initfp); up->fpstate = FPactive; break; case FPinactive: fprestore(&up->fpsave); up->fpstate = FPactive; break; case FPactive: print("up->fpstate %d\n", up->fpstate); delay(100); dumpregs(ureg); delay(200); panic("fpstate"); break; default: if(user){ spllo(); sprint(buf, "sys: floating point in note handler:"); postnote(up, 1, buf, NDebug); break; } panic("kernel fpstate illegal"); } ureg->srr1 |= MSR_FP; break; case CPROG: if(ureg->status & (1<<19)) s = "floating point exception"; else if(ureg->status & (1<<18)) s = "illegal instruction"; else if(ureg->status & (1<<17)) s = "privileged instruction"; else s = "undefined program exception"; if(user){ spllo(); sprint(buf, "sys: trap: %s", s); postnote(up, 1, buf, NDebug); break; } dumpregs(ureg); panic(s); break; default: if(ecode < nelem(excname) && user){ spllo(); sprint(buf, "sys: trap: %s", excname[ecode]); postnote(up, 1, buf, NDebug); break; } dumpregs(ureg); if(ecode < nelem(excname)) panic("%s", excname[ecode]); panic("unknown trap/intr: %d\n", ecode); } /* restoreureg must execute at high IPL */ splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && ecode == CDEC){ sched(); splhi(); } if(user) { if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){ postnote(up, 1, buf, NDebug); } notify(ureg); if(up->fpstate != FPactive) ureg->srr1 &= ~MSR_FP; kexit(ureg); } } void faultpower(Ureg *ureg, ulong addr, int read) { int user, insyscall, n; char buf[ERRMAX]; user = (ureg->srr1 & MSR_PR) != 0; insyscall = up->insyscall; up->insyscall = 1; n = fault(addr, read); if(n < 0){ if(!user){ dumpregs(ureg); panic("fault: 0x%lux", addr); } sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr); postnote(up, 1, buf, NDebug); } up->insyscall = insyscall; } void sethvec(int v, void (*r)(void)) { ulong *vp, pa, o; vp = KADDR(v); vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ pa = PADDR(r); o = pa >> 25; if(o != 0 && o != 0x7F){ /* a branch too far */ vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ vp[5] = 0x7c0803a6; /* MOVW R0, LR */ vp[6] = 0x4e800021; /* BL (LR) */ }else vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ } void setmvec(int v, void (*r)(void), void (*t)(void)) { ulong *vp, pa, o, n; vp = KADDR(v); n = 0; vp[n++] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ vp[n++] = 0x7c0802a6; /* MOVW LR, R0 */ vp[n++] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ pa = PADDR(r); o = pa >> 25; if(o != 0 && o != 0x7F){ /* a branch too far */ vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ vp[n++] = 0x7c0803a6; /* MOVW R0, LR */ vp[n++] = 0x4e800021; /* BL (LR) */ }else vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ pa = PADDR(t); o = pa >> 25; if(o != 0 && o != 0x7F){ /* a branch too far */ vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ vp[n++] = 0x7c0803a6; /* MOVW R0, LR */ vp[n] = 0x4e800021; /* BL (LR) */ }else vp[n] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ } void intr(Ureg *ureg) { int vno, pvno, i; Vctl *ctl, *v; void (*pt)(Proc*, int, vlong); uvlong tt, x; cycles(&tt); pt = proctrace; pvno = -1; for(i = 0; i < 64; i++){ vno = intvec(); if(vno == 0) break; cycles(&x); vnot[vno] -= x; if(vno == pvno) dblintr[vno]++; pvno = vno; if(pt && up && up->trace) pt(up, (vno << 16) | SInts, 0); if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) { iprint("spurious intr %d\n", vno); return; } for(v = ctl; v != nil; v = v->next) if(v->f) v->f(ureg, v->a); intend(vno); /* reenable the interrupt */ if(pt && up && up->trace) pt(up, (vno << 16) | SInte, 0); cycles(&x); vnot[vno] += x; vnon[vno]++; } if(i < nelem(nintr)) nintr[i]++; else nintro++; cycles(&x); tt = x - tt; i = tt / 3600; /* 100 microseconds units */ if(i < nelem(thisto)) thisto[i]++; else thistoo++; if(up) preempted(); } char* fpexcname(Ureg *ur, ulong fpscr, char *buf) { int i; char *s; ulong fppc; fppc = ur->pc; s = 0; fpscr >>= 3; /* trap enable bits */ fpscr &= (fpscr>>22); /* anded with exceptions */ for(i=0; i<5; i++) if(fpscr & (1<<i)) s = fpcause[i]; if(s == 0) return "no floating point exception"; sprint(buf, "%s fppc=0x%lux", s, fppc); return buf; } /* * Fill in enough of Ureg to get a stack trace, and call a function. * Used by debugging interface rdb. */ static void getpcsp(ulong *pc, ulong *sp) { *pc = getcallerpc(&pc); *sp = (ulong)&pc-4; }