ref: a691c9111a69257e206ce895d35396d0f6225929
dir: /trap.c/
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "../port/systab.h" #include <tos.h> #include "ureg.h" int (*buserror)(Ureg*); /* SPSR bits user can modify */ #define USPSRMASK (0xFULL<<28) void trapinit(void) { } static char *traps[64] = { [0x00] "sys: trap: unknown", [0x01] "sys: trap: WFI or WFE instruction execution", [0x0E] "sys: trap: illegal execution state", [0x18] "sys: trap: illegal MSR/MRS access", [0x22] "sys: trap: misaligned pc", [0x26] "sys: trap: stack pointer misaligned", [0x30] "sys: breakpoint", [0x32] "sys: software step", [0x34] "sys: watchpoint", [0x3C] "sys: breakpoint", }; void trap(Ureg *ureg) { } void syscall(Ureg *ureg) { vlong startns, stopns; uintptr sp, ret; ulong scallnr; int i, s; char *e; if(!kenter(ureg)) panic("syscall from kernel"); fpukenter(ureg); m->syscall++; up->insyscall = 1; up->pc = ureg->pc; sp = ureg->sp; up->scallnr = scallnr = ureg->r0; spllo(); up->nerrlab = 0; startns = 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] == nil){ 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=%#p pc=%#p\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)); /* * normally, syscall() returns to forkret() * not restoring general registers when going * to userspace. to completely restore the * interrupted context, we have to return thru * noteret(). we override return pc to jump to * to it when returning form syscall() */ returnto(noteret); splhi(); up->fpstate &= ~FPillegal; } else splhi(); if(scallnr != RFORK && (up->procctl || up->nnote)) notify(ureg); if(up->delaysched){ sched(); splhi(); } kexit(ureg); fpukexit(ureg, nil); } int notify(Ureg *ureg) { uintptr sp; char *msg; if(up->procctl) procctl(); if(up->nnote == 0) return 0; spllo(); qlock(&up->debug); msg = popnote(ureg); if(msg == nil){ qunlock(&up->debug); splhi(); return 0; } sp = ureg->sp; sp -= 256; /* debugging: preserve context causing problem */ sp -= sizeof(Ureg); sp = STACKALIGN(sp); if(!okaddr((uintptr)up->notify, 1, 0) || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1) || ((uintptr) up->notify & 3) != 0 || (sp & 7) != 0){ qunlock(&up->debug); pprint("suicide: bad address in notify: handler=%#p sp=%#p\n", up->notify, sp); 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, msg, ERRMAX); sp -= 3*BY2WD; *(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD; *(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg; ureg->r0 = (uintptr) up->ureg; ureg->sp = sp; ureg->pc = (uintptr) up->notify; ureg->cause = 0; qunlock(&up->debug); splhi(); fpuprocsave(up); up->fpstate |= FPillegal; return 1; } void noted(Ureg *ureg, ulong arg0) { } static void faultnote(Ureg *ureg, char *access, uintptr addr) { } int userureg(Ureg* ureg) { return 0; } uintptr userpc(void) { Ureg *ur = up->dbgreg; return ur->pc; } uintptr dbgpc(Proc *) { Ureg *ur = up->dbgreg; if(ur == nil) return 0; return ur->pc; } void procfork(Proc *p) { fpuprocfork(p); p->tpidr = up->tpidr; } void procsetup(Proc *p) { } void procsave(Proc *p) { } void procrestore(Proc *p) { } void kprocchild(Proc *p, void (*entry)(void)) { } void forkchild(Proc *p, Ureg *ureg) { } uintptr execregs(uintptr entry, ulong ssize, ulong nargs) { return 0; } void evenaddr(uintptr addr) { } void callwithureg(void (*f) (Ureg *)) { } void setkernur(Ureg *ureg, Proc *p) { } void setupwatchpts(Proc*, Watchpt*, int) { } void setregisters(Ureg* ureg, char* pureg, char* uva, int n) { } static void dumpstackwithureg(Ureg *ureg) { } void dumpstack(void) { callwithureg(dumpstackwithureg); } void dumpregs(Ureg *ureg) { }