| plan 9 kernel history: overview | file list | diff list |
1991/0718/power/trap.c (diff list | history)
| power/trap.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "ureg.h" #include "io.h" | |
| 1990/0511 | #include "errno.h" | |
| 1990/0227 | /* * vme interrupt routines */ void (*vmevec[256])(int); | |
| 1991/0717 | void noted(Ureg**, ulong); | |
| 1990/0227 | void rfnote(Ureg**); #define LSYS 0x01 #define LUSER 0x02 /* * CAUSE register */ #define EXCCODE(c) ((c>>2)&0x0F) #define FPEXC 16 char *excname[] = { "external interrupt", "TLB modification", "TLB miss (load or fetch)", "TLB miss (store)", "address error (load or fetch)", "address error (store)", "bus error (fetch)", "bus error (data load or store)", "system call", "breakpoint", "reserved instruction", "coprocessor unusable", "arithmetic overflow", "undefined 13", "undefined 14", | |
| 1990/0901 | "undefined 15", /* used as sys call for debugger */ | |
| 1990/0227 | /* the following is made up */ "floating point exception" /* FPEXC */ }; char *fpexcname(ulong); char *regname[]={ "STATUS", "PC", "SP", "CAUSE", "BADADDR", "TLBVIRT", "HI", "LO", "R31", "R30", "R28", "R27", "R26", "R25", "R24", "R23", "R22", "R21", "R20", "R19", "R18", "R17", "R16", "R15", "R14", "R13", "R12", "R11", "R10", "R9", "R8", "R7", "R6", "R5", "R4", "R3", "R2", "R1", }; long ticks; void trap(Ureg *ur) { int ecode; int user; ulong x; char buf[ERRLEN]; | |
| 1990/1214 | SET(x); | |
| 1990/0227 | ecode = EXCCODE(ur->cause); user = ur->status&KUP; if(u) u->p->pc = ur->pc; /* BUG */ | |
| 1991/0705 | ||
| 1990/0227 | switch(ecode){ case CINT: if(u && u->p->state==Running){ if(u->p->fpstate == FPactive) { if(ur->cause & INTR3){ /* FP trap */ x = clrfpintr(); ecode = FPEXC; } savefpregs(&u->fpsave); u->p->fpstate = FPinactive; ur->status &= ~CU1; if(ecode == FPEXC) goto Default; } | |
| 1991/0209 | } intr(ur); | |
| 1990/0227 | break; case CTLBM: case CTLBL: case CTLBS: if(u == 0) | |
| 1990/0802 | panic("fault u==0 pc %lux addr %lux", ur->pc, ur->badvaddr); | |
| 1990/0227 | if(u->p->fpstate == FPactive) { savefpregs(&u->fpsave); u->p->fpstate = FPinactive; ur->status &= ~CU1; } spllo(); x = u->p->insyscall; u->p->insyscall = 1; | |
| 1990/1212 | faultmips(ur, user, ecode); | |
| 1990/0227 | u->p->insyscall = x; break; case CCPU: | |
| 1990/0722 | if(u && u->p && u->p->fpstate == FPinit) { | |
| 1991/0314 | restfpregs(&initfp, u->fpsave.fpstatus); | |
| 1990/0227 | u->p->fpstate = FPactive; ur->status |= CU1; break; } | |
| 1990/0722 | if(u && u->p && u->p->fpstate == FPinactive) { | |
| 1991/0314 | restfpregs(&u->fpsave, u->fpsave.fpstatus); | |
| 1990/0227 | u->p->fpstate = FPactive; ur->status |= CU1; break; } | |
| 1990/0722 | goto Default; | |
| 1990/0227 | default: | |
| 1990/0722 | if(u && u->p && u->p->fpstate == FPactive){ savefpregs(&u->fpsave); u->p->fpstate = FPinactive; ur->status &= ~CU1; } | |
| 1990/0227 | Default: /* | |
| 1991/0705 | * This isn't good enough; can still deadlock because we may * hold print's locks in this processor. | |
| 1990/0227 | */ if(user){ spllo(); if(ecode == FPEXC) | |
| 1990/1110 | sprint(buf, "sys: fp: %s FCR31 %lux", fpexcname(x), x); | |
| 1990/0227 | else | |
| 1991/0705 | sprint(buf, "sys: %s pc=0x%lux", excname[ecode], ur->pc); | |
| 1991/0425 | ||
| 1990/0227 | postnote(u->p, 1, buf, NDebug); }else{ print("%s %s pc=%lux\n", user? "user": "kernel", excname[ecode], ur->pc); if(ecode == FPEXC) print("fp: %s FCR31 %lux\n", fpexcname(x), x); dumpregs(ur); if(m->machno == 0) spllo(); exit(); } } | |
| 1991/0705 | if(user) { if(u->p->procctl) procctl(u->p); if(u->nnote) notify(ur); } | |
| 1990/0227 | splhi(); if(user && u && u->p->fpstate == FPinactive) { | |
| 1991/0314 | restfpregs(&u->fpsave, u->fpsave.fpstatus); | |
| 1990/0227 | u->p->fpstate = FPactive; ur->status |= CU1; } } void | |
| 1991/0209 | intr(Ureg *ur) | |
| 1990/0227 | { | |
| 1991/0212 | int i, any; | |
| 1991/0316 | uchar xxx; | |
| 1991/0212 | uchar pend, npend; | |
| 1990/0227 | long v; | |
| 1991/0209 | ulong cause; | |
| 1991/0219 | static int bogies; | |
| 1990/0227 | ||
| 1991/0425 | m->intr++; | |
| 1991/0209 | cause = ur->cause&(INTR5|INTR4|INTR3|INTR2|INTR1); | |
| 1990/0227 | if(cause & (INTR2|INTR4)){ | |
| 1991/0209 | clock(ur); | |
| 1990/0227 | cause &= ~(INTR2|INTR4); } if(cause & INTR1){ duartintr(); cause &= ~INTR1; } if(cause & INTR5){ | |
| 1991/0212 | any = 0; | |
| 1990/0227 | if(!(*MPBERR1 & (1<<8))){ | |
| 1990/0911 | print("MP bus error %lux %lux\n", *MPBERR0, *MPBERR1); | |
| 1990/0227 | *MPBERR0 = 0; i = *SBEADDR; | |
| 1990/1214 | USED(i); | |
| 1991/0212 | any = 1; | |
| 1990/0227 | } /* * directions from IO2 manual * 1. clear all IO2 masks */ | |
| 1991/0212 | *IO2CLRMASK = 0xff000000; | |
| 1990/0227 | /* * 2. wait for interrupt in progress */ while(!(*INTPENDREG & (1<<5))) ; /* * 3. read pending interrupts */ | |
| 1991/0316 | pend = SBCCREG->fintpending; npend = pend; | |
| 1990/0227 | /* * 4. clear pending register */ i = SBCCREG->flevel; | |
| 1990/1214 | USED(i); | |
| 1991/0316 | /* * 4a. attempt to fix problem */ if(!(*INTPENDREG & (1<<5))) print("pause again\n"); while(!(*INTPENDREG & (1<<5))) ; xxx = SBCCREG->fintpending; if(xxx){ print("new pend %ux\n", xxx); npend = pend |= xxx; i = SBCCREG->flevel; | |
| 1991/0425 | USED(i); | |
| 1991/0316 | } | |
| 1990/0227 | /* * 5a. process lance, scsi */ if(pend & 1) { v = INTVECREG->i[0].vec; | |
| 1990/0907 | if(!(v & (1<<12))){ print("io2 mp bus error %d %lux %lux\n", 0, *MPBERR0, *MPBERR1); *MPBERR0 = 0; | |
| 1991/0212 | any = 1; | |
| 1990/0907 | } | |
| 1990/0911 | if(ioid < IO3R1){ | |
| 1991/0212 | if(!(v & 7)) any = 1; | |
| 1990/0907 | if(!(v & (1<<2))) lanceintr(); if(!(v & (1<<1))) lanceparity(); if(!(v & (1<<0))) print("SCSI interrupt\n"); | |
| 1991/0212 | }else{ if(v & 7) any = 1; | |
| 1990/0907 | if(v & (1<<2)) | |
| 1990/0911 | lanceintr(); | |
| 1990/0907 | if(v & (1<<1)) print("SCSI 1 interrupt\n"); if(v & (1<<0)) print("SCSI 0 interrupt\n"); } | |
| 1990/0227 | } /* * 5b. process vme | |
| 1991/0212 | * i can guess your level | |
| 1990/0227 | */ | |
| 1991/0212 | for(i=1; pend>>=1; i++){ | |
| 1990/0227 | if(pend & 1) { v = INTVECREG->i[i].vec; | |
| 1990/0907 | if(!(v & (1<<12))){ | |
| 1991/0212 | print("io2 mp bus error %d %lux %lux\n", i, *MPBERR0, *MPBERR1); | |
| 1990/0907 | *MPBERR0 = 0; } | |
| 1990/0227 | v &= 0xff; (*vmevec[v])(v); | |
| 1991/0212 | any = 1; | |
| 1990/0227 | } } /* | |
| 1991/0212 | * if nothing else, assume bus error */ | |
| 1991/0219 | if(!any && bogies++<100){ | |
| 1991/0212 | print("bogus intr lvl 5 pend %lux on %d\n", npend, m->machno); delay(100); } /* | |
| 1990/0227 | * 6. re-enable interrupts */ | |
| 1991/0212 | *IO2SETMASK = 0xff000000; | |
| 1990/0227 | cause &= ~INTR5; } if(cause) panic("cause %lux %lux\n", u, cause); } char * fpexcname(ulong x) { static char *str[]={ "inexact operation", "underflow", "overflow", "division by zero", "invalid operation", "unimplemented operation", }; int i; x >>= 12; for(i=0; i<6; i++, x>>=1) if(x & 1) return str[i]; return "no floating point exception"; } | |
| 1990/03091 | ||
| 1990/0227 | void dumpstack(void) { ulong l, v; extern ulong etext; if(u) for(l=(ulong)&l; l<USERADDR+BY2PG; l+=4){ v = *(ulong*)l; if(KTZERO < v && v < (ulong)&etext) print("%lux=%lux\n", l, v); } } void dumpregs(Ureg *ur) { int i; ulong *l; int (*pr)(char*, ...); if(u) print("registers for %s %d\n", u->p->text, u->p->pid); else print("registers for kernel\n"); l = &ur->status; for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2) print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]); } /* * Call user, if necessary, with note */ void notify(Ureg *ur) { ulong sp; lock(&u->p->debug); if(u->nnote==0){ unlock(&u->p->debug); return; } if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){ if(u->note[0].flag == NDebug) pprint("suicide: %s\n", u->note[0].msg); Die: unlock(&u->p->debug); pexit(u->note[0].msg, u->note[0].flag!=NDebug); } if(!u->notified){ if(!u->notify) goto Die; | |
| 1991/0503 | u->svstatus = ur->status; | |
| 1990/0816 | sp = ur->usp; | |
| 1990/0227 | sp -= sizeof(Ureg); | |
| 1991/0705 | if(waserror()){ pprint("suicide: trap in notify\n"); pexit("Suicide", 0); } validaddr((ulong)u->notify, 1, 0); validaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN-3*BY2WD, 0); poperror(); | |
| 1990/0227 | u->ureg = (void*)sp; | |
| 1991/0318 | memmove((Ureg*)sp, ur, sizeof(Ureg)); | |
| 1990/0227 | sp -= ERRLEN; | |
| 1991/0318 | memmove((char*)sp, u->note[0].msg, ERRLEN); | |
| 1990/0227 | sp -= 3*BY2WD; *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ *(ulong*)(sp+1*BY2WD) = (ulong)u->ureg; /* arg 1 is ureg* */ *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ | |
| 1990/0816 | ur->usp = sp; | |
| 1990/0227 | ur->pc = (ulong)u->notify; u->notified = 1; u->nnote--; | |
| 1991/0717 | memmove(&u->lastnote, &u->note[0], sizeof(Note)); | |
| 1991/0318 | memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note)); | |
| 1990/0227 | } unlock(&u->p->debug); } /* * Return user to state before notify() */ void | |
| 1991/0717 | noted(Ureg **urp, ulong arg0) | |
| 1990/0227 | { | |
| 1991/0503 | Ureg *nur; nur = u->ureg; validaddr(nur->pc, 1, 0); validaddr(nur->usp, BY2WD, 0); if(nur->status!=u->svstatus){ | |
| 1991/0717 | pprint("bad noted ureg status %lux\n", nur->status); | |
| 1991/0503 | pexit("Suicide", 0); } | |
| 1990/0227 | lock(&u->p->debug); | |
| 1990/0619 | if(!u->notified){ unlock(&u->p->debug); return; } | |
| 1990/0227 | u->notified = 0; | |
| 1991/0318 | memmove(*urp, u->ureg, sizeof(Ureg)); | |
| 1990/1113 | (*urp)->r1 = -1; /* return error from the interrupted call */ | |
| 1991/0717 | switch(arg0){ case NCONT: splhi(); unlock(&u->p->debug); rfnote(urp); break; /* never returns */ default: pprint("unknown noted arg 0x%lux\n", arg0); u->lastnote.flag = NDebug; /* fall through */ | |
| 1991/0718 | case NDFLT: | |
| 1991/0717 | if(u->lastnote.flag == NDebug) pprint("suicide: %s\n", u->lastnote.msg); unlock(&u->p->debug); pexit(u->lastnote.msg, u->lastnote.flag!=NDebug); } | |
| 1990/0227 | } #undef CHDIR /* BUG */ | |
| 1991/0710 | #include "/sys/src/libc/9syscall/sys.h" | |
| 1990/0227 | typedef long Syscall(ulong*); | |
| 1990/11211 | Syscall sysbind, sysbrk_, syschdir, sysclose, syscreate, sysdeath; | |
| 1990/0227 | Syscall sysdup, syserrstr, sysexec, sysexits, sysfork, sysforkpgrp; | |
| 1990/11211 | Syscall sysfstat, sysfwstat, sysgetpid, sysmount, sysnoted; | |
| 1990/0227 | Syscall sysnotify, sysopen, syspipe, sysr1, sysread, sysremove, sysseek; | |
| 1991/0705 | Syscall syssleep, sysstat, syswait, syswrite, syswstat, sysalarm, syssegbrk; Syscall syssegattach, syssegdetach, syssegfree, syssegflush; | |
| 1990/0227 | Syscall *systab[]={ [SYSR1] sysr1, | |
| 1990/11211 | [ERRSTR] syserrstr, | |
| 1990/0227 | [BIND] sysbind, [CHDIR] syschdir, [CLOSE] sysclose, [DUP] sysdup, | |
| 1991/0513 | [ALARM] sysalarm, | |
| 1990/0227 | [EXEC] sysexec, [EXITS] sysexits, [FORK] sysfork, [FORKPGRP] sysforkpgrp, [FSTAT] sysfstat, | |
| 1991/0705 | [SEGBRK] syssegbrk, | |
| 1990/0227 | [MOUNT] sysmount, [OPEN] sysopen, [READ] sysread, [SEEK] sysseek, [SLEEP] syssleep, [STAT] sysstat, [WAIT] syswait, [WRITE] syswrite, [PIPE] syspipe, [CREATE] syscreate, | |
| 1990/11211 | [___USERSTR___] sysdeath, | |
| 1990/0227 | [BRK_] sysbrk_, [REMOVE] sysremove, [WSTAT] syswstat, [FWSTAT] sysfwstat, [NOTIFY] sysnotify, [NOTED] sysnoted, | |
| 1991/0705 | [SEGATTACH] syssegattach, [SEGDETACH] syssegdetach, [SEGFREE] syssegfree, [SEGFLUSH] syssegflush, | |
| 1990/0227 | }; long syscall(Ureg *aur) { long ret; ulong sp; ulong r1; Ureg *ur; | |
| 1990/0511 | char *msg; | |
| 1990/0227 | ||
| 1991/0425 | m->syscall++; | |
| 1990/0227 | u->p->insyscall = 1; ur = aur; | |
| 1990/0310 | u->p->pc = ur->pc; /* BUG */ | |
| 1990/0901 | ur->cause = 15<<2; /* for debugging: system call is undef 15; | |
| 1990/0227 | /* * since the system call interface does not | |
| 1991/0314 | * guarantee anything about registers, we can * smash them. but we must save fpstatus. | |
| 1990/0227 | */ if(u->p->fpstate == FPactive) { | |
| 1991/0314 | u->fpsave.fpstatus = fcr31(); | |
| 1990/0722 | u->p->fpstate = FPinit; | |
| 1990/0227 | ur->status &= ~CU1; } spllo(); | |
| 1991/0705 | if(u->p->procctl) procctl(u->p); | |
| 1990/0227 | r1 = ur->r1; sp = ur->sp; u->nerrlab = 0; ret = -1; | |
| 1990/0511 | if(!waserror()){ if(r1 >= sizeof systab/BY2WD){ pprint("bad sys call number %d pc %lux\n", r1, ((Ureg*)UREGADDR)->pc); | |
| 1990/1110 | msg = "sys: bad sys call"; | |
| 1990/0511 | Bad: postnote(u->p, 1, msg, NDebug); | |
| 1990/11211 | error(Ebadarg); | |
| 1990/0511 | } if(sp & (BY2WD-1)){ pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); | |
| 1990/1110 | msg = "sys: odd stack"; | |
| 1990/0511 | goto Bad; } | |
| 1991/0710 | if(((ulong*)ur->pc)[-2] == 0x23bdfffc){ /* old calling convention: look for ADD $-4, SP */ pprint("old system call linkage; recompile\n"); sp += BY2WD; } | |
| 1991/0711 | if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD)) validaddr(sp, (1+MAXSYSARG)*BY2WD, 0); | |
| 1991/0710 | ret = (*systab[r1])((ulong*)(sp+BY2WD)); | |
| 1990/0511 | } | |
| 1990/0227 | ur->pc += 4; u->nerrlab = 0; | |
| 1991/0705 | if(u->p->procctl) procctl(u->p); | |
| 1990/0227 | splhi(); | |
| 1990/03091 | u->p->insyscall = 0; | |
| 1990/0227 | if(r1 == NOTED) /* ugly hack */ | |
| 1991/0717 | noted(&aur, *(ulong*)(sp+BY2WD)); /* doesn't return */ | |
| 1990/0227 | if(u->nnote){ ur->r1 = ret; notify(ur); } | |
| 1991/0705 | ||
| 1990/0227 | return ret; } | |
| 1990/1226 | void execpc(ulong entry) { ((Ureg*)UREGADDR)->pc = entry - 4; /* syscall advances it */ | |
| 1990/0227 | } void novme(int v) { static count = 0; print("vme intr 0x%.2x\n", v); count++; if(count >= 10) panic("too many vme intr"); } void setvmevec(int v, void (*f)(int)) { void (*g)(int); v &= 0xff; g = vmevec[v]; if(g && g != novme) print("second setvmevec to 0x%.2x\n", v); vmevec[v] = f; } | |