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 * Check that status is OK to return from note.
582 validstatus(ulong kstatus, ulong ustatus)
584 // if((kstatus & (INTMASK|KX|SX|UX)) != (ustatus & (INTMASK|KX|SX|UX)))
585 if((kstatus & INTMASK) != (ustatus & INTMASK))
587 if((ustatus&(KSU|ERL|EXL|IE)) != (KUSER|EXL|IE))
589 if(ustatus & (0xFFFF0000&~CU1)) /* no CU3, CU2, CU0, RP, FR, RE, DS */
595 * Return user to state before notify(); called from user's handler.
598 noted(Ureg *kur, ulong arg0)
604 if(arg0!=NRSTR && !up->notified) {
606 pprint("call to noted() when not notified\n");
611 up->fpstate &= ~FPillegal;
616 if((oureg & (BY2WD-1))
617 || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
618 pprint("bad up->ureg in noted or call to noted() when not notified\n");
623 if(0 && !validstatus(kur->status, nur->status)) {
625 pprint("bad noted ureg status %#lux\n", nur->status);
629 memmove(kur, up->ureg, sizeof(Ureg));
632 case NRSTR: /* only used by APE */
633 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
634 pprint("suicide: trap in noted\n");
638 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
643 case NSAVE: /* only used by APE */
644 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
645 pprint("suicide: trap in noted\n");
650 sp = oureg-4*BY2WD-ERRMAX;
653 kur->r1 = oureg; /* arg 1 is ureg* */
654 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
655 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
659 pprint("unknown noted arg %#lux\n", arg0);
660 up->lastnote.flag = NDebug;
664 if(up->lastnote.flag == NDebug)
665 pprint("suicide: %s\n", up->lastnote.msg);
667 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
671 #include "../port/systab.h"
674 sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
676 if(up->procctl == Proc_tracesyscall){
678 * Redundant validaddr. Do we care?
679 * Tracing syscalls is not exactly a fast path...
680 * Beware, validaddr currently does a pexit rather
681 * than an error if there's a problem; that might
682 * change in the future.
684 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
685 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
687 syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
688 up->procctl = Proc_stopme;
691 free(up->syscalltrace);
692 up->syscalltrace = nil;
693 *startnsp = todget(nil);
698 sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
702 if(up->procctl == Proc_tracesyscall){
703 up->procctl = Proc_stopme;
704 sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
705 startns, todget(nil));
710 free(up->syscalltrace);
711 up->syscalltrace = nil;
716 * called directly from assembler, not via trap()
733 ur->cause = 16<<2; /* for debugging: system call is undef 16 */
736 up->scallnr = ur->r1;
738 sctracesetup(scallnr, sp, ur->pc, &startns);
740 /* no fpu, so no fp state to save */
746 if(scallnr >= nsyscall || systab[scallnr] == 0){
747 pprint("bad sys call number %ld pc %#lux\n",
749 postnote(up, 1, "sys: bad sys call", NDebug);
754 pprint("odd sp in sys call pc %#lux sp %#lux\n",
756 postnote(up, 1, "sys: odd stack", NDebug);
760 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
761 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
763 up->s = *((Sargs*)(sp+BY2WD));
764 up->psstate = sysctab[scallnr];
766 ret = systab[scallnr]((va_list)up->s.args);
769 /* failure: save the error buffer for errstr */
771 up->syserrstr = up->errstr;
773 if(0 && up->pid == 1)
774 print("[%lud %s] syscall %lud: %s\n",
775 up->pid, up->text, scallnr, up->errstr);
778 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
779 for(i = 0; i < NERR; i++)
780 print("sp=%#lux pc=%#lux\n",
781 up->errlab[i].sp, up->errlab[i].pc);
782 panic("error stack");
784 sctracefinish(scallnr, sp, ret, startns);
792 if(scallnr == NOTED) /* ugly hack */
793 noted(ur, *(ulong*)(sp+BY2WD)); /* may return */
795 if(scallnr!=RFORK && (up->procctl || up->nnote))
797 /* if we delayed sched because we held a lock, sched now */
804 forkchild(Proc *p, Ureg *ur)
808 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
809 p->sched.pc = (ulong)forkret;
811 cur = (Ureg*)(p->sched.sp+2*BY2WD);
812 memmove(cur, ur, sizeof(Ureg));
814 cur->status &= ~CU1; /* FPU off when returning */
819 /* Things from bottom of syscall we never got to execute */
829 up->kpfun(up->kparg);
830 pexit("kproc exiting", 0);
834 kprocchild(Proc *p, void (*func)(void*), void *arg)
836 p->sched.pc = (ulong)linkproc;
837 p->sched.sp = (ulong)p->kstack+KSTACK;
843 /* set up user registers before return from exec() */
845 execregs(ulong entry, ulong ssize, ulong nargs)
850 sp = (ulong*)(USTKTOP - ssize);
853 ur = (Ureg*)up->dbgreg;
855 ur->pc = entry - 4; /* syscall advances it */
856 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
864 ur = (Ureg*)up->dbgreg;
869 * This routine must save the values of registers the user is not
870 * permitted to write from devproc and then restore the saved values
874 setregisters(Ureg *xp, char *pureg, char *uva, int n)
879 memmove(pureg, uva, n);
884 * Give enough context in the ureg to produce a kernel stack for
888 setkernur(Ureg *xp, Proc *p)
890 xp->pc = p->sched.pc;
891 xp->sp = p->sched.sp;
892 xp->r24 = (ulong)p; /* up */
893 xp->r31 = (ulong)sched;