2 #include "../port/lib.h"
7 #include "../port/error.h"
15 intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
21 print("intrenable: nil handler for %d for %s\n",
26 v = xalloc(sizeof(Vctl));
31 strncpy(v->name, name, KNAMELEN-1);
32 v->name[KNAMELEN-1] = 0;
35 vno = vectorenable(v);
38 print("intrenable: couldn't enable irq %d for %s\n",
49 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name)
56 ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a ||
57 strcmp((*pv)->name, name)))
61 print("intrdisable: irq %d not found\n", irq);
67 *pv = (*pv)->next; /* Link out the entry */
76 void noted(Ureg*, ulong);
77 static void _dumpstack(Ureg*);
89 "floating-point unavailable",
95 "floating point assist",
98 "data load translation miss",
99 "data store translation miss",
100 "instruction address breakpoint",
101 "system management interrupt",
112 char *fpexcname(Ureg*, ulong, char*);
113 #define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */
149 /* precise time accounting, kernel exit */
150 tos = (Tos*)(USTKTOP-sizeof(Tos));
152 tos->kcycles += t - up->kentry;
153 tos->pcycles = t + up->pcycles;
161 char buf[ERRMAX], *s;
162 extern FPsave initfp;
164 ecode = (ureg->cause >> 8) & 0xff;
165 user = (ureg->srr1 & MSR_PR) != 0;
170 if(ureg->status & MSR_RI == 0)
171 print("double fault?: ecode = %d\n", ecode);
185 panic("kernel fault");
188 faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0);
194 panic("kernel fault");
197 faultpower(ureg, ureg->pc, 1);
199 case CIMISS: /* instruction miss */
202 panic("kernel fault");
205 faultpower(ureg, ureg->imiss, 1);
207 case CLMISS: /* data load miss */
210 panic("kernel fault");
213 faultpower(ureg, ureg->dmiss, 1);
215 case CSMISS: /* data store miss */
218 panic("kernel fault");
221 faultpower(ureg, ureg->dmiss, 0);
226 panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1);
233 return; /* syscall() calls notify itself, don't do it again */
236 if(!user || up == nil) {
238 panic("floating point in kernel");
243 up->fpstate = FPactive;
246 fprestore(&up->fpsave);
247 up->fpstate = FPactive;
250 print("up->fpstate %d\n", up->fpstate);
259 sprint(buf, "sys: floating point in note handler:");
260 postnote(up, 1, buf, NDebug);
263 panic("kernel fpstate illegal");
265 ureg->srr1 |= MSR_FP;
268 if(ureg->status & (1<<19))
269 s = "floating point exception";
270 else if(ureg->status & (1<<18))
271 s = "illegal instruction";
272 else if(ureg->status & (1<<17))
273 s = "privileged instruction";
275 s = "undefined program exception";
278 sprint(buf, "sys: trap: %s", s);
279 postnote(up, 1, buf, NDebug);
286 if(ecode < nelem(excname) && user){
288 sprint(buf, "sys: trap: %s", excname[ecode]);
289 postnote(up, 1, buf, NDebug);
293 if(ecode < nelem(excname))
294 panic("%s", excname[ecode]);
295 panic("unknown trap/intr: %d\n", ecode);
298 /* restoreureg must execute at high IPL */
301 /* delaysched set because we held a lock or because our quantum ended */
302 if(up && up->delaysched && ecode == CDEC){
308 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
309 postnote(up, 1, buf, NDebug);
312 if(up->fpstate != FPactive)
313 ureg->srr1 &= ~MSR_FP;
319 faultpower(Ureg *ureg, ulong addr, int read)
321 int user, insyscall, n;
324 user = (ureg->srr1 & MSR_PR) != 0;
325 insyscall = up->insyscall;
327 n = fault(addr, read);
331 panic("fault: 0x%lux", addr);
333 sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
334 postnote(up, 1, buf, NDebug);
336 up->insyscall = insyscall;
340 sethvec(int v, void (*r)(void))
345 vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
346 vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
347 vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
350 if(o != 0 && o != 0x7F){
351 /* a branch too far */
352 vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
353 vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
354 vp[5] = 0x7c0803a6; /* MOVW R0, LR */
355 vp[6] = 0x4e800021; /* BL (LR) */
357 vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
361 setmvec(int v, void (*r)(void), void (*t)(void))
367 vp[n++] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
368 vp[n++] = 0x7c0802a6; /* MOVW LR, R0 */
369 vp[n++] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
372 if(o != 0 && o != 0x7F){
373 /* a branch too far */
374 vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
375 vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
376 vp[n++] = 0x7c0803a6; /* MOVW R0, LR */
377 vp[n++] = 0x4e800021; /* BL (LR) */
379 vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
382 if(o != 0 && o != 0x7F){
383 /* a branch too far */
384 vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
385 vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
386 vp[n++] = 0x7c0803a6; /* MOVW R0, LR */
387 vp[n] = 0x4e800021; /* BL (LR) */
389 vp[n] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
393 fpexcname(Ureg *ur, ulong fpscr, char *buf)
401 fpscr >>= 3; /* trap enable bits */
402 fpscr &= (fpscr>>22); /* anded with exceptions */
407 return "no floating point exception";
408 sprint(buf, "%s fppc=0x%lux", s, fppc);
413 * Fill in enough of Ureg to get a stack trace, and call a function.
414 * Used by debugging interface rdb.
418 getpcsp(ulong *pc, ulong *sp)
420 *pc = getcallerpc(&pc);
425 callwithureg(void (*fn)(Ureg*))
429 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
430 ureg.lr = getcallerpc(&fn);
435 _dumpstack(Ureg *ureg)
446 sl = (ulong)up->kstack;
449 if(l > el || l < sl){
455 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
457 for(; l < el; l += 4){
459 if(KTZERO < v && v < (ulong)etext){
460 print("%.8lux=%.8lux ", l, v);
472 callwithureg(_dumpstack);
482 print("registers for %s %ld\n", up->text, up->pid);
483 if(ur->srr1 & MSR_PR == 0)
484 if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
485 print("invalid stack ptr\n");
488 print("registers for kernel\n");
491 print("sr[%x]\t0x%.8lux\tsr[%x]\t0x%.8lux\n", i, getsr(i<<28), i+1, getsr((i+1)<<28));
493 for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
494 print("%s\t0x%.8lux\t%s\t0x%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
502 (*up->kpfun)(up->kparg);
507 kprocchild(Proc *p, void (*func)(void*), void *arg)
509 p->sched.pc = (ulong)linkproc;
510 p->sched.sp = (ulong)p->kstack+KSTACK;
517 * called in sysfile.c
523 postnote(up, 1, "sys: odd address", NDebug);
529 execregs(ulong entry, ulong ssize, ulong nargs)
534 sp = (ulong*)(USTKTOP - ssize);
538 ureg->usp = (ulong)sp;
540 ureg->srr1 &= ~MSR_FP; /* disable floating point */
541 up->fpstate = FPinit;
542 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
546 forkchild(Proc *p, Ureg *ur)
550 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
551 p->sched.pc = (ulong)forkret;
553 cur = (Ureg*)(p->sched.sp+2*BY2WD);
554 memmove(cur, ur, sizeof(Ureg));
557 /* Things from bottom of syscall we never got to execute */
567 ureg = (Ureg*)up->dbgreg;
572 /* This routine must save the values of registers the user is not
573 * permitted to write from devproc and then restore the saved values
577 setregisters(Ureg *xp, char *pureg, char *uva, int n)
582 memmove(pureg, uva, n);
586 /* Give enough context in the ureg to produce a kernel stack for
590 setkernur(Ureg* ureg, Proc* p)
592 ureg->pc = p->sched.pc;
593 ureg->sp = p->sched.sp+4;
611 #include "../port/systab.h"
613 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
627 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
628 print("fpstate check, entry syscall\n");
631 print("fpstate check, entry syscall\n");
635 up->scallnr = ureg->r3;
636 if(scallnr == RFORK && up->fpstate == FPactive){
638 up->fpstate = FPinactive;
646 if(scallnr >= nsyscall || systab[scallnr] == nil){
647 pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
648 postnote(up, 1, "sys: bad sys call", NDebug);
652 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
653 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
655 up->s = *((Sargs*)(sp+BY2WD));
656 up->psstate = sysctab[scallnr];
658 ret = systab[scallnr](up->s.args);
661 /* failure: save the error buffer for errstr */
663 up->syserrstr = up->errstr;
667 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
668 print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
669 for(i = 0; i < NERR; i++)
670 print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
671 panic("error stack");
678 * Put return value in frame. On the x86 the syscall is
679 * just another trap and the return value from syscall is
680 * ignored. On other machines the return value is put into
681 * the results register by caller of syscall.
686 noted(ureg, *(ulong*)(sp+BY2WD));
688 /* restoreureg must execute at high IPL */
693 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
694 print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
697 if(up->fpstate != FPactive)
698 ureg->srr1 &= ~MSR_FP;
702 * Call user, if necessary, with note.
703 * Pass user the Ureg struct and the note on his stack.
721 if(strncmp(n->msg, "sys:", 4) == 0){
723 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
725 sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
728 if(n->flag!=NUser && (up->notified || up->notify==0)){
729 if(n->flag == NDebug)
730 pprint("suicide: %s\n", n->msg);
732 pexit(n->msg, n->flag!=NDebug);
743 pexit(n->msg, n->flag!=NDebug);
746 if(up->fpstate == FPactive){
748 up->fpstate = FPinactive;
750 up->fpstate |= FPillegal;
752 sp = ur->usp & ~(BY2V-1);
755 if(!okaddr((ulong)up->notify, BY2WD, 0) ||
756 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
757 pprint("suicide: bad address or sp in notify\n");
762 memmove((Ureg*)sp, ur, sizeof(Ureg));
763 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
764 up->ureg = (void*)sp;
766 memmove((char*)sp, up->note[0].msg, ERRMAX);
768 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
769 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
770 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
771 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
773 ur->pc = (ulong)up->notify;
776 memmove(&up->lastnote, &up->note[0], sizeof(Note));
777 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
786 * Return user to state before notify()
789 noted(Ureg* ureg, ulong arg0)
795 if(arg0!=NRSTR && !up->notified) {
797 pprint("call to noted() when not notified\n");
802 nureg = up->ureg; /* pointer to user returned Ureg struct */
805 oureg = (ulong)nureg;
806 if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
807 pprint("bad ureg in noted or call to noted when not notified\n");
812 memmove(ureg, nureg, sizeof(Ureg));
817 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
818 pprint("suicide: trap in noted\n");
822 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
827 if(!okaddr(nureg->pc, BY2WD, 0)
828 || !okaddr(nureg->usp, BY2WD, 0)){
829 pprint("suicide: trap in noted\n");
834 sp = oureg-4*BY2WD-ERRMAX;
837 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
838 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
842 pprint("unknown noted arg 0x%lux\n", arg0);
843 up->lastnote.flag = NDebug;
847 if(up->lastnote.flag == NDebug)
848 pprint("suicide: %s\n", up->lastnote.msg);
850 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
852 up->fpstate &= ~FPillegal;
853 if (up->fpstate == FPactive)
854 ureg->srr1 |= MSR_FP;
856 ureg->srr1 &= ~MSR_FP;