2 * traps, exceptions, faults and interrupts on ar7161
6 #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");
158 int ecode, clockintr, user, cop, x, fpchk;
160 char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
163 if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
164 iprint("trap: proc %ld kernel stack getting full\n", up->pid);
170 (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
171 iprint("trap: cpu%d kernel stack getting full\n", m->machno);
178 panic("trap: tlb shutdown");
179 ecode = (ur->cause>>2)&EXCMASK;
184 clockintr = intr(ur);
190 if(up->fpstate == FPactive){
191 savefpregs(up->fpsave);
192 up->fpstate = FPinactive;
202 if(up == nil || !user && (ur->badvaddr & KSEGM) == KSEG3) {
209 faultmips(ur, user, ecode);
220 panic("watchpoint trap from kernel mode pc=%#p",
226 cop = (ur->cause>>28)&3;
227 if(user && up && cop == 1) {
228 if(up->fpstate & FPillegal) {
229 /* someone used floating point in a note handler */
231 "sys: floating point in note handler",
235 if(up->fpstate == FPinit || up->fpstate == FPinactive){
236 restfpregs(up->fpsave, up->fpsave->fpstatus&~FPEXPMASK);
237 up->fpstate = FPactive;
250 snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
251 postnote(up, 1, buf, NDebug);
254 if (ecode == CADREL || ecode == CADRES)
255 iprint("kernel addr exception for va %#p pid %#ld %s\n",
256 ur->badvaddr, (up? up->pid: 0),
258 print("cpu%d: kernel %s pc=%#lux\n",
259 m->machno, excname[ecode], ur->pc);
268 fpfcr31 = up->fpsave->fpstatus;
269 if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
271 fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1);
272 snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
273 postnote(up, 1, buf, NDebug);
279 /* delaysched set because we held a lock or because our quantum ended */
280 if(up && up->delaysched && clockintr){
287 /* replicate fpstate to ureg status */
288 if(up->fpstate != FPactive)
294 /* map HPC3 irq to INTR2 */
296 hpc3irqlevel(int irq)
298 *IO(uchar, LIO_0_MASK) |= 1 << (irq & 7);
306 intrenable(int level, void (*h)(Ureg*, void *), void *arg)
310 hp = &handlers[level];
311 if (hp->handler != nil) { /* occupied? */
312 /* add a new one at the end of the chain */
313 for (; hp->next != nil; hp = hp->next)
315 if((hp->next = xalloc(sizeof *hp)) == nil)
316 panic("intrenable: out of memory");
322 intron(INTR0 << level);
335 * ignore interrupts that we have disabled, even if their cause bits
338 cause = ur->cause & ur->status & INTMASK;
339 cause &= ~(INTR1|INTR0); /* ignore sw interrupts */
346 for(mask = INTR2; cause != 0 && mask < INTR7; mask <<= 1){
348 for(hp = hh; hp != nil; hp = hp->next){
349 if(hp->handler != nil){
350 (*hp->handler)(ur, hp->arg);
358 iprint("unhandled interrupts %lux\n", cause);
360 /* preemptive scheduling */
361 if(up != nil && !clockintr)
363 /* if it was a clockintr, sched will be called at end of trap() */
368 fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
375 if(ur->cause & BD) /* branch delay */
379 s = "unimplemented operation";
381 fcr31 >>= 7; /* trap enable bits */
382 fcr31 &= (fcr31>>5); /* anded with exceptions */
389 return "no floating point exception";
391 snprint(buf, size, "%s fppc=%#lux", s, fppc);
396 getpcsp(ulong *pc, ulong *sp)
398 *pc = getcallerpc(&pc);
403 callwithureg(void (*fn)(Ureg*))
407 memset(&ureg, 0, sizeof ureg);
408 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
409 ureg.r31 = getcallerpc(&fn);
414 _dumpstack(Ureg *ureg)
419 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
420 ureg->pc, ureg->sp, ureg->r31);
422 top = (ulong)MACHADDR + MACHSIZE;
424 top = (ulong)up->kstack + KSTACK;
426 for(l=ureg->sp; l < top; l += BY2WD) {
428 if(KTZERO < v && v < (ulong)&etext) {
429 print("%.8lux=%.8lux ", l, v);
442 callwithureg(_dumpstack);
451 return *(ulong*)(s + regname[i].off);
460 print("registers for %s %lud\n", up->text, up->pid);
462 print("registers for kernel\n");
464 for(i = 0; i < nelem(regname); i += 2)
465 print("%s\t%#.8lux\t%s\t%#.8lux\n",
466 regname[i].name, R(ur, i),
467 regname[i+1].name, R(ur, i+1));
482 if(up->fpstate == FPactive){
483 savefpregs(up->fpsave);
484 up->fpstate = FPinactive;
486 up->fpstate |= FPillegal;
492 if(strncmp(n->msg, "sys:", 4) == 0) {
494 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
497 seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
500 if(n->flag != NUser && (up->notified || up->notify==0)) {
501 if(n->flag == NDebug)
502 pprint("suicide: %s\n", n->msg);
505 pexit(n->msg, n->flag!=NDebug);
516 pexit(n->msg, n->flag!=NDebug);
518 sp = ur->usp & ~(BY2V-1);
521 if(!okaddr((ulong)up->notify, BY2WD, 0) ||
522 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
523 pprint("suicide: bad address or sp in notify\n");
528 memmove((Ureg*)sp, ur, sizeof(Ureg)); /* push user regs */
529 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
530 up->ureg = (void*)sp;
533 memmove((char*)sp, up->note[0].msg, ERRMAX); /* push err string */
536 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
537 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
538 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
539 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
542 * arrange to resume at user's handler as if handler(ureg, errstr)
545 ur->pc = (ulong)up->notify;
549 memmove(&up->lastnote, &up->note[0], sizeof(Note));
550 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
558 * Return user to state before notify(); called from user's handler.
561 noted(Ureg *kur, ulong arg0)
567 if(arg0!=NRSTR && !up->notified) {
569 pprint("call to noted() when not notified\n");
574 up->fpstate &= ~FPillegal;
579 if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
580 pprint("bad up->ureg in noted or call to noted() when not notified\n");
585 setregisters(kur, (char*)kur, (char*)up->ureg, sizeof(Ureg));
588 case NRSTR: /* only used by APE */
589 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
590 pprint("suicide: trap in noted\n");
594 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
599 case NSAVE: /* only used by APE */
600 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
601 pprint("suicide: trap in noted\n");
606 sp = oureg-4*BY2WD-ERRMAX;
609 kur->r1 = oureg; /* arg 1 is ureg* */
610 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
611 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
615 pprint("unknown noted arg %#lux\n", arg0);
616 up->lastnote.flag = NDebug;
620 if(up->lastnote.flag == NDebug)
621 pprint("suicide: %s\n", up->lastnote.msg);
623 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
627 #include "../port/systab.h"
630 sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
632 if(up->procctl == Proc_tracesyscall){
634 * Redundant validaddr. Do we care?
635 * Tracing syscalls is not exactly a fast path...
636 * Beware, validaddr currently does a pexit rather
637 * than an error if there's a problem; that might
638 * change in the future.
640 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
641 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
643 syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
644 up->procctl = Proc_stopme;
647 free(up->syscalltrace);
648 up->syscalltrace = nil;
649 *startnsp = todget(nil);
654 sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
658 if(up->procctl == Proc_tracesyscall){
659 up->procctl = Proc_stopme;
660 sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
661 startns, todget(nil));
666 free(up->syscalltrace);
667 up->syscalltrace = nil;
672 * called directly from assembler, not via trap()
684 panic("syscall from kernel");
689 ur->cause = 16<<2; /* for debugging: system call is undef 16 */
692 up->scallnr = ur->r1;
694 sctracesetup(scallnr, sp, ur->pc, &startns);
696 /* no fpu, so no fp state to save */
702 if(scallnr >= nsyscall || systab[scallnr] == 0){
703 pprint("bad sys call number %ld pc %#lux\n",
705 postnote(up, 1, "sys: bad sys call", NDebug);
710 pprint("odd sp in sys call pc %#lux sp %#lux\n",
712 postnote(up, 1, "sys: odd stack", NDebug);
716 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
717 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
719 up->s = *((Sargs*)(sp+BY2WD));
720 up->psstate = sysctab[scallnr];
722 ret = systab[scallnr]((va_list)up->s.args);
725 /* failure: save the error buffer for errstr */
727 up->syserrstr = up->errstr;
729 if(0 && up->pid == 1)
730 print("[%lud %s] syscall %lud: %s\n",
731 up->pid, up->text, scallnr, up->errstr);
734 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
735 for(i = 0; i < NERR; i++)
736 print("sp=%#lux pc=%#lux\n",
737 up->errlab[i].sp, up->errlab[i].pc);
738 panic("error stack");
740 sctracefinish(scallnr, sp, ret, startns);
748 if(scallnr == NOTED) /* ugly hack */
749 noted(ur, *(ulong*)(sp+BY2WD)); /* may return */
751 if(scallnr!=RFORK && (up->procctl || up->nnote))
753 /* if we delayed sched because we held a lock, sched now */
756 /* replicate fpstate to ureg status */
757 if(up->fpstate != FPactive)
763 forkchild(Proc *p, Ureg *ur)
767 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
768 p->sched.pc = (ulong)forkret;
770 cur = (Ureg*)(p->sched.sp+2*BY2WD);
771 memmove(cur, ur, sizeof(Ureg));
773 cur->status &= ~CU1; /* FPU off when returning */
780 kprocchild(Proc *p, void (*entry)(void))
782 p->sched.pc = (ulong)entry;
783 p->sched.sp = (ulong)p->kstack+KSTACK;
786 /* set up user registers before return from exec() */
788 execregs(ulong entry, ulong ssize, ulong nargs)
793 sp = (ulong*)(USTKTOP - ssize);
796 ur = (Ureg*)up->dbgreg;
798 ur->pc = entry - 4; /* syscall advances it */
799 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
807 ur = (Ureg*)up->dbgreg;
812 * This routine must save the values of registers the user is not
813 * permitted to write from devproc and then restore the saved values
817 setregisters(Ureg *xp, char *pureg, char *uva, int n)
821 r27 = xp->r27; /* return PC for GEVector() */
823 memmove(pureg, uva, n);
829 * Give enough context in the ureg to produce a kernel stack for
833 setkernur(Ureg *xp, Proc *p)
835 xp->pc = p->sched.pc;
836 xp->sp = p->sched.sp;
837 xp->r24 = (ulong)p; /* up */
838 xp->r31 = (ulong)sched;