2 #include "../port/lib.h"
9 #include "../port/error.h"
12 static Vctl *vctl[256];
18 mpicenable(0, nil); /* 8259 interrupts are routed through MPIC intr 0 */
27 if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
29 print("intrenable: pci irq %d out of range\n", v->irq);
37 print("intrenable: irq %d out of range\n", v->irq);
41 if(i8259enable(v) == -1)
48 hwintrdisable(Vctl *v)
53 if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
55 print("intrdisable: pci irq %d out of range\n", v->irq);
63 print("intrdisable: irq %d out of range\n", v->irq);
67 if(i8259disable(irq) == -1)
74 hwvecno(int irq, int tbdf)
76 if(BUSTYPE(tbdf) == BusPCI) /* MPIC? */
83 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
89 print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
94 v = xalloc(sizeof(Vctl));
100 strncpy(v->name, name, KNAMELEN-1);
101 v->name[KNAMELEN-1] = 0;
104 vno = hwintrenable(v);
107 print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
113 if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
114 panic("intrenable: handler: %s %s %#p %#p %#p %#p",
115 vctl[vno]->name, v->name,
116 vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
124 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
129 vno = hwvecno(irq, tbdf);
133 ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
134 strcmp((*pv)->name, name)))
139 *pv = (*pv)->next; /* Link out the entry */
148 void noted(Ureg*, ulong);
149 static void _dumpstack(Ureg*);
157 "instruction access",
158 "external interrupt",
161 "floating-point unavailable",
167 "floating point assist",
172 "instruction address breakpoint",
173 "system management interrupt",
184 char *fpexcname(Ureg*, ulong, char*);
185 #define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */
216 char buf[ERRMAX], *s;
218 ecode = (ureg->cause >> 8) & 0xff;
219 user = (ureg->srr1 & MSR_PR) != 0;
223 if((ureg->status & MSR_RI) == 0)
224 print("double fault?: ecode = %d\n", ecode);
235 panic("syscall in kernel: srr1 0x%4.4luX", ureg->srr1);
237 return; /* syscall() calls notify itself, don't do it again */
239 if(!user || up == nil) {
241 panic("floating point in kernel");
246 up->fpstate = FPactive;
249 fprestore(up->fpsave);
250 up->fpstate = FPactive;
255 ureg->srr1 |= MSR_FP;
258 faultpower(ureg, ureg->pc, 1);
263 faultpower(ureg, getdar(), 0);
265 faultpower(ureg, getdar(), 1);
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", 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){
309 if(up->fpstate == FPinactive)
310 ureg->srr1 &= ~MSR_FP;
316 faultpower(Ureg *ureg, ulong addr, int read)
318 int user, insyscall, n;
321 user = (ureg->srr1 & MSR_PR) != 0;
322 insyscall = up->insyscall;
324 n = fault(addr, read);
328 panic("fault: 0x%lux", addr);
330 sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
331 postnote(up, 1, buf, NDebug);
333 up->insyscall = insyscall;
337 sethvec(int v, void (*r)(void))
342 vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
343 vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
344 vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
347 if(o != 0 && o != 0x7F){
348 /* a branch too far */
349 vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
350 vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
351 vp[5] = 0x7c0803a6; /* MOVW R0, LR */
352 vp[6] = 0x4e800021; /* BL (LR) */
354 vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
355 dcflush(vp, 8*sizeof(ulong));
364 * set all exceptions to trap
366 for(i = 0; i < 0x2000; i += 0x100)
369 putmsr(getmsr() & ~MSR_IP);
379 if(vno == 0) { /* 8259, wired through MPIC vec 0 */
384 if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
385 panic("spurious intr %d", vno);
391 for(v = ctl; v != nil; v = v->next){
403 fpexcname(Ureg *ur, ulong fpscr, char *buf)
411 fpscr >>= 3; /* trap enable bits */
412 fpscr &= (fpscr>>22); /* anded with exceptions */
417 return "no floating point exception";
418 sprint(buf, "%s fppc=0x%lux", s, fppc);
423 * Fill in enough of Ureg to get a stack trace, and call a function.
424 * Used by debugging interface rdb.
428 getpcsp(ulong *pc, ulong *sp)
430 *pc = getcallerpc(&pc);
435 callwithureg(void (*fn)(Ureg*))
439 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
440 ureg.lr = getcallerpc(&fn);
445 _dumpstack(Ureg *ureg)
456 sl = (ulong)up->kstack;
459 if(l > el || l < sl){
465 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
467 for(; l < el; l += 4){
469 if(KTZERO < v && v < (ulong)etext){
470 print("%.8lux=%.8lux ", l, v);
482 callwithureg(_dumpstack);
492 print("registers for %s %ld\n", up->text, up->pid);
493 if((ur->srr1 & MSR_PR) == 0)
494 if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
495 print("invalid stack ptr\n");
498 print("registers for kernel\n");
500 print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
502 for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
503 print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
510 (*up->kpfun)(up->kparg);
515 kprocchild(Proc *p, void (*func)(void*), void *arg)
517 p->sched.pc = (ulong)linkproc;
518 p->sched.sp = (ulong)p->kstack+KSTACK;
525 * called in sysfile.c
531 postnote(up, 1, "sys: odd address", NDebug);
537 execregs(uintptr entry, ulong ssize, ulong nargs)
542 sp = (ulong*)(USTKTOP - ssize);
546 ureg->usp = (ulong)sp;
548 ureg->srr1 &= ~MSR_FP;
549 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
553 forkchild(Proc *p, Ureg *ur)
557 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
558 p->sched.pc = (ulong)forkret;
560 cur = (Ureg*)(p->sched.sp+2*BY2WD);
561 memmove(cur, ur, sizeof(Ureg));
564 /* Things from bottom of syscall we never got to execute */
574 ureg = (Ureg*)up->dbgreg;
579 /* This routine must save the values of registers the user is not
580 * permitted to write from devproc and then restore the saved values
584 setregisters(Ureg *xp, char *pureg, char *uva, int n)
589 memmove(pureg, uva, n);
593 /* Give enough context in the ureg to produce a kernel stack for
597 setkernur(Ureg* ureg, Proc* p)
599 ureg->pc = p->sched.pc;
600 ureg->sp = p->sched.sp+4;
618 #include "../port/systab.h"
620 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
635 up->scallnr = ureg->r3;
642 if(scallnr >= nsyscall || systab[scallnr] == nil){
643 pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
644 postnote(up, 1, "sys: bad sys call", NDebug);
648 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
649 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
651 up->s = *((Sargs*)(sp+BY2WD));
652 up->psstate = sysctab[scallnr];
654 ret = systab[scallnr](up->s.args);
657 /* failure: save the error buffer for errstr */
659 up->syserrstr = up->errstr;
663 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
664 print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
665 for(i = 0; i < NERR; i++)
666 print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
667 panic("error stack");
674 * Put return value in frame. On the x86 the syscall is
675 * just another trap and the return value from syscall is
676 * ignored. On other machines the return value is put into
677 * the results register by caller of syscall.
682 noted(ureg, *(ulong*)(sp+BY2WD));
684 /* restoreureg must execute at high IPL */
688 if(up->fpstate == FPinactive)
689 ureg->srr1 &= ~MSR_FP;
693 * Call user, if necessary, with note.
694 * Pass user the Ureg struct and the note on his stack.
712 if(strncmp(n->msg, "sys:", 4) == 0){
714 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
716 sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
719 if(n->flag!=NUser && (up->notified || up->notify==0)){
721 if(n->flag == NDebug)
722 pprint("suicide: %s\n", n->msg);
723 pexit(n->msg, n->flag!=NDebug);
734 pexit(n->msg, n->flag!=NDebug);
736 sp = ur->usp & ~(BY2V-1);
739 if(!okaddr((uintptr)up->notify, BY2WD, 0) ||
740 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
742 pprint("suicide: bad address or sp in notify\n");
746 memmove((Ureg*)sp, ur, sizeof(Ureg));
747 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
748 up->ureg = (void*)sp;
750 memmove((char*)sp, up->note[0].msg, ERRMAX);
752 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
753 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
754 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
755 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
757 ur->pc = (ulong)up->notify;
760 memmove(&up->lastnote, &up->note[0], sizeof(Note));
761 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
770 * Return user to state before notify()
773 noted(Ureg* ureg, ulong arg0)
779 if(arg0!=NRSTR && !up->notified) {
781 pprint("call to noted() when not notified\n");
786 nureg = up->ureg; /* pointer to user returned Ureg struct */
789 oureg = (ulong)nureg;
790 if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
792 pprint("bad ureg in noted or call to noted when not notified\n");
796 memmove(ureg, nureg, sizeof(Ureg));
801 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
803 pprint("suicide: trap in noted\n");
806 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
811 if(!okaddr(nureg->pc, BY2WD, 0)
812 || !okaddr(nureg->usp, BY2WD, 0)){
814 pprint("suicide: trap in noted\n");
818 sp = oureg-4*BY2WD-ERRMAX;
821 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
822 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
826 up->lastnote.flag = NDebug;
831 if(up->lastnote.flag == NDebug)
832 pprint("suicide: %s\n", up->lastnote.msg);
833 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);