2 * traps, exceptions, faults and interrupts on ar7161
5 #include "../port/lib.h"
12 #include "../port/error.h"
14 typedef struct Handler Handler;
17 void (*handler)(Ureg*, void *);
19 Handler *next; /* at this interrupt level */
23 void kernfault(Ureg*, int);
24 void noted(Ureg*, ulong);
29 "trap: external interrupt",
30 "trap: TLB modification (store to unwritable)",
31 "trap: TLB miss (load or fetch)",
32 "trap: TLB miss (store)",
33 "trap: address error (load or fetch)",
34 "trap: address error (store)",
35 "trap: bus error (fetch)",
36 "trap: bus error (data load or store)",
39 "trap: reserved instruction",
40 "trap: coprocessor unusable",
41 "trap: arithmetic overflow",
42 "trap: TRAP exception",
43 "trap: VCE (instruction)",
44 "trap: floating-point exception",
45 "trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */
46 "trap: corextend unusable",
47 "trap: precise coprocessor 2 exception",
48 "trap: TLB read-inhibit",
49 "trap: TLB execute-inhibit",
52 "trap: WATCH exception",
53 "trap: machine checkcore",
71 char *fpexcname(Ureg*, ulong, char*, uint);
72 #define FPEXPMASK (0x3f<<12) /* Floating exception bits in fcr31 */
78 "STATUS", offsetof(Ureg, status),
79 "PC", offsetof(Ureg, pc),
80 "SP", offsetof(Ureg, sp),
81 "CAUSE",offsetof(Ureg, cause),
82 "BADADDR", offsetof(Ureg, badvaddr),
83 "TLBVIRT", offsetof(Ureg, tlbvirt),
84 "HI", offsetof(Ureg, hi),
85 "LO", offsetof(Ureg, lo),
86 "R31", offsetof(Ureg, r31),
87 "R30", offsetof(Ureg, r30),
88 "R28", offsetof(Ureg, r28),
89 "R27", offsetof(Ureg, r27),
90 "R26", offsetof(Ureg, r26),
91 "R25", offsetof(Ureg, r25),
92 "R24", offsetof(Ureg, r24),
93 "R23", offsetof(Ureg, r23),
94 "R22", offsetof(Ureg, r22),
95 "R21", offsetof(Ureg, r21),
96 "R20", offsetof(Ureg, r20),
97 "R19", offsetof(Ureg, r19),
98 "R18", offsetof(Ureg, r18),
99 "R17", offsetof(Ureg, r17),
100 "R16", offsetof(Ureg, r16),
101 "R15", offsetof(Ureg, r15),
102 "R14", offsetof(Ureg, r14),
103 "R13", offsetof(Ureg, r13),
104 "R12", offsetof(Ureg, r12),
105 "R11", offsetof(Ureg, r11),
106 "R10", offsetof(Ureg, r10),
107 "R9", offsetof(Ureg, r9),
108 "R8", offsetof(Ureg, r8),
109 "R7", offsetof(Ureg, r7),
110 "R6", offsetof(Ureg, r6),
111 "R5", offsetof(Ureg, r5),
112 "R4", offsetof(Ureg, r4),
113 "R3", offsetof(Ureg, r3),
114 "R2", offsetof(Ureg, r2),
115 "R1", offsetof(Ureg, r1),
118 static Handler handlers[8];
121 kvce(Ureg *ur, int ecode)
132 print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);
133 if(up && !(ur->badvaddr & KSEGM)) {
135 s = seg(up, addr, 0);
137 print("kvce: no seg for %#lux\n", addr);
141 soff = addr - s->base;
142 p = &s->map[soff/PTEMAPMEM];
144 pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
146 print("kvce: pa=%#lux, va=%#lux\n",
147 (*pg)->pa, (*pg)->va);
149 print("kvce: no *pg\n");
151 print("kvce: no *p\n");
155 /* prepare to go to user space */
161 /* replicate fpstate to ureg status */
162 if(up->fpstate != FPactive)
165 /* precise time accounting, kernel exit */
166 tos = (Tos*)(USTKTOP-sizeof(Tos));
167 tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;
168 tos->pcycles = up->pcycles;
175 int ecode, clockintr, user, cop, x, fpchk;
177 char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
180 if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
181 iprint("trap: proc %ld kernel stack getting full\n", up->pid);
187 (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
188 iprint("trap: cpu%d kernel stack getting full\n", m->machno);
194 ecode = (ur->cause>>2)&EXCMASK;
197 panic("trap: tlb shutdown");
208 clockintr = intr(ur);
214 if(up->fpstate == FPactive){
215 savefpregs(&up->fpsave);
216 up->fpstate = FPinactive;
226 if(up == nil || !user && (ur->badvaddr & KSEGM) == KSEG3) {
233 faultmips(ur, user, ecode);
244 panic("watchpoint trap from kernel mode pc=%#p",
250 cop = (ur->cause>>28)&3;
251 if(user && up && cop == 1) {
252 if(up->fpstate & FPillegal) {
253 /* someone used floating point in a note handler */
255 "sys: floating point in note handler",
259 if(up->fpstate == FPinit || up->fpstate == FPinactive){
260 restfpregs(&up->fpsave, up->fpsave.fpstatus&~FPEXPMASK);
261 up->fpstate = FPactive;
274 snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
275 postnote(up, 1, buf, NDebug);
278 if (ecode == CADREL || ecode == CADRES)
279 iprint("kernel addr exception for va %#p pid %#ld %s\n",
280 ur->badvaddr, (up? up->pid: 0),
282 print("cpu%d: kernel %s pc=%#lux\n",
283 m->machno, excname[ecode], ur->pc);
292 fpfcr31 = up->fpsave.fpstatus;
293 if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
295 fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1);
296 snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
297 postnote(up, 1, buf, NDebug);
303 /* delaysched set because we held a lock or because our quantum ended */
304 if(up && up->delaysched && clockintr){
315 /* map HPC3 irq to INTR2 */
317 hpc3irqlevel(int irq)
319 *IO(uchar, LIO_0_MASK) |= 1 << (irq & 7);
327 intrenable(int level, void (*h)(Ureg*, void *), void *arg)
331 hp = &handlers[level];
332 if (hp->handler != nil) { /* occupied? */
333 /* add a new one at the end of the chain */
334 for (; hp->next != nil; hp = hp->next)
336 if((hp->next = xalloc(sizeof *hp)) == nil)
337 panic("intrenable: out of memory");
343 intron(INTR0 << level);
356 * ignore interrupts that we have disabled, even if their cause bits
359 cause = ur->cause & ur->status & INTMASK;
360 cause &= ~(INTR1|INTR0); /* ignore sw interrupts */
367 for(mask = INTR2; cause != 0 && mask < INTR7; mask <<= 1){
369 for(hp = hh; hp != nil; hp = hp->next){
370 if(hp->handler != nil){
371 (*hp->handler)(ur, hp->arg);
379 iprint("unhandled interrupts %lux\n", cause);
381 /* preemptive scheduling */
382 if(up != nil && !clockintr)
384 /* if it was a clockintr, sched will be called at end of trap() */
389 fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
396 if(ur->cause & BD) /* branch delay */
400 s = "unimplemented operation";
402 fcr31 >>= 7; /* trap enable bits */
403 fcr31 &= (fcr31>>5); /* anded with exceptions */
410 return "no floating point exception";
412 snprint(buf, size, "%s fppc=%#lux", s, fppc);
417 getpcsp(ulong *pc, ulong *sp)
419 *pc = getcallerpc(&pc);
424 callwithureg(void (*fn)(Ureg*))
428 memset(&ureg, 0, sizeof ureg);
429 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
430 ureg.r31 = getcallerpc(&fn);
435 _dumpstack(Ureg *ureg)
440 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
441 ureg->pc, ureg->sp, ureg->r31);
443 top = (ulong)MACHADDR + MACHSIZE;
445 top = (ulong)up->kstack + KSTACK;
447 for(l=ureg->sp; l < top; l += BY2WD) {
449 if(KTZERO < v && v < (ulong)&etext) {
450 print("%.8lux=%.8lux ", l, v);
463 callwithureg(_dumpstack);
472 return *(ulong*)(s + regname[i].off);
481 print("registers for %s %lud\n", up->text, up->pid);
483 print("registers for kernel\n");
485 for(i = 0; i < nelem(regname); i += 2)
486 print("%s\t%#.8lux\t%s\t%#.8lux\n",
487 regname[i].name, R(ur, i),
488 regname[i+1].name, R(ur, i+1));
503 if(up->fpstate == FPactive){
504 savefpregs(&up->fpsave);
505 up->fpstate = FPinactive;
507 up->fpstate |= FPillegal;
513 if(strncmp(n->msg, "sys:", 4) == 0) {
515 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
518 seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
521 if(n->flag != NUser && (up->notified || up->notify==0)) {
522 if(n->flag == NDebug)
523 pprint("suicide: %s\n", n->msg);
526 pexit(n->msg, n->flag!=NDebug);
537 pexit(n->msg, n->flag!=NDebug);
539 sp = ur->usp & ~(BY2V-1);
542 if(!okaddr((ulong)up->notify, BY2WD, 0) ||
543 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
544 pprint("suicide: bad address or sp in notify\n");
549 memmove((Ureg*)sp, ur, sizeof(Ureg)); /* push user regs */
550 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
551 up->ureg = (void*)sp;
554 memmove((char*)sp, up->note[0].msg, ERRMAX); /* push err string */
557 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
558 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
559 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
560 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
563 * arrange to resume at user's handler as if handler(ureg, errstr)
566 ur->pc = (ulong)up->notify;
570 memmove(&up->lastnote, &up->note[0], sizeof(Note));
571 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
579 * Return user to state before notify(); called from user's handler.
582 noted(Ureg *kur, ulong arg0)
588 if(arg0!=NRSTR && !up->notified) {
590 pprint("call to noted() when not notified\n");
595 up->fpstate &= ~FPillegal;
600 if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
601 pprint("bad up->ureg in noted or call to noted() when not notified\n");
606 setregisters(kur, (char*)kur, (char*)up->ureg, sizeof(Ureg));
609 case NRSTR: /* only used by APE */
610 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
611 pprint("suicide: trap in noted\n");
615 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
620 case NSAVE: /* only used by APE */
621 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
622 pprint("suicide: trap in noted\n");
627 sp = oureg-4*BY2WD-ERRMAX;
630 kur->r1 = oureg; /* arg 1 is ureg* */
631 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
632 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
636 pprint("unknown noted arg %#lux\n", arg0);
637 up->lastnote.flag = NDebug;
641 if(up->lastnote.flag == NDebug)
642 pprint("suicide: %s\n", up->lastnote.msg);
644 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
648 #include "../port/systab.h"
651 sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
653 if(up->procctl == Proc_tracesyscall){
655 * Redundant validaddr. Do we care?
656 * Tracing syscalls is not exactly a fast path...
657 * Beware, validaddr currently does a pexit rather
658 * than an error if there's a problem; that might
659 * change in the future.
661 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
662 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
664 syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
665 up->procctl = Proc_stopme;
668 free(up->syscalltrace);
669 up->syscalltrace = nil;
670 *startnsp = todget(nil);
675 sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
679 if(up->procctl == Proc_tracesyscall){
680 up->procctl = Proc_stopme;
681 sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
682 startns, todget(nil));
687 free(up->syscalltrace);
688 up->syscalltrace = nil;
693 * called directly from assembler, not via trap()
710 ur->cause = 16<<2; /* for debugging: system call is undef 16 */
713 up->scallnr = ur->r1;
715 sctracesetup(scallnr, sp, ur->pc, &startns);
717 /* no fpu, so no fp state to save */
723 if(scallnr >= nsyscall || systab[scallnr] == 0){
724 pprint("bad sys call number %ld pc %#lux\n",
726 postnote(up, 1, "sys: bad sys call", NDebug);
731 pprint("odd sp in sys call pc %#lux sp %#lux\n",
733 postnote(up, 1, "sys: odd stack", NDebug);
737 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
738 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
740 up->s = *((Sargs*)(sp+BY2WD));
741 up->psstate = sysctab[scallnr];
743 ret = systab[scallnr]((va_list)up->s.args);
746 /* failure: save the error buffer for errstr */
748 up->syserrstr = up->errstr;
750 if(0 && up->pid == 1)
751 print("[%lud %s] syscall %lud: %s\n",
752 up->pid, up->text, scallnr, up->errstr);
755 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
756 for(i = 0; i < NERR; i++)
757 print("sp=%#lux pc=%#lux\n",
758 up->errlab[i].sp, up->errlab[i].pc);
759 panic("error stack");
761 sctracefinish(scallnr, sp, ret, startns);
769 if(scallnr == NOTED) /* ugly hack */
770 noted(ur, *(ulong*)(sp+BY2WD)); /* may return */
772 if(scallnr!=RFORK && (up->procctl || up->nnote))
774 /* if we delayed sched because we held a lock, sched now */
781 forkchild(Proc *p, Ureg *ur)
785 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
786 p->sched.pc = (ulong)forkret;
788 cur = (Ureg*)(p->sched.sp+2*BY2WD);
789 memmove(cur, ur, sizeof(Ureg));
791 cur->status &= ~CU1; /* FPU off when returning */
796 /* Things from bottom of syscall we never got to execute */
806 up->kpfun(up->kparg);
807 pexit("kproc exiting", 0);
811 kprocchild(Proc *p, void (*func)(void*), void *arg)
813 p->sched.pc = (ulong)linkproc;
814 p->sched.sp = (ulong)p->kstack+KSTACK;
820 /* set up user registers before return from exec() */
822 execregs(ulong entry, ulong ssize, ulong nargs)
827 sp = (ulong*)(USTKTOP - ssize);
830 ur = (Ureg*)up->dbgreg;
832 ur->pc = entry - 4; /* syscall advances it */
833 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
841 ur = (Ureg*)up->dbgreg;
846 * This routine must save the values of registers the user is not
847 * permitted to write from devproc and then restore the saved values
851 setregisters(Ureg *xp, char *pureg, char *uva, int n)
855 r27 = xp->r27; /* return PC for GEVector() */
857 memmove(pureg, uva, n);
863 * Give enough context in the ureg to produce a kernel stack for
867 setkernur(Ureg *xp, Proc *p)
869 xp->pc = p->sched.pc;
870 xp->sp = p->sched.sp;
871 xp->r24 = (ulong)p; /* up */
872 xp->r31 = (ulong)sched;