1154abd99SDavid du Colombier #include "u.h" 2154abd99SDavid du Colombier #include "../port/lib.h" 3154abd99SDavid du Colombier #include "mem.h" 4154abd99SDavid du Colombier #include "dat.h" 5154abd99SDavid du Colombier #include "fns.h" 6154abd99SDavid du Colombier #include "../port/error.h" 7154abd99SDavid du Colombier #include "../port/systab.h" 8154abd99SDavid du Colombier 9154abd99SDavid du Colombier #include <tos.h> 10154abd99SDavid du Colombier #include "ureg.h" 11154abd99SDavid du Colombier 12154abd99SDavid du Colombier #include "arm.h" 13154abd99SDavid du Colombier 14154abd99SDavid du Colombier typedef struct { 15154abd99SDavid du Colombier uintptr ip; 16154abd99SDavid du Colombier Ureg* arg0; 17154abd99SDavid du Colombier char* arg1; 18154abd99SDavid du Colombier char msg[ERRMAX]; 19154abd99SDavid du Colombier Ureg* old; 20154abd99SDavid du Colombier Ureg ureg; 21154abd99SDavid du Colombier } NFrame; 22154abd99SDavid du Colombier 23154abd99SDavid du Colombier /* 24154abd99SDavid du Colombier * Return user to state before notify() 25154abd99SDavid du Colombier */ 26154abd99SDavid du Colombier static void 27154abd99SDavid du Colombier noted(Ureg* cur, uintptr arg0) 28154abd99SDavid du Colombier { 29154abd99SDavid du Colombier NFrame *nf; 30154abd99SDavid du Colombier Ureg *nur; 31154abd99SDavid du Colombier 32154abd99SDavid du Colombier qlock(&up->debug); 33154abd99SDavid du Colombier if(arg0 != NRSTR && !up->notified){ 34154abd99SDavid du Colombier qunlock(&up->debug); 35154abd99SDavid du Colombier pprint("call to noted() when not notified\n"); 36154abd99SDavid du Colombier pexit("Suicide", 0); 37154abd99SDavid du Colombier } 38154abd99SDavid du Colombier up->notified = 0; 39154abd99SDavid du Colombier fpunoted(); 40154abd99SDavid du Colombier 41154abd99SDavid du Colombier nf = up->ureg; 42154abd99SDavid du Colombier 43154abd99SDavid du Colombier /* sanity clause */ 44154abd99SDavid du Colombier if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){ 45154abd99SDavid du Colombier qunlock(&up->debug); 462f205b96SDavid du Colombier pprint("bad ureg in noted %#p\n", nf); 47154abd99SDavid du Colombier pexit("Suicide", 0); 48154abd99SDavid du Colombier } 49154abd99SDavid du Colombier 50154abd99SDavid du Colombier /* don't let user change system flags */ 51154abd99SDavid du Colombier nur = &nf->ureg; 52154abd99SDavid du Colombier nur->psr &= PsrMask|PsrDfiq|PsrDirq; 53154abd99SDavid du Colombier nur->psr |= (cur->psr & ~(PsrMask|PsrDfiq|PsrDirq)); 54154abd99SDavid du Colombier 55154abd99SDavid du Colombier memmove(cur, nur, sizeof(Ureg)); 56154abd99SDavid du Colombier 57154abd99SDavid du Colombier switch((int)arg0){ 58154abd99SDavid du Colombier case NCONT: 59154abd99SDavid du Colombier case NRSTR: 60472c7937SDavid du Colombier if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){ 61154abd99SDavid du Colombier qunlock(&up->debug); 62154abd99SDavid du Colombier pprint("suicide: trap in noted\n"); 63154abd99SDavid du Colombier pexit("Suicide", 0); 64154abd99SDavid du Colombier } 65154abd99SDavid du Colombier up->ureg = nf->old; 66154abd99SDavid du Colombier qunlock(&up->debug); 67154abd99SDavid du Colombier break; 68154abd99SDavid du Colombier case NSAVE: 69472c7937SDavid du Colombier if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){ 70154abd99SDavid du Colombier qunlock(&up->debug); 71154abd99SDavid du Colombier pprint("suicide: trap in noted\n"); 72154abd99SDavid du Colombier pexit("Suicide", 0); 73154abd99SDavid du Colombier } 74154abd99SDavid du Colombier qunlock(&up->debug); 75154abd99SDavid du Colombier 76154abd99SDavid du Colombier splhi(); 77154abd99SDavid du Colombier nf->arg1 = nf->msg; 78154abd99SDavid du Colombier nf->arg0 = &nf->ureg; 79154abd99SDavid du Colombier nf->ip = 0; 80154abd99SDavid du Colombier cur->sp = PTR2UINT(nf); 81154abd99SDavid du Colombier break; 82154abd99SDavid du Colombier default: 83154abd99SDavid du Colombier pprint("unknown noted arg %#p\n", arg0); 84154abd99SDavid du Colombier up->lastnote.flag = NDebug; 85154abd99SDavid du Colombier /*FALLTHROUGH*/ 86154abd99SDavid du Colombier case NDFLT: 87154abd99SDavid du Colombier if(up->lastnote.flag == NDebug){ 88154abd99SDavid du Colombier qunlock(&up->debug); 89154abd99SDavid du Colombier pprint("suicide: %s\n", up->lastnote.msg); 90154abd99SDavid du Colombier } 91154abd99SDavid du Colombier else 92154abd99SDavid du Colombier qunlock(&up->debug); 93154abd99SDavid du Colombier pexit(up->lastnote.msg, up->lastnote.flag != NDebug); 94154abd99SDavid du Colombier } 95154abd99SDavid du Colombier } 96154abd99SDavid du Colombier 97154abd99SDavid du Colombier /* 98154abd99SDavid du Colombier * Call user, if necessary, with note. 99154abd99SDavid du Colombier * Pass user the Ureg struct and the note on his stack. 100154abd99SDavid du Colombier */ 101154abd99SDavid du Colombier int 102154abd99SDavid du Colombier notify(Ureg* ureg) 103154abd99SDavid du Colombier { 104154abd99SDavid du Colombier int l; 105154abd99SDavid du Colombier Note *n; 106154abd99SDavid du Colombier u32int s; 107154abd99SDavid du Colombier uintptr sp; 108154abd99SDavid du Colombier NFrame *nf; 109154abd99SDavid du Colombier 110154abd99SDavid du Colombier if(up->procctl) 111154abd99SDavid du Colombier procctl(up); 112154abd99SDavid du Colombier if(up->nnote == 0) 113154abd99SDavid du Colombier return 0; 114154abd99SDavid du Colombier 115154abd99SDavid du Colombier fpunotify(ureg); 116154abd99SDavid du Colombier 117154abd99SDavid du Colombier s = spllo(); 118154abd99SDavid du Colombier qlock(&up->debug); 119154abd99SDavid du Colombier 120154abd99SDavid du Colombier up->notepending = 0; 121154abd99SDavid du Colombier n = &up->note[0]; 122154abd99SDavid du Colombier if(strncmp(n->msg, "sys:", 4) == 0){ 123154abd99SDavid du Colombier l = strlen(n->msg); 124154abd99SDavid du Colombier if(l > ERRMAX-23) /* " pc=0x0123456789abcdef\0" */ 125154abd99SDavid du Colombier l = ERRMAX-23; 1267bb09086SDavid du Colombier snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc); 127154abd99SDavid du Colombier } 128154abd99SDavid du Colombier 129154abd99SDavid du Colombier if(n->flag != NUser && (up->notified || up->notify == 0)){ 130154abd99SDavid du Colombier if(n->flag == NDebug) 131154abd99SDavid du Colombier pprint("suicide: %s\n", n->msg); 132154abd99SDavid du Colombier qunlock(&up->debug); 133154abd99SDavid du Colombier pexit(n->msg, n->flag != NDebug); 134154abd99SDavid du Colombier } 135154abd99SDavid du Colombier 136154abd99SDavid du Colombier if(up->notified){ 137154abd99SDavid du Colombier qunlock(&up->debug); 138154abd99SDavid du Colombier splhi(); 139154abd99SDavid du Colombier return 0; 140154abd99SDavid du Colombier } 141154abd99SDavid du Colombier 142154abd99SDavid du Colombier if(up->notify == nil){ 143154abd99SDavid du Colombier qunlock(&up->debug); 144154abd99SDavid du Colombier pexit(n->msg, n->flag != NDebug); 145154abd99SDavid du Colombier } 146154abd99SDavid du Colombier if(!okaddr(PTR2UINT(up->notify), 1, 0)){ 147154abd99SDavid du Colombier pprint("suicide: notify function address %#p\n", up->notify); 148154abd99SDavid du Colombier qunlock(&up->debug); 149154abd99SDavid du Colombier pexit("Suicide", 0); 150154abd99SDavid du Colombier } 151154abd99SDavid du Colombier 152154abd99SDavid du Colombier sp = ureg->sp - sizeof(NFrame); 153154abd99SDavid du Colombier if(!okaddr(sp, sizeof(NFrame), 1)){ 154154abd99SDavid du Colombier qunlock(&up->debug); 1552f205b96SDavid du Colombier pprint("suicide: notify stack address %#p\n", sp); 156154abd99SDavid du Colombier pexit("Suicide", 0); 157154abd99SDavid du Colombier } 158154abd99SDavid du Colombier 159154abd99SDavid du Colombier nf = UINT2PTR(sp); 160154abd99SDavid du Colombier memmove(&nf->ureg, ureg, sizeof(Ureg)); 161154abd99SDavid du Colombier nf->old = up->ureg; 162154abd99SDavid du Colombier up->ureg = nf; 163154abd99SDavid du Colombier memmove(nf->msg, up->note[0].msg, ERRMAX); 164154abd99SDavid du Colombier nf->arg1 = nf->msg; 165154abd99SDavid du Colombier nf->arg0 = &nf->ureg; 166*ddc74443SDavid du Colombier ureg->r0 = PTR2UINT(nf->arg0); 167154abd99SDavid du Colombier nf->ip = 0; 168154abd99SDavid du Colombier 169154abd99SDavid du Colombier ureg->sp = sp; 170154abd99SDavid du Colombier ureg->pc = PTR2UINT(up->notify); 171154abd99SDavid du Colombier up->notified = 1; 172154abd99SDavid du Colombier up->nnote--; 173154abd99SDavid du Colombier memmove(&up->lastnote, &up->note[0], sizeof(Note)); 174154abd99SDavid du Colombier memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 175154abd99SDavid du Colombier 176154abd99SDavid du Colombier qunlock(&up->debug); 177154abd99SDavid du Colombier splx(s); 178154abd99SDavid du Colombier 179154abd99SDavid du Colombier return 1; 180154abd99SDavid du Colombier } 181154abd99SDavid du Colombier 182154abd99SDavid du Colombier void 183154abd99SDavid du Colombier syscall(Ureg* ureg) 184154abd99SDavid du Colombier { 185154abd99SDavid du Colombier char *e; 186154abd99SDavid du Colombier u32int s; 187154abd99SDavid du Colombier ulong sp; 188154abd99SDavid du Colombier long ret; 189154abd99SDavid du Colombier int i, scallnr; 190fcbb35d1SDavid du Colombier vlong startns, stopns; 191154abd99SDavid du Colombier 192154abd99SDavid du Colombier if(!userureg(ureg)) 1937bb09086SDavid du Colombier panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux", 194154abd99SDavid du Colombier ureg->pc, ureg->r14, ureg->psr); 195154abd99SDavid du Colombier 196154abd99SDavid du Colombier cycles(&up->kentry); 197154abd99SDavid du Colombier 198154abd99SDavid du Colombier m->syscall++; 199154abd99SDavid du Colombier up->insyscall = 1; 200154abd99SDavid du Colombier up->pc = ureg->pc; 201154abd99SDavid du Colombier up->dbgreg = ureg; 202154abd99SDavid du Colombier 203154abd99SDavid du Colombier scallnr = ureg->r0; 204154abd99SDavid du Colombier up->scallnr = scallnr; 205154abd99SDavid du Colombier if(scallnr == RFORK) 206154abd99SDavid du Colombier fpusysrfork(ureg); 207154abd99SDavid du Colombier spllo(); 208154abd99SDavid du Colombier sp = ureg->sp; 209fcbb35d1SDavid du Colombier 210fcbb35d1SDavid du Colombier if(up->procctl == Proc_tracesyscall){ 211fcbb35d1SDavid du Colombier /* 212fcbb35d1SDavid du Colombier * Redundant validaddr. Do we care? 213fcbb35d1SDavid du Colombier * Tracing syscalls is not exactly a fast path... 214fcbb35d1SDavid du Colombier * Beware, validaddr currently does a pexit rather 215fcbb35d1SDavid du Colombier * than an error if there's a problem; that might 216fcbb35d1SDavid du Colombier * change in the future. 217fcbb35d1SDavid du Colombier */ 218fcbb35d1SDavid du Colombier if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) 219fcbb35d1SDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0); 220fcbb35d1SDavid du Colombier 221472c7937SDavid du Colombier syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD)); 222fcbb35d1SDavid du Colombier up->procctl = Proc_stopme; 223fcbb35d1SDavid du Colombier procctl(up); 224fcbb35d1SDavid du Colombier if (up->syscalltrace) 225fcbb35d1SDavid du Colombier free(up->syscalltrace); 226fcbb35d1SDavid du Colombier up->syscalltrace = nil; 227fcbb35d1SDavid du Colombier } 228fcbb35d1SDavid du Colombier 229154abd99SDavid du Colombier up->nerrlab = 0; 230154abd99SDavid du Colombier ret = -1; 231fcbb35d1SDavid du Colombier startns = todget(nil); 232154abd99SDavid du Colombier if(!waserror()){ 233154abd99SDavid du Colombier if(scallnr >= nsyscall){ 2347bb09086SDavid du Colombier pprint("bad sys call number %d pc %#lux\n", 235154abd99SDavid du Colombier scallnr, ureg->pc); 236154abd99SDavid du Colombier postnote(up, 1, "sys: bad sys call", NDebug); 237154abd99SDavid du Colombier error(Ebadarg); 238154abd99SDavid du Colombier } 239154abd99SDavid du Colombier 240154abd99SDavid du Colombier if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) 241154abd99SDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0); 242154abd99SDavid du Colombier 243154abd99SDavid du Colombier up->s = *((Sargs*)(sp+BY2WD)); 244154abd99SDavid du Colombier up->psstate = sysctab[scallnr]; 245154abd99SDavid du Colombier 246154abd99SDavid du Colombier /* iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */ 247154abd99SDavid du Colombier 248154abd99SDavid du Colombier ret = systab[scallnr](up->s.args); 249154abd99SDavid du Colombier poperror(); 250154abd99SDavid du Colombier }else{ 251154abd99SDavid du Colombier /* failure: save the error buffer for errstr */ 252154abd99SDavid du Colombier e = up->syserrstr; 253154abd99SDavid du Colombier up->syserrstr = up->errstr; 254154abd99SDavid du Colombier up->errstr = e; 255154abd99SDavid du Colombier } 256154abd99SDavid du Colombier if(up->nerrlab){ 257154abd99SDavid du Colombier print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab); 258154abd99SDavid du Colombier for(i = 0; i < NERR; i++) 259154abd99SDavid du Colombier print("sp=%#p pc=%#p\n", 260154abd99SDavid du Colombier up->errlab[i].sp, up->errlab[i].pc); 261154abd99SDavid du Colombier panic("error stack"); 262154abd99SDavid du Colombier } 263154abd99SDavid du Colombier 264154abd99SDavid du Colombier /* 265154abd99SDavid du Colombier * Put return value in frame. On the x86 the syscall is 266154abd99SDavid du Colombier * just another trap and the return value from syscall is 267154abd99SDavid du Colombier * ignored. On other machines the return value is put into 268154abd99SDavid du Colombier * the results register by caller of syscall. 269154abd99SDavid du Colombier */ 270154abd99SDavid du Colombier ureg->r0 = ret; 271154abd99SDavid du Colombier 272154abd99SDavid du Colombier if(up->procctl == Proc_tracesyscall){ 273fcbb35d1SDavid du Colombier stopns = todget(nil); 274154abd99SDavid du Colombier up->procctl = Proc_stopme; 275472c7937SDavid du Colombier sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns); 276154abd99SDavid du Colombier s = splhi(); 277154abd99SDavid du Colombier procctl(up); 278154abd99SDavid du Colombier splx(s); 279fcbb35d1SDavid du Colombier if(up->syscalltrace) 280fcbb35d1SDavid du Colombier free(up->syscalltrace); 281fcbb35d1SDavid du Colombier up->syscalltrace = nil; 282154abd99SDavid du Colombier } 283154abd99SDavid du Colombier 284154abd99SDavid du Colombier up->insyscall = 0; 285154abd99SDavid du Colombier up->psstate = 0; 286154abd99SDavid du Colombier 287154abd99SDavid du Colombier if(scallnr == NOTED) 288154abd99SDavid du Colombier noted(ureg, *(ulong*)(sp+BY2WD)); 289154abd99SDavid du Colombier 290154abd99SDavid du Colombier splhi(); 291154abd99SDavid du Colombier if(scallnr != RFORK && (up->procctl || up->nnote)) 292154abd99SDavid du Colombier notify(ureg); 293154abd99SDavid du Colombier 294154abd99SDavid du Colombier /* if we delayed sched because we held a lock, sched now */ 295154abd99SDavid du Colombier if(up->delaysched){ 296154abd99SDavid du Colombier sched(); 297154abd99SDavid du Colombier splhi(); 298154abd99SDavid du Colombier } 299154abd99SDavid du Colombier kexit(ureg); 300154abd99SDavid du Colombier } 301154abd99SDavid du Colombier 302b1c4f505SDavid du Colombier long 303154abd99SDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs) 304154abd99SDavid du Colombier { 305154abd99SDavid du Colombier ulong *sp; 306154abd99SDavid du Colombier Ureg *ureg; 307154abd99SDavid du Colombier 308154abd99SDavid du Colombier sp = (ulong*)(USTKTOP - ssize); 309154abd99SDavid du Colombier *--sp = nargs; 310154abd99SDavid du Colombier 311154abd99SDavid du Colombier ureg = up->dbgreg; 312154abd99SDavid du Colombier // memset(ureg, 0, 15*sizeof(ulong)); 313154abd99SDavid du Colombier ureg->r13 = (ulong)sp; 314154abd99SDavid du Colombier ureg->pc = entry; 315154abd99SDavid du Colombier //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs); 316154abd99SDavid du Colombier 317154abd99SDavid du Colombier /* 318154abd99SDavid du Colombier * return the address of kernel/user shared data 319154abd99SDavid du Colombier * (e.g. clock stuff) 320154abd99SDavid du Colombier */ 321154abd99SDavid du Colombier return USTKTOP-sizeof(Tos); 322154abd99SDavid du Colombier } 323154abd99SDavid du Colombier 324154abd99SDavid du Colombier void 325154abd99SDavid du Colombier sysprocsetup(Proc* p) 326154abd99SDavid du Colombier { 327154abd99SDavid du Colombier fpusysprocsetup(p); 328154abd99SDavid du Colombier } 329154abd99SDavid du Colombier 330154abd99SDavid du Colombier /* 331154abd99SDavid du Colombier * Craft a return frame which will cause the child to pop out of 332154abd99SDavid du Colombier * the scheduler in user mode with the return register zero. Set 333154abd99SDavid du Colombier * pc to point to a l.s return function. 334154abd99SDavid du Colombier */ 335154abd99SDavid du Colombier void 336154abd99SDavid du Colombier forkchild(Proc *p, Ureg *ureg) 337154abd99SDavid du Colombier { 338154abd99SDavid du Colombier Ureg *cureg; 339154abd99SDavid du Colombier 340154abd99SDavid du Colombier //print("%lud setting up for forking child %lud\n", up->pid, p->pid); 341154abd99SDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg); 342154abd99SDavid du Colombier p->sched.pc = (ulong)forkret; 343154abd99SDavid du Colombier 344154abd99SDavid du Colombier cureg = (Ureg*)(p->sched.sp); 345154abd99SDavid du Colombier memmove(cureg, ureg, sizeof(Ureg)); 346154abd99SDavid du Colombier 347154abd99SDavid du Colombier /* syscall returns 0 for child */ 348154abd99SDavid du Colombier cureg->r0 = 0; 349154abd99SDavid du Colombier 350154abd99SDavid du Colombier /* Things from bottom of syscall which were never executed */ 351154abd99SDavid du Colombier p->psstate = 0; 352154abd99SDavid du Colombier p->insyscall = 0; 353b1c4f505SDavid du Colombier 354b1c4f505SDavid du Colombier fpusysrforkchild(p, cureg, up); 355154abd99SDavid du Colombier } 356