/* * 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. */ /* * traps, exceptions, faults and interrupts on ar7161 */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "ureg.h"#include "io.h"#include <tos.h>#include "../port/error.h" #define setstatus(v) /* experiment: delete this to enable recursive traps */ typedef struct Handler Handler; struct Handler { void (*handler)(void *); void *arg; Handler *next; /* at this interrupt level */ ulong intrs;}; ulong offintrs;ulong intrcauses[ILmax+1]; int intr(Ureg*);void kernfault(Ureg*, int);void noted(Ureg*, Ureg**, ulong);void rfnote(Ureg**); char *excname[] ={ "trap: external interrupt", "trap: TLB modification (store to unwritable)", "trap: TLB miss (load or fetch)", "trap: TLB miss (store)", "trap: address error (load or fetch)", "trap: address error (store)", "trap: bus error (fetch)", "trap: bus error (data load or store)", "trap: system call", "breakpoint", "trap: reserved instruction", "trap: coprocessor unusable", "trap: arithmetic overflow", "trap: TRAP exception", "trap: VCE (instruction)", "trap: floating-point exception", "trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */ "trap: corextend unusable", "trap: precise coprocessor 2 exception", "trap: TLB read-inhibit", "trap: TLB execute-inhibit", "trap: undefined 21", "trap: undefined 22", "trap: WATCH exception", "trap: machine checkcore", "trap: undefined 25", "trap: undefined 26", "trap: undefined 27", "trap: undefined 28", "trap: undefined 29", "trap: cache error", "trap: VCE (data)",}; char *fpcause[] ={ "inexact operation", "underflow", "overflow", "division by zero", "invalid operation",};char *fpexcname(Ureg*, ulong, char*, uint);#define FPEXPMASK (0x3f<<12) /* Floating exception bits in fcr31 */ struct { char *name; uint off;} regname[] = { "STATUS", Ureg_status, "PC", Ureg_pc, "SP", Ureg_sp, "CAUSE",Ureg_cause, "BADADDR", Ureg_badvaddr, "TLBVIRT", Ureg_tlbvirt, "HI", Ureg_hi, "LO", Ureg_lo, "R31", Ureg_r31, "R30", Ureg_r30, "R28", Ureg_r28, "R27", Ureg_r27, "R26", Ureg_r26, "R25", Ureg_r25, "R24", Ureg_r24, "R23", Ureg_r23, "R22", Ureg_r22, "R21", Ureg_r21, "R20", Ureg_r20, "R19", Ureg_r19, "R18", Ureg_r18, "R17", Ureg_r17, "R16", Ureg_r16, "R15", Ureg_r15, "R14", Ureg_r14, "R13", Ureg_r13, "R12", Ureg_r12, "R11", Ureg_r11, "R10", Ureg_r10, "R9", Ureg_r9, "R8", Ureg_r8, "R7", Ureg_r7, "R6", Ureg_r6, "R5", Ureg_r5, "R4", Ureg_r4, "R3", Ureg_r3, "R2", Ureg_r2, "R1", Ureg_r1,}; static Lock intrlock;static Handler handlers[ILmax+1]; static char *ptlb(ulong phys){ static char buf[4][32]; static int k; char *p; k = (k+1)&3; p = buf[k]; p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ", (phys<<6) & ~(BY2PG-1), (phys>>3)&7); if(phys & 4) *p++ = 'd'; if(phys & 2) *p++ = 'v'; if(phys & 1) *p++ = 'g'; *p++ = ')'; *p = 0; return buf[k];} static voidkpteprint(Ureg *ur){ ulong i, tlbstuff[3]; KMap *k; i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt()); print("tlbvirt=%#lux\n", i); i = gettlbp(i, tlbstuff); print("i=%lud v=%#lux p0=%s p1=%s\n", i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2])); i = (ur->badvaddr & ~KMAPADDR)>>15; if(i > KPTESIZE){ print("kpte index = %lud ?\n", i); return; } k = &kpte[i]; print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n", i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg); print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va);} voidkvce(Ureg *ur, int ecode){ char c; Pte **p; Page **pg; Segment *s; ulong addr, soff; c = 'D'; if(ecode == CVCEI) c = 'I'; print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr); if((ur->badvaddr & KSEGM) == KSEG3) { kpteprint(ur); return; } if(up && !(ur->badvaddr & KSEGM)) { addr = ur->badvaddr; s = seg(up, addr, 0); if(s == 0){ print("kvce: no seg for %#lux\n", addr); for(;;) ; } addr &= ~(BY2PG-1); soff = addr - s->base; p = &s->map[soff/PTEMAPMEM]; if(*p){ pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG]; if(*pg) print("kvce: pa=%#lux, va=%#lux\n", (*pg)->pa, (*pg)->va); else print("kvce: no *pg\n"); }else print("kvce: no *p\n"); }} /* prepare to go to user space */voidkexit(Ureg*){ Tos *tos; /* precise time accounting, kernel exit */ tos = (Tos*)(USTKTOP-sizeof(Tos)); tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry; tos->pcycles = up->pcycles; tos->pid = up->pid;} voidtrap(Ureg *ur){ int ecode, clockintr, user, cop, x, fpchk; ulong fpfcr31; char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep; static int dumps; ecode = (ur->cause>>2)&EXCMASK; user = ur->status&KUSER; if (ur->cause & TS) panic("trap: tlb shutdown"); fpchk = 0; if(user){ up->dbgreg = ur; cycles(&up->kentry); /* no fpu, so no fp state to save */ } if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) { iprint("trap: proc %ld kernel stack getting full\n", up->pid); dumpregs(ur); dumpstack(); } if (up == nil && (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) { iprint("trap: cpu%d kernel stack getting full\n", m->machno); dumpregs(ur); dumpstack(); } // splhi(); /* for the experiment: make it explicit */ /* clear EXL in status */ setstatus(getstatus() & ~EXL); clockintr = 0; switch(ecode){ case CINT: clockintr = intr(ur); break; case CFPE: panic("FP exception but no FPU");#ifdef OLD_MIPS_EXAMPLE fptrap(ur); clrfpintr(); fpchk = 1;#endif break; case CTLBM: case CTLBL: case CTLBS: /* user tlb entries assumed not overwritten during startup */ if(up == 0) kernfault(ur, ecode); if(!user && (ur->badvaddr & KSEGM) == KSEG3) { kfault(ur); break; } x = up->insyscall; up->insyscall = 1; spllo(); faultmips(ur, user, ecode); up->insyscall = x; break; case CVCEI: case CVCED: kvce(ur, ecode); goto Default; case CWATCH: if(!user) panic("watchpoint trap from kernel mode pc=%#p", ur->pc); fpwatch(ur); break; case CCPU: cop = (ur->cause>>28)&3; if(user && up && cop == 1) { if(up->fpstate & FPillegal) { /* someone used floating point in a note handler */ postnote(up, 1, "sys: floating point in note handler", NDebug); break; } /* no fpu, so we can only emulate fp ins'ns */ if (fpuemu(ur) < 0) postnote(up, 1, "sys: fp instruction not emulated", NDebug); else fpchk = 1; break; } /* Fallthrough */ Default: default: if(user) { spllo(); snprint(buf, sizeof buf, "sys: %s", excname[ecode]); postnote(up, 1, buf, NDebug); break; } if (ecode == CADREL || ecode == CADRES) iprint("kernel addr exception for va %#p pid %#ld %s\n", ur->badvaddr, (up? up->pid: 0), (up? up->text: "")); print("cpu%d: kernel %s pc=%#lux\n", m->machno, excname[ecode], ur->pc); dumpregs(ur); dumpstack(); if(m->machno == 0) spllo(); exit(1); } if(fpchk) { fpfcr31 = up->fpsave.fpstatus; if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) { spllo(); fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1); snprint(buf, sizeof buf, "sys: fp: %s", fpexcep); postnote(up, 1, buf, NDebug); } } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ sched(); splhi(); } if(user){ notify(ur); /* no fpu, so no fp state to restore */ kexit(ur); } /* restore EXL in status */ setstatus(getstatus() | EXL);} /* periodically zero all the interrupt counts */static voidresetcounts(void){ int i; Handler *hp; ilock(&intrlock); for (i = 0; i < nelem(handlers); i++) for (hp = &handlers[i]; hp != nil; hp = hp->next) hp->intrs = 0; iunlock(&intrlock);} /* * set handlers */voidintrenable(int irq, void (*h)(void *), void *arg){ Handler *hp; static int resetclock; if (h == nil) panic("intrenable: nil handler intr %d", irq); if(irq < ILmin || irq >= nelem(handlers)) panic("intrenable: bad handler intr %d %#p", irq, h); hp = &handlers[irq]; ilock(&intrlock); if (hp->handler != nil) { /* occupied? */ /* add a new one at the end of the chain */ for (; hp->next != nil; hp = hp->next) ; hp->next = smalloc(sizeof *hp); hp = hp->next; hp->next = nil; } hp->handler = h; hp->arg = arg; iunlock(&intrlock); if (irq == ILduart0) { /* special apb sub-interrupt */ *Apbintrsts = 0; *Apbintrmask = 1 << Apbintruart; /* enable, actually */ coherence(); } intron(1 << (ILshift + irq)); if (!resetclock) { resetclock = 1; addclock0link(resetcounts, 100); }} voidintrshutdown(void){ introff(INTMASK);} static voidjabberoff(Ureg *ur, int irq, ulong bit){ introff(bit); /* interrupt off now ... */ if (ur) ur->status &= ~bit; /* ... and upon return */ offintrs |= bit; iprint("irq %d jabbering; shutting it down\n", irq);} ulongpollall(Ureg *ur, ulong cause) /* must be called splhi */{ int i, intrs, sts; ulong bit; Handler *hp; /* exclude clock and sw intrs */ intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus(); if(intrs == 0) return cause; ilock(&intrlock); for (i = ILmax; i >= ILmin; i--) { bit = 1 << (ILshift + i); if (!(intrs & bit)) continue; intrcauses[i]++; for (hp = &handlers[i]; hp != nil; hp = hp->next) if (hp->handler) { if (i == ILduart0) { sts = *Apbintrsts; if((sts & (1 << Apbintruart)) == 0) continue; /* don't need to ack apb sub-intr */ // *Apbintrsts &= ~(1 << Apbintruart); } (*hp->handler)(hp->arg); splhi(); if (++hp->intrs > 25000) { jabberoff(ur, i, bit); intrs &= ~bit; hp->intrs = 0; } } else if (ur) iprint("no handler for interrupt %d\n", i); cause &= ~bit; } iunlock(&intrlock); return cause;} intintr(Ureg *ur){ int clockintr;Lines 1–500 of 1084. 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. */ /* * traps, exceptions, faults and interrupts on ar7161 */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "ureg.h" #include "io.h" #include <tos.h> #include "../port/error.h" #define setstatus(v) /* experiment: delete this to enable recursive traps */ typedef struct Handler Handler; struct Handler { void (*handler)(void *); void *arg; Handler *next; /* at this interrupt level */ ulong intrs; }; ulong offintrs; ulong intrcauses[ILmax+1]; int intr(Ureg*); void kernfault(Ureg*, int); void noted(Ureg*, Ureg**, ulong); void rfnote(Ureg**); char *excname[] = { "trap: external interrupt", "trap: TLB modification (store to unwritable)", "trap: TLB miss (load or fetch)", "trap: TLB miss (store)", "trap: address error (load or fetch)", "trap: address error (store)", "trap: bus error (fetch)", "trap: bus error (data load or store)", "trap: system call", "breakpoint", "trap: reserved instruction", "trap: coprocessor unusable", "trap: arithmetic overflow", "trap: TRAP exception", "trap: VCE (instruction)", "trap: floating-point exception", "trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */ "trap: corextend unusable", "trap: precise coprocessor 2 exception", "trap: TLB read-inhibit", "trap: TLB execute-inhibit", "trap: undefined 21", "trap: undefined 22", "trap: WATCH exception", "trap: machine checkcore", "trap: undefined 25", "trap: undefined 26", "trap: undefined 27", "trap: undefined 28", "trap: undefined 29", "trap: cache error", "trap: VCE (data)", }; char *fpcause[] = { "inexact operation", "underflow", "overflow", "division by zero", "invalid operation", }; char *fpexcname(Ureg*, ulong, char*, uint); #define FPEXPMASK (0x3f<<12) /* Floating exception bits in fcr31 */ struct { char *name; uint off; } regname[] = { "STATUS", Ureg_status, "PC", Ureg_pc, "SP", Ureg_sp, "CAUSE",Ureg_cause, "BADADDR", Ureg_badvaddr, "TLBVIRT", Ureg_tlbvirt, "HI", Ureg_hi, "LO", Ureg_lo, "R31", Ureg_r31, "R30", Ureg_r30, "R28", Ureg_r28, "R27", Ureg_r27, "R26", Ureg_r26, "R25", Ureg_r25, "R24", Ureg_r24, "R23", Ureg_r23, "R22", Ureg_r22, "R21", Ureg_r21, "R20", Ureg_r20, "R19", Ureg_r19, "R18", Ureg_r18, "R17", Ureg_r17, "R16", Ureg_r16, "R15", Ureg_r15, "R14", Ureg_r14, "R13", Ureg_r13, "R12", Ureg_r12, "R11", Ureg_r11, "R10", Ureg_r10, "R9", Ureg_r9, "R8", Ureg_r8, "R7", Ureg_r7, "R6", Ureg_r6, "R5", Ureg_r5, "R4", Ureg_r4, "R3", Ureg_r3, "R2", Ureg_r2, "R1", Ureg_r1, }; static Lock intrlock; static Handler handlers[ILmax+1]; static char * ptlb(ulong phys) { static char buf[4][32]; static int k; char *p; k = (k+1)&3; p = buf[k]; p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ", (phys<<6) & ~(BY2PG-1), (phys>>3)&7); if(phys & 4) *p++ = 'd'; if(phys & 2) *p++ = 'v'; if(phys & 1) *p++ = 'g'; *p++ = ')'; *p = 0; return buf[k]; } static void kpteprint(Ureg *ur) { ulong i, tlbstuff[3]; KMap *k; i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt()); print("tlbvirt=%#lux\n", i); i = gettlbp(i, tlbstuff); print("i=%lud v=%#lux p0=%s p1=%s\n", i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2])); i = (ur->badvaddr & ~KMAPADDR)>>15; if(i > KPTESIZE){ print("kpte index = %lud ?\n", i); return; } k = &kpte[i]; print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n", i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg); print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va); } void kvce(Ureg *ur, int ecode) { char c; Pte **p; Page **pg; Segment *s; ulong addr, soff; c = 'D'; if(ecode == CVCEI) c = 'I'; print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr); if((ur->badvaddr & KSEGM) == KSEG3) { kpteprint(ur); return; } if(up && !(ur->badvaddr & KSEGM)) { addr = ur->badvaddr; s = seg(up, addr, 0); if(s == 0){ print("kvce: no seg for %#lux\n", addr); for(;;) ; } addr &= ~(BY2PG-1); soff = addr - s->base; p = &s->map[soff/PTEMAPMEM]; if(*p){ pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG]; if(*pg) print("kvce: pa=%#lux, va=%#lux\n", (*pg)->pa, (*pg)->va); else print("kvce: no *pg\n"); }else print("kvce: no *p\n"); } } /* prepare to go to user space */ void kexit(Ureg*) { Tos *tos; /* precise time accounting, kernel exit */ tos = (Tos*)(USTKTOP-sizeof(Tos)); tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry; tos->pcycles = up->pcycles; tos->pid = up->pid; } void trap(Ureg *ur) { int ecode, clockintr, user, cop, x, fpchk; ulong fpfcr31; char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep; static int dumps; ecode = (ur->cause>>2)&EXCMASK; user = ur->status&KUSER; if (ur->cause & TS) panic("trap: tlb shutdown"); fpchk = 0; if(user){ up->dbgreg = ur; cycles(&up->kentry); /* no fpu, so no fp state to save */ } if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) { iprint("trap: proc %ld kernel stack getting full\n", up->pid); dumpregs(ur); dumpstack(); } if (up == nil && (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) { iprint("trap: cpu%d kernel stack getting full\n", m->machno); dumpregs(ur); dumpstack(); } // splhi(); /* for the experiment: make it explicit */ /* clear EXL in status */ setstatus(getstatus() & ~EXL); clockintr = 0; switch(ecode){ case CINT: clockintr = intr(ur); break; case CFPE: panic("FP exception but no FPU"); #ifdef OLD_MIPS_EXAMPLE fptrap(ur); clrfpintr(); fpchk = 1; #endif break; case CTLBM: case CTLBL: case CTLBS: /* user tlb entries assumed not overwritten during startup */ if(up == 0) kernfault(ur, ecode); if(!user && (ur->badvaddr & KSEGM) == KSEG3) { kfault(ur); break; } x = up->insyscall; up->insyscall = 1; spllo(); faultmips(ur, user, ecode); up->insyscall = x; break; case CVCEI: case CVCED: kvce(ur, ecode); goto Default; case CWATCH: if(!user) panic("watchpoint trap from kernel mode pc=%#p", ur->pc); fpwatch(ur); break; case CCPU: cop = (ur->cause>>28)&3; if(user && up && cop == 1) { if(up->fpstate & FPillegal) { /* someone used floating point in a note handler */ postnote(up, 1, "sys: floating point in note handler", NDebug); break; } /* no fpu, so we can only emulate fp ins'ns */ if (fpuemu(ur) < 0) postnote(up, 1, "sys: fp instruction not emulated", NDebug); else fpchk = 1; break; } /* Fallthrough */ Default: default: if(user) { spllo(); snprint(buf, sizeof buf, "sys: %s", excname[ecode]); postnote(up, 1, buf, NDebug); break; } if (ecode == CADREL || ecode == CADRES) iprint("kernel addr exception for va %#p pid %#ld %s\n", ur->badvaddr, (up? up->pid: 0), (up? up->text: "")); print("cpu%d: kernel %s pc=%#lux\n", m->machno, excname[ecode], ur->pc); dumpregs(ur); dumpstack(); if(m->machno == 0) spllo(); exit(1); } if(fpchk) { fpfcr31 = up->fpsave.fpstatus; if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) { spllo(); fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1); snprint(buf, sizeof buf, "sys: fp: %s", fpexcep); postnote(up, 1, buf, NDebug); } } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ sched(); splhi(); } if(user){ notify(ur); /* no fpu, so no fp state to restore */ kexit(ur); } /* restore EXL in status */ setstatus(getstatus() | EXL); } /* periodically zero all the interrupt counts */ static void resetcounts(void) { int i; Handler *hp; ilock(&intrlock); for (i = 0; i < nelem(handlers); i++) for (hp = &handlers[i]; hp != nil; hp = hp->next) hp->intrs = 0; iunlock(&intrlock); } /* * set handlers */ void intrenable(int irq, void (*h)(void *), void *arg) { Handler *hp; static int resetclock; if (h == nil) panic("intrenable: nil handler intr %d", irq); if(irq < ILmin || irq >= nelem(handlers)) panic("intrenable: bad handler intr %d %#p", irq, h); hp = &handlers[irq]; ilock(&intrlock); if (hp->handler != nil) { /* occupied? */ /* add a new one at the end of the chain */ for (; hp->next != nil; hp = hp->next) ; hp->next = smalloc(sizeof *hp); hp = hp->next; hp->next = nil; } hp->handler = h; hp->arg = arg; iunlock(&intrlock); if (irq == ILduart0) { /* special apb sub-interrupt */ *Apbintrsts = 0; *Apbintrmask = 1 << Apbintruart; /* enable, actually */ coherence(); } intron(1 << (ILshift + irq)); if (!resetclock) { resetclock = 1; addclock0link(resetcounts, 100); } } void intrshutdown(void) { introff(INTMASK); } static void jabberoff(Ureg *ur, int irq, ulong bit) { introff(bit); /* interrupt off now ... */ if (ur) ur->status &= ~bit; /* ... and upon return */ offintrs |= bit; iprint("irq %d jabbering; shutting it down\n", irq); } ulong pollall(Ureg *ur, ulong cause) /* must be called splhi */ { int i, intrs, sts; ulong bit; Handler *hp; /* exclude clock and sw intrs */ intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus(); if(intrs == 0) return cause; ilock(&intrlock); for (i = ILmax; i >= ILmin; i--) { bit = 1 << (ILshift + i); if (!(intrs & bit)) continue; intrcauses[i]++; for (hp = &handlers[i]; hp != nil; hp = hp->next) if (hp->handler) { if (i == ILduart0) { sts = *Apbintrsts; if((sts & (1 << Apbintruart)) == 0) continue; /* don't need to ack apb sub-intr */ // *Apbintrsts &= ~(1 << Apbintruart); } (*hp->handler)(hp->arg); splhi(); if (++hp->intrs > 25000) { jabberoff(ur, i, bit); intrs &= ~bit; hp->intrs = 0; } } else if (ur) iprint("no handler for interrupt %d\n", i); cause &= ~bit; } iunlock(&intrlock); return cause; } int intr(Ureg *ur) { int clockintr;