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 pprint("bad ureg in noted %#p\n", nf); 46154abd99SDavid du Colombier qunlock(&up->debug); 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: 60*472c7937SDavid 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: 69*472c7937SDavid 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 pprint("suicide: notify stack address %#p\n", sp); 155154abd99SDavid du Colombier qunlock(&up->debug); 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; 166154abd99SDavid du Colombier nf->ip = 0; 167154abd99SDavid du Colombier 168154abd99SDavid du Colombier ureg->sp = sp; 169154abd99SDavid du Colombier ureg->pc = PTR2UINT(up->notify); 170154abd99SDavid du Colombier up->notified = 1; 171154abd99SDavid du Colombier up->nnote--; 172154abd99SDavid du Colombier memmove(&up->lastnote, &up->note[0], sizeof(Note)); 173154abd99SDavid du Colombier memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 174154abd99SDavid du Colombier 175154abd99SDavid du Colombier qunlock(&up->debug); 176154abd99SDavid du Colombier splx(s); 177154abd99SDavid du Colombier 178154abd99SDavid du Colombier return 1; 179154abd99SDavid du Colombier } 180154abd99SDavid du Colombier 181154abd99SDavid du Colombier void 182154abd99SDavid du Colombier syscall(Ureg* ureg) 183154abd99SDavid du Colombier { 184154abd99SDavid du Colombier char *e; 185154abd99SDavid du Colombier u32int s; 186154abd99SDavid du Colombier ulong sp; 187154abd99SDavid du Colombier long ret; 188154abd99SDavid du Colombier int i, scallnr; 189fcbb35d1SDavid du Colombier vlong startns, stopns; 190154abd99SDavid du Colombier 191154abd99SDavid du Colombier if(!userureg(ureg)) 1927bb09086SDavid du Colombier panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux", 193154abd99SDavid du Colombier ureg->pc, ureg->r14, ureg->psr); 194154abd99SDavid du Colombier 195154abd99SDavid du Colombier cycles(&up->kentry); 196154abd99SDavid du Colombier 197154abd99SDavid du Colombier m->syscall++; 198154abd99SDavid du Colombier up->insyscall = 1; 199154abd99SDavid du Colombier up->pc = ureg->pc; 200154abd99SDavid du Colombier up->dbgreg = ureg; 201154abd99SDavid du Colombier 202154abd99SDavid du Colombier scallnr = ureg->r0; 203154abd99SDavid du Colombier up->scallnr = scallnr; 204154abd99SDavid du Colombier if(scallnr == RFORK) 205154abd99SDavid du Colombier fpusysrfork(ureg); 206154abd99SDavid du Colombier spllo(); 207154abd99SDavid du Colombier sp = ureg->sp; 208fcbb35d1SDavid du Colombier 209fcbb35d1SDavid du Colombier if(up->procctl == Proc_tracesyscall){ 210fcbb35d1SDavid du Colombier /* 211fcbb35d1SDavid du Colombier * Redundant validaddr. Do we care? 212fcbb35d1SDavid du Colombier * Tracing syscalls is not exactly a fast path... 213fcbb35d1SDavid du Colombier * Beware, validaddr currently does a pexit rather 214fcbb35d1SDavid du Colombier * than an error if there's a problem; that might 215fcbb35d1SDavid du Colombier * change in the future. 216fcbb35d1SDavid du Colombier */ 217fcbb35d1SDavid du Colombier if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) 218fcbb35d1SDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0); 219fcbb35d1SDavid du Colombier 220*472c7937SDavid du Colombier syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD)); 221fcbb35d1SDavid du Colombier up->procctl = Proc_stopme; 222fcbb35d1SDavid du Colombier procctl(up); 223fcbb35d1SDavid du Colombier if (up->syscalltrace) 224fcbb35d1SDavid du Colombier free(up->syscalltrace); 225fcbb35d1SDavid du Colombier up->syscalltrace = nil; 226fcbb35d1SDavid du Colombier } 227fcbb35d1SDavid du Colombier 228154abd99SDavid du Colombier up->nerrlab = 0; 229154abd99SDavid du Colombier ret = -1; 230fcbb35d1SDavid du Colombier startns = todget(nil); 231154abd99SDavid du Colombier if(!waserror()){ 232154abd99SDavid du Colombier if(scallnr >= nsyscall){ 2337bb09086SDavid du Colombier pprint("bad sys call number %d pc %#lux\n", 234154abd99SDavid du Colombier scallnr, ureg->pc); 235154abd99SDavid du Colombier postnote(up, 1, "sys: bad sys call", NDebug); 236154abd99SDavid du Colombier error(Ebadarg); 237154abd99SDavid du Colombier } 238154abd99SDavid du Colombier 239154abd99SDavid du Colombier if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD)) 240154abd99SDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0); 241154abd99SDavid du Colombier 242154abd99SDavid du Colombier up->s = *((Sargs*)(sp+BY2WD)); 243154abd99SDavid du Colombier up->psstate = sysctab[scallnr]; 244154abd99SDavid du Colombier 245154abd99SDavid du Colombier /* iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */ 246154abd99SDavid du Colombier 247154abd99SDavid du Colombier ret = systab[scallnr](up->s.args); 248154abd99SDavid du Colombier poperror(); 249154abd99SDavid du Colombier }else{ 250154abd99SDavid du Colombier /* failure: save the error buffer for errstr */ 251154abd99SDavid du Colombier e = up->syserrstr; 252154abd99SDavid du Colombier up->syserrstr = up->errstr; 253154abd99SDavid du Colombier up->errstr = e; 254154abd99SDavid du Colombier } 255154abd99SDavid du Colombier if(up->nerrlab){ 256154abd99SDavid du Colombier print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab); 257154abd99SDavid du Colombier for(i = 0; i < NERR; i++) 258154abd99SDavid du Colombier print("sp=%#p pc=%#p\n", 259154abd99SDavid du Colombier up->errlab[i].sp, up->errlab[i].pc); 260154abd99SDavid du Colombier panic("error stack"); 261154abd99SDavid du Colombier } 262154abd99SDavid du Colombier 263154abd99SDavid du Colombier /* 264154abd99SDavid du Colombier * Put return value in frame. On the x86 the syscall is 265154abd99SDavid du Colombier * just another trap and the return value from syscall is 266154abd99SDavid du Colombier * ignored. On other machines the return value is put into 267154abd99SDavid du Colombier * the results register by caller of syscall. 268154abd99SDavid du Colombier */ 269154abd99SDavid du Colombier ureg->r0 = ret; 270154abd99SDavid du Colombier 271154abd99SDavid du Colombier if(up->procctl == Proc_tracesyscall){ 272fcbb35d1SDavid du Colombier stopns = todget(nil); 273154abd99SDavid du Colombier up->procctl = Proc_stopme; 274*472c7937SDavid du Colombier sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns); 275154abd99SDavid du Colombier s = splhi(); 276154abd99SDavid du Colombier procctl(up); 277154abd99SDavid du Colombier splx(s); 278fcbb35d1SDavid du Colombier if(up->syscalltrace) 279fcbb35d1SDavid du Colombier free(up->syscalltrace); 280fcbb35d1SDavid du Colombier up->syscalltrace = nil; 281154abd99SDavid du Colombier } 282154abd99SDavid du Colombier 283154abd99SDavid du Colombier up->insyscall = 0; 284154abd99SDavid du Colombier up->psstate = 0; 285154abd99SDavid du Colombier 286154abd99SDavid du Colombier if(scallnr == NOTED) 287154abd99SDavid du Colombier noted(ureg, *(ulong*)(sp+BY2WD)); 288154abd99SDavid du Colombier 289154abd99SDavid du Colombier splhi(); 290154abd99SDavid du Colombier if(scallnr != RFORK && (up->procctl || up->nnote)) 291154abd99SDavid du Colombier notify(ureg); 292154abd99SDavid du Colombier 293154abd99SDavid du Colombier /* if we delayed sched because we held a lock, sched now */ 294154abd99SDavid du Colombier if(up->delaysched){ 295154abd99SDavid du Colombier sched(); 296154abd99SDavid du Colombier splhi(); 297154abd99SDavid du Colombier } 298154abd99SDavid du Colombier kexit(ureg); 299154abd99SDavid du Colombier } 300154abd99SDavid du Colombier 301b1c4f505SDavid du Colombier long 302154abd99SDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs) 303154abd99SDavid du Colombier { 304154abd99SDavid du Colombier ulong *sp; 305154abd99SDavid du Colombier Ureg *ureg; 306154abd99SDavid du Colombier 307154abd99SDavid du Colombier sp = (ulong*)(USTKTOP - ssize); 308154abd99SDavid du Colombier *--sp = nargs; 309154abd99SDavid du Colombier 310154abd99SDavid du Colombier ureg = up->dbgreg; 311154abd99SDavid du Colombier // memset(ureg, 0, 15*sizeof(ulong)); 312154abd99SDavid du Colombier ureg->r13 = (ulong)sp; 313154abd99SDavid du Colombier ureg->pc = entry; 314154abd99SDavid du Colombier //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs); 315154abd99SDavid du Colombier 316154abd99SDavid du Colombier /* 317154abd99SDavid du Colombier * return the address of kernel/user shared data 318154abd99SDavid du Colombier * (e.g. clock stuff) 319154abd99SDavid du Colombier */ 320154abd99SDavid du Colombier return USTKTOP-sizeof(Tos); 321154abd99SDavid du Colombier } 322154abd99SDavid du Colombier 323154abd99SDavid du Colombier void 324154abd99SDavid du Colombier sysprocsetup(Proc* p) 325154abd99SDavid du Colombier { 326154abd99SDavid du Colombier fpusysprocsetup(p); 327154abd99SDavid du Colombier } 328154abd99SDavid du Colombier 329154abd99SDavid du Colombier /* 330154abd99SDavid du Colombier * Craft a return frame which will cause the child to pop out of 331154abd99SDavid du Colombier * the scheduler in user mode with the return register zero. Set 332154abd99SDavid du Colombier * pc to point to a l.s return function. 333154abd99SDavid du Colombier */ 334154abd99SDavid du Colombier void 335154abd99SDavid du Colombier forkchild(Proc *p, Ureg *ureg) 336154abd99SDavid du Colombier { 337154abd99SDavid du Colombier Ureg *cureg; 338154abd99SDavid du Colombier 339154abd99SDavid du Colombier //print("%lud setting up for forking child %lud\n", up->pid, p->pid); 340154abd99SDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg); 341154abd99SDavid du Colombier p->sched.pc = (ulong)forkret; 342154abd99SDavid du Colombier 343154abd99SDavid du Colombier cureg = (Ureg*)(p->sched.sp); 344154abd99SDavid du Colombier memmove(cureg, ureg, sizeof(Ureg)); 345154abd99SDavid du Colombier 346154abd99SDavid du Colombier /* syscall returns 0 for child */ 347154abd99SDavid du Colombier cureg->r0 = 0; 348154abd99SDavid du Colombier 349154abd99SDavid du Colombier /* Things from bottom of syscall which were never executed */ 350154abd99SDavid du Colombier p->psstate = 0; 351154abd99SDavid du Colombier p->insyscall = 0; 352b1c4f505SDavid du Colombier 353b1c4f505SDavid du Colombier fpusysrforkchild(p, cureg, up); 354154abd99SDavid du Colombier } 355