summaryrefslogtreecommitdiff
path: root/sys/src/9/cycv/trap.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2020-01-08 02:35:01 +0000
committeraiju <devnull@localhost>2020-01-08 02:35:01 +0000
commit17ebe55031ae6945ad1f671b69267a672328e4b1 (patch)
treef3879436d00a88389d57d549a9b07171206c17c1 /sys/src/9/cycv/trap.c
parent826c76f90df66a9b20a3cf279bfb47d4d27322af (diff)
add cycv kernel
Diffstat (limited to 'sys/src/9/cycv/trap.c')
-rw-r--r--sys/src/9/cycv/trap.c591
1 files changed, 591 insertions, 0 deletions
diff --git a/sys/src/9/cycv/trap.c b/sys/src/9/cycv/trap.c
new file mode 100644
index 000000000..5dbe809b2
--- /dev/null
+++ b/sys/src/9/cycv/trap.c
@@ -0,0 +1,591 @@
+#include "u.h"
+#include <ureg.h>
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "tos.h"
+
+static void
+_dumpstack(Ureg *ureg)
+{
+ uintptr l, v, i, estack;
+ extern ulong etext;
+ int x;
+ char *s;
+
+ if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
+ iprint("dumpstack disabled\n");
+ return;
+ }
+ iprint("cpu%d: dumpstack\n", m->machno);
+
+ x = 0;
+ x += iprint("ktrace /arm/9cycv %.8lux %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp, ureg->r14);
+ i = 0;
+ if(up
+ && (uintptr)&l >= (uintptr)up->kstack
+ && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
+ estack = (uintptr)up->kstack+KSTACK;
+ else if((uintptr)&l >= (uintptr)m->stack
+ && (uintptr)&l <= (uintptr)m+MACHSIZE)
+ estack = (uintptr)m+MACHSIZE;
+ else
+ return;
+ x += iprint("estackx %p\n", estack);
+
+ for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
+ v = *(uintptr*)l;
+ if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
+ x += iprint("%.8p=%.8p ", l, v);
+ i++;
+ }
+ if(i == 4){
+ i = 0;
+ x += iprint("\n");
+ }
+ }
+ if(i)
+ iprint("\n");
+ iprint("EOF\n");
+}
+
+static char*
+faulterr[0x20] = {
+[0x01] "alignement fault",
+[0x02] "debug event",
+[0x04] "fault on instruction cache maintenance",
+[0x08] "synchronous external abort",
+[0x0C] "synchronous external abort on translation table walk L1",
+[0x0E] "synchronous external abort on translation table walk L2",
+[0x10] "tlb conflict abort",
+[0x16] "asynchronous external abort",
+[0x19] "synchronous parity error on memory access",
+[0x1C] "synchronous parity error on translation table walk L1",
+[0x1E] "synchronous parity error on translation table walk L2",
+};
+
+static void
+faultarm(Ureg *ureg, ulong fsr, uintptr addr)
+{
+ int user, insyscall, read;
+ static char buf[ERRMAX];
+ char *err;
+
+ read = (fsr & (1<<11)) == 0;
+ user = userureg(ureg);
+ if(!user){
+ if(addr >= USTKTOP || up == nil)
+ _dumpstack(ureg);
+ if(addr >= USTKTOP)
+ panic("kernel fault: bad address pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+ if(up == nil)
+ panic("kernel fault: no user process pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+ }
+ if(up == nil)
+ panic("user fault: up=nil pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+
+ insyscall = up->insyscall;
+ up->insyscall = 1;
+ switch(fsr & 0x1F){
+ case 0x05: /* translation fault L1 */
+ case 0x07: /* translation fault L2 */
+ case 0x03: /* access flag fault L1 */
+ case 0x06: /* access flag fault L2 */
+ case 0x09: /* domain fault L1 */
+ case 0x0B: /* domain fault L2 */
+ case 0x0D: /* permission fault L1 */
+ case 0x0F: /* permission fault L2 */
+ if(fault(addr, ureg->pc, read) == 0)
+ break;
+ /* wet floor */
+ default:
+ err = faulterr[fsr & 0x1F];
+ if(err == nil)
+ err = "fault";
+ if(!user){
+ dumpregs(ureg);
+ _dumpstack(ureg);
+ panic("kernel %s: pc=%#.8lux addr=%#.8lux fsr=%#.8lux", err, ureg->pc, addr, fsr);
+ }
+ sprint(buf, "sys: trap: %s %s addr=%#.8lux", err, read ? "read" : "write", addr);
+ postnote(up, 1, buf, NDebug);
+ }
+ up->insyscall = insyscall;
+}
+
+static void
+mathtrap(Ureg *, ulong)
+{
+ int s;
+
+ if((up->fpstate & FPillegal) != 0){
+ postnote(up, 1, "sys: floating point in note handler", NDebug);
+ return;
+ }
+ switch(up->fpstate){
+ case FPinit:
+ s = splhi();
+ fpinit();
+ up->fpstate = FPactive;
+ splx(s);
+ break;
+ case FPinactive:
+ s = splhi();
+ fprestore(up->fpsave);
+ up->fpstate = FPactive;
+ splx(s);
+ break;
+ case FPactive:
+ postnote(up, 1, "sys: floating point error", NDebug);
+ break;
+ }
+}
+
+void
+trap(Ureg *ureg)
+{
+ int user;
+ ulong opc, cp;
+
+ user = userureg(ureg);
+ if(user){
+ if(up == nil)
+ panic("user trap: up=nil");
+ up->dbgreg = ureg;
+ cycles(&up->kentry);
+ }
+ switch(ureg->type){
+ case PsrMund:
+ ureg->pc -= 4;
+ if(user){
+ spllo();
+ if(okaddr(ureg->pc, 4, 0)){
+ opc = *(ulong*)ureg->pc;
+ if((opc & 0x0f000000) == 0x0e000000 || (opc & 0x0e000000) == 0x0c000000){
+ cp = opc >> 8 & 15;
+ if(cp == 10 || cp == 11){
+ mathtrap(ureg, opc);
+ break;
+ }
+ }
+ }
+ postnote(up, 1, "sys: trap: invalid opcode", NDebug);
+ break;
+ }
+ dumpregs(ureg);
+ panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
+ break;
+ case PsrMiabt:
+ ureg->pc -= 4;
+ faultarm(ureg, getifsr(), getifar());
+ break;
+ case PsrMabt:
+ ureg->pc -= 8;
+ faultarm(ureg, getdfsr(), getdfar());
+ break;
+ case PsrMirq:
+ ureg->pc -= 4;
+ intr(ureg);
+ break;
+ default:
+ iprint("cpu%d: unknown trap type %ulx\n", m->machno, ureg->type);
+ }
+ splhi();
+ if(user){
+ if(up->procctl || up->nnote)
+ notify(ureg);
+ kexit(ureg);
+ }
+}
+
+#include "../port/systab.h"
+
+void
+syscall(Ureg *ureg)
+{
+ char *e;
+ uintptr sp;
+ long ret;
+ int i, s;
+ ulong scallnr;
+ vlong startns, stopns;
+
+ if(!userureg(ureg))
+ panic("syscall: pc=%#.8lux", ureg->pc);
+
+ cycles(&up->kentry);
+
+ m->syscall++;
+ up->insyscall = 1;
+ up->pc = ureg->pc;
+ up->dbgreg = ureg;
+
+ sp = ureg->sp;
+ up->scallnr = scallnr = ureg->r0;
+
+ spllo();
+
+ up->nerrlab = 0;
+ ret = -1;
+ if(!waserror()){
+ if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
+ validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+ evenaddr(sp);
+ }
+ up->s = *((Sargs*) (sp + BY2WD));
+
+ if(up->procctl == Proc_tracesyscall){
+ syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl();
+ splx(s);
+ startns = todget(nil);
+ }
+
+ if(scallnr >= nsyscall || systab[scallnr] == 0){
+ pprint("bad sys call number %lud pc %lux", scallnr, ureg->pc);
+ postnote(up, 1, "sys: bad sys call", NDebug);
+ error(Ebadarg);
+ }
+ up->psstate = sysctab[scallnr];
+ ret = systab[scallnr]((va_list)up->s.args);
+ poperror();
+ }else{
+ e = up->syserrstr;
+ up->syserrstr = up->errstr;
+ up->errstr = e;
+ }
+ if(up->nerrlab){
+ print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
+ for(i = 0; i < NERR; i++)
+ print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
+ panic("error stack");
+ }
+
+ ureg->r0 = ret;
+ if(up->procctl == Proc_tracesyscall){
+ stopns = todget(nil);
+ sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl();
+ splx(s);
+ }
+
+ up->insyscall = 0;
+ up->psstate = 0;
+ if(scallnr == NOTED)
+ noted(ureg, *((ulong *) up->s.args));
+
+ if(scallnr != RFORK && (up->procctl || up->nnote)){
+ splhi();
+ notify(ureg);
+ }
+ if(up->delaysched)
+ sched();
+ kexit(ureg);
+ splhi();
+}
+
+int
+notify(Ureg *ureg)
+{
+ int l;
+ ulong s, sp;
+ Note *n;
+
+ if(up->procctl)
+ procctl();
+ if(up->nnote == 0)
+ return 0;
+
+ if(up->fpstate == FPactive){
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPillegal;
+
+ s = spllo();
+ qlock(&up->debug);
+ up->notepending = 0;
+ n = &up->note[0];
+ if(strncmp(n->msg, "sys:", 4) == 0){
+ l = strlen(n->msg);
+ if(l > ERRMAX-15) /* " pc=0x12345678\0" */
+ l = ERRMAX-15;
+ sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
+ }
+
+ if(n->flag!=NUser && (up->notified || up->notify==0)){
+ qunlock(&up->debug);
+ if(n->flag == NDebug)
+ pprint("suicide: %s\n", n->msg);
+ pexit(n->msg, n->flag!=NDebug);
+ }
+
+ if(up->notified){
+ qunlock(&up->debug);
+ splhi();
+ return 0;
+ }
+
+ if(!up->notify){
+ qunlock(&up->debug);
+ pexit(n->msg, n->flag!=NDebug);
+ }
+ sp = ureg->sp;
+ sp -= 256; /* debugging: preserve context causing problem */
+ sp -= sizeof(Ureg);
+
+ if(!okaddr((uintptr)up->notify, 1, 0)
+ || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+ || ((uintptr) up->notify & 3) != 0
+ || (sp & 3) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: bad address in notify\n");
+ pexit("Suicide", 0);
+ }
+
+ memmove((Ureg*)sp, ureg, sizeof(Ureg));
+ *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
+ up->ureg = (void*)sp;
+ sp -= BY2WD+ERRMAX;
+ memmove((char*)sp, up->note[0].msg, ERRMAX);
+ sp -= 3*BY2WD;
+ *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
+ *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;
+ ureg->r0 = (uintptr) up->ureg;
+ ureg->sp = sp;
+ ureg->pc = (uintptr) up->notify;
+ ureg->r14 = 0;
+ up->notified = 1;
+ up->nnote--;
+ memmove(&up->lastnote, &up->note[0], sizeof(Note));
+ memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
+
+ qunlock(&up->debug);
+ splx(s);
+ return 1;
+}
+
+void
+noted(Ureg *ureg, ulong arg0)
+{
+ Ureg *nureg;
+ ulong oureg, sp;
+
+ qlock(&up->debug);
+ if(arg0 != NRSTR && !up->notified){
+ qunlock(&up->debug);
+ pprint("call to noted() when not notified\n");
+ pexit("Suicide", 0);
+ }
+ up->notified = 0;
+
+ nureg = up->ureg;
+ up->fpstate &= ~FPillegal;
+
+ oureg = (ulong) nureg;
+ if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
+ qunlock(&up->debug);
+ pprint("bad ureg in noted or call to noted when not notified\n");
+ pexit("Suicide", 0);
+ }
+
+ nureg->psr = nureg->psr & 0xf80f0000 | ureg->psr & 0x07f0ffff;
+
+ memmove(ureg, nureg, sizeof(Ureg));
+
+ switch(arg0){
+ case NCONT: case NRSTR:
+ if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
+ (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: trap in noted\n");
+ pexit("Suicide", 0);
+ }
+ up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD));
+ qunlock(&up->debug);
+ break;
+
+ case NSAVE:
+ if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
+ (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: trap in noted\n");
+ pexit("Suicide", 0);
+ }
+ qunlock(&up->debug);
+ sp = oureg - 4 * BY2WD - ERRMAX;
+ splhi();
+ ureg->sp = sp;
+ ureg->r0 = (uintptr) oureg;
+ ((ulong *) sp)[1] = oureg;
+ ((ulong *) sp)[0] = 0;
+ break;
+
+ default:
+ up->lastnote.flag = NDebug;
+
+ case NDFLT:
+ qunlock(&up->debug);
+ if(up->lastnote.flag == NDebug)
+ pprint("suicide: %s\n", up->lastnote.msg);
+ pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
+ }
+}
+
+
+void
+dumpstack(void)
+{
+ callwithureg(_dumpstack);
+}
+
+void
+dumpregs(Ureg *ureg)
+{
+ iprint("trap: %lux psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
+ ureg->type, ureg->psr, ureg->type, ureg->pc, ureg->link);
+ iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
+ ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
+ iprint("R9 %8.8lux R8 %8.8lux R7 %8.8lux R6 %8.8lux R5 %8.8lux\n",
+ ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
+ iprint("R4 %8.8lux R3 %8.8lux R2 %8.8lux R1 %8.8lux R0 %8.8lux\n",
+ ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
+ iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
+}
+
+void
+setkernur(Ureg *ureg, Proc *p)
+{
+ ureg->pc = p->sched.pc;
+ ureg->sp = p->sched.sp + 4;
+ ureg->r14 = (uintptr) sched;
+}
+
+void
+setregisters(Ureg* ureg, char* pureg, char* uva, int n)
+{
+ ulong v;
+
+ v = ureg->psr;
+ memmove(pureg, uva, n);
+ ureg->psr = ureg->psr & 0xf80f0000 | v & 0x07f0ffff;
+}
+
+void
+callwithureg(void (*f) (Ureg *))
+{
+ Ureg u;
+
+ u.pc = getcallerpc(&f);
+ u.sp = (uintptr) &f - 4;
+ f(&u);
+}
+
+uintptr
+userpc(void)
+{
+ Ureg *ur;
+
+ ur = up->dbgreg;
+ return ur->pc;
+}
+
+uintptr
+dbgpc(Proc *)
+{
+ Ureg *ur;
+
+ ur = up->dbgreg;
+ if(ur == nil)
+ return 0;
+ return ur->pc;
+}
+
+void
+procsave(Proc *p)
+{
+ uvlong t;
+
+ if(p->fpstate == FPactive){
+ if(p->state == Moribund)
+ fpclear();
+ else
+ fpsave(p->fpsave);
+ p->fpstate = FPinactive;
+ }
+ cycles(&t);
+ p->kentry -= t;
+ p->pcycles += t;
+
+ l1switch(&m->l1, 0);
+}
+
+void
+procrestore(Proc *p)
+{
+ uvlong t;
+
+ if(p->kp)
+ return;
+
+ cycles(&t);
+ p->kentry += t;
+ p->pcycles -= t;
+}
+
+static void
+linkproc(void)
+{
+ spllo();
+ up->kpfun(up->kparg);
+ pexit("kproc dying", 0);
+}
+
+void
+kprocchild(Proc* p, void (*func)(void*), void* arg)
+{
+ p->sched.pc = (uintptr) linkproc;
+ p->sched.sp = (uintptr) p->kstack + KSTACK;
+
+ p->kpfun = func;
+ p->kparg = arg;
+}
+
+void
+forkchild(Proc *p, Ureg *ureg)
+{
+ Ureg *cureg;
+
+ p->sched.pc = (uintptr) forkret;
+ p->sched.sp = (uintptr) p->kstack + KSTACK - sizeof(Ureg);
+
+ cureg = (Ureg*) p->sched.sp;
+ memmove(cureg, ureg, sizeof(Ureg));
+ cureg->r0 = 0;
+
+ p->psstate = 0;
+ p->insyscall = 0;
+}
+
+uintptr
+execregs(uintptr entry, ulong ssize, ulong nargs)
+{
+ ulong *sp;
+ Ureg *ureg;
+
+ sp = (ulong*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ureg = up->dbgreg;
+ ureg->sp = (uintptr) sp;
+ ureg->pc = entry;
+ ureg->r14 = 0;
+ return USTKTOP-sizeof(Tos);
+}