17bb09086SDavid du Colombier #include "u.h"
27bb09086SDavid du Colombier #include "../port/lib.h"
37bb09086SDavid du Colombier #include "mem.h"
47bb09086SDavid du Colombier #include "dat.h"
57bb09086SDavid du Colombier #include "fns.h"
67bb09086SDavid du Colombier #include "../port/error.h"
77bb09086SDavid du Colombier #include "../port/systab.h"
87bb09086SDavid du Colombier
97bb09086SDavid du Colombier #include <tos.h>
107bb09086SDavid du Colombier #include "ureg.h"
117bb09086SDavid du Colombier
127bb09086SDavid du Colombier #include "arm.h"
137bb09086SDavid du Colombier
147bb09086SDavid du Colombier typedef struct {
157bb09086SDavid du Colombier uintptr ip;
167bb09086SDavid du Colombier Ureg* arg0;
177bb09086SDavid du Colombier char* arg1;
187bb09086SDavid du Colombier char msg[ERRMAX];
197bb09086SDavid du Colombier Ureg* old;
207bb09086SDavid du Colombier Ureg ureg;
217bb09086SDavid du Colombier } NFrame;
227bb09086SDavid du Colombier
237bb09086SDavid du Colombier /*
247bb09086SDavid du Colombier * Return user to state before notify()
257bb09086SDavid du Colombier */
267bb09086SDavid du Colombier static void
noted(Ureg * cur,uintptr arg0)277bb09086SDavid du Colombier noted(Ureg* cur, uintptr arg0)
287bb09086SDavid du Colombier {
297bb09086SDavid du Colombier NFrame *nf;
307bb09086SDavid du Colombier Ureg *nur;
317bb09086SDavid du Colombier
327bb09086SDavid du Colombier qlock(&up->debug);
337bb09086SDavid du Colombier if(arg0 != NRSTR && !up->notified){
347bb09086SDavid du Colombier qunlock(&up->debug);
357bb09086SDavid du Colombier pprint("call to noted() when not notified\n");
367bb09086SDavid du Colombier pexit("Suicide", 0);
377bb09086SDavid du Colombier }
387bb09086SDavid du Colombier up->notified = 0;
397bb09086SDavid du Colombier fpunoted();
407bb09086SDavid du Colombier
417bb09086SDavid du Colombier nf = up->ureg;
427bb09086SDavid du Colombier
437bb09086SDavid du Colombier /* sanity clause */
447bb09086SDavid du Colombier if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
457bb09086SDavid du Colombier qunlock(&up->debug);
462f205b96SDavid du Colombier pprint("bad ureg in noted %#p\n", nf);
477bb09086SDavid du Colombier pexit("Suicide", 0);
487bb09086SDavid du Colombier }
497bb09086SDavid du Colombier
507bb09086SDavid du Colombier /* don't let user change system flags */
517bb09086SDavid du Colombier nur = &nf->ureg;
527bb09086SDavid du Colombier nur->psr &= PsrMask|PsrDfiq|PsrDirq;
537bb09086SDavid du Colombier nur->psr |= (cur->psr & ~(PsrMask|PsrDfiq|PsrDirq));
547bb09086SDavid du Colombier
557bb09086SDavid du Colombier memmove(cur, nur, sizeof(Ureg));
567bb09086SDavid du Colombier
577bb09086SDavid du Colombier switch((int)arg0){
587bb09086SDavid du Colombier case NCONT:
597bb09086SDavid du Colombier case NRSTR:
60472c7937SDavid du Colombier if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
617bb09086SDavid du Colombier qunlock(&up->debug);
627bb09086SDavid du Colombier pprint("suicide: trap in noted\n");
637bb09086SDavid du Colombier pexit("Suicide", 0);
647bb09086SDavid du Colombier }
657bb09086SDavid du Colombier up->ureg = nf->old;
667bb09086SDavid du Colombier qunlock(&up->debug);
677bb09086SDavid du Colombier break;
687bb09086SDavid du Colombier case NSAVE:
69472c7937SDavid du Colombier if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
707bb09086SDavid du Colombier qunlock(&up->debug);
717bb09086SDavid du Colombier pprint("suicide: trap in noted\n");
727bb09086SDavid du Colombier pexit("Suicide", 0);
737bb09086SDavid du Colombier }
747bb09086SDavid du Colombier qunlock(&up->debug);
757bb09086SDavid du Colombier
767bb09086SDavid du Colombier splhi();
777bb09086SDavid du Colombier nf->arg1 = nf->msg;
787bb09086SDavid du Colombier nf->arg0 = &nf->ureg;
797bb09086SDavid du Colombier nf->ip = 0;
807bb09086SDavid du Colombier cur->sp = PTR2UINT(nf);
81*c02f0a41SDavid du Colombier cur->r0 = PTR2UINT(nf->arg0);
827bb09086SDavid du Colombier break;
837bb09086SDavid du Colombier default:
847bb09086SDavid du Colombier pprint("unknown noted arg %#p\n", arg0);
857bb09086SDavid du Colombier up->lastnote.flag = NDebug;
867bb09086SDavid du Colombier /*FALLTHROUGH*/
877bb09086SDavid du Colombier case NDFLT:
887bb09086SDavid du Colombier if(up->lastnote.flag == NDebug){
897bb09086SDavid du Colombier qunlock(&up->debug);
907bb09086SDavid du Colombier pprint("suicide: %s\n", up->lastnote.msg);
917bb09086SDavid du Colombier }
927bb09086SDavid du Colombier else
937bb09086SDavid du Colombier qunlock(&up->debug);
947bb09086SDavid du Colombier pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
957bb09086SDavid du Colombier }
967bb09086SDavid du Colombier }
977bb09086SDavid du Colombier
987bb09086SDavid du Colombier /*
997bb09086SDavid du Colombier * Call user, if necessary, with note.
1007bb09086SDavid du Colombier * Pass user the Ureg struct and the note on his stack.
1017bb09086SDavid du Colombier */
1027bb09086SDavid du Colombier int
notify(Ureg * ureg)1037bb09086SDavid du Colombier notify(Ureg* ureg)
1047bb09086SDavid du Colombier {
1057bb09086SDavid du Colombier int l;
1067bb09086SDavid du Colombier Note *n;
1077bb09086SDavid du Colombier u32int s;
1087bb09086SDavid du Colombier uintptr sp;
1097bb09086SDavid du Colombier NFrame *nf;
1107bb09086SDavid du Colombier
1117bb09086SDavid du Colombier if(up->procctl)
1127bb09086SDavid du Colombier procctl(up);
1137bb09086SDavid du Colombier if(up->nnote == 0)
1147bb09086SDavid du Colombier return 0;
1157bb09086SDavid du Colombier
1167bb09086SDavid du Colombier fpunotify(ureg);
1177bb09086SDavid du Colombier
1187bb09086SDavid du Colombier s = spllo();
1197bb09086SDavid du Colombier qlock(&up->debug);
1207bb09086SDavid du Colombier
1217bb09086SDavid du Colombier up->notepending = 0;
1227bb09086SDavid du Colombier n = &up->note[0];
1237bb09086SDavid du Colombier if(strncmp(n->msg, "sys:", 4) == 0){
1247bb09086SDavid du Colombier l = strlen(n->msg);
1257bb09086SDavid du Colombier if(l > ERRMAX-23) /* " pc=0x0123456789abcdef\0" */
1267bb09086SDavid du Colombier l = ERRMAX-23;
1277bb09086SDavid du Colombier snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc);
1287bb09086SDavid du Colombier }
1297bb09086SDavid du Colombier
1307bb09086SDavid du Colombier if(n->flag != NUser && (up->notified || up->notify == 0)){
1317bb09086SDavid du Colombier if(n->flag == NDebug)
1327bb09086SDavid du Colombier pprint("suicide: %s\n", n->msg);
1337bb09086SDavid du Colombier qunlock(&up->debug);
1347bb09086SDavid du Colombier pexit(n->msg, n->flag != NDebug);
1357bb09086SDavid du Colombier }
1367bb09086SDavid du Colombier
1377bb09086SDavid du Colombier if(up->notified){
1387bb09086SDavid du Colombier qunlock(&up->debug);
1397bb09086SDavid du Colombier splhi();
1407bb09086SDavid du Colombier return 0;
1417bb09086SDavid du Colombier }
1427bb09086SDavid du Colombier
1437bb09086SDavid du Colombier if(up->notify == nil){
1447bb09086SDavid du Colombier qunlock(&up->debug);
1457bb09086SDavid du Colombier pexit(n->msg, n->flag != NDebug);
1467bb09086SDavid du Colombier }
1477bb09086SDavid du Colombier if(!okaddr(PTR2UINT(up->notify), 1, 0)){
1487bb09086SDavid du Colombier pprint("suicide: notify function address %#p\n", up->notify);
1497bb09086SDavid du Colombier qunlock(&up->debug);
1507bb09086SDavid du Colombier pexit("Suicide", 0);
1517bb09086SDavid du Colombier }
1527bb09086SDavid du Colombier
1537bb09086SDavid du Colombier sp = ureg->sp - sizeof(NFrame);
1547bb09086SDavid du Colombier if(!okaddr(sp, sizeof(NFrame), 1)){
1557bb09086SDavid du Colombier qunlock(&up->debug);
1562f205b96SDavid du Colombier pprint("suicide: notify stack address %#p\n", sp);
1577bb09086SDavid du Colombier pexit("Suicide", 0);
1587bb09086SDavid du Colombier }
1597bb09086SDavid du Colombier
1607bb09086SDavid du Colombier nf = UINT2PTR(sp);
1617bb09086SDavid du Colombier memmove(&nf->ureg, ureg, sizeof(Ureg));
1627bb09086SDavid du Colombier nf->old = up->ureg;
1637bb09086SDavid du Colombier up->ureg = nf;
1647bb09086SDavid du Colombier memmove(nf->msg, up->note[0].msg, ERRMAX);
1657bb09086SDavid du Colombier nf->arg1 = nf->msg;
1667bb09086SDavid du Colombier nf->arg0 = &nf->ureg;
167ddc74443SDavid du Colombier ureg->r0 = PTR2UINT(nf->arg0);
1687bb09086SDavid du Colombier nf->ip = 0;
1697bb09086SDavid du Colombier
1707bb09086SDavid du Colombier ureg->sp = sp;
1717bb09086SDavid du Colombier ureg->pc = PTR2UINT(up->notify);
1727bb09086SDavid du Colombier up->notified = 1;
1737bb09086SDavid du Colombier up->nnote--;
1747bb09086SDavid du Colombier memmove(&up->lastnote, &up->note[0], sizeof(Note));
1757bb09086SDavid du Colombier memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
1767bb09086SDavid du Colombier
1777bb09086SDavid du Colombier qunlock(&up->debug);
1787bb09086SDavid du Colombier splx(s);
1797bb09086SDavid du Colombier
1807bb09086SDavid du Colombier return 1;
1817bb09086SDavid du Colombier }
1827bb09086SDavid du Colombier
1837bb09086SDavid du Colombier void
syscall(Ureg * ureg)1847bb09086SDavid du Colombier syscall(Ureg* ureg)
1857bb09086SDavid du Colombier {
1867bb09086SDavid du Colombier char *e;
1877bb09086SDavid du Colombier u32int s;
1887bb09086SDavid du Colombier ulong sp;
1897bb09086SDavid du Colombier long ret;
1907bb09086SDavid du Colombier int i, scallnr;
1917bb09086SDavid du Colombier
1927bb09086SDavid du Colombier if(!userureg(ureg))
1937bb09086SDavid du Colombier panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
1947bb09086SDavid du Colombier ureg->pc, ureg->r14, ureg->psr);
1957bb09086SDavid du Colombier
1967bb09086SDavid du Colombier cycles(&up->kentry);
1977bb09086SDavid du Colombier
1987bb09086SDavid du Colombier m->syscall++;
1997bb09086SDavid du Colombier up->insyscall = 1;
2007bb09086SDavid du Colombier up->pc = ureg->pc;
2017bb09086SDavid du Colombier up->dbgreg = ureg;
2027bb09086SDavid du Colombier
2037bb09086SDavid du Colombier if(up->procctl == Proc_tracesyscall){
2047bb09086SDavid du Colombier up->procctl = Proc_stopme;
2057bb09086SDavid du Colombier procctl(up);
2067bb09086SDavid du Colombier }
2077bb09086SDavid du Colombier
2087bb09086SDavid du Colombier scallnr = ureg->r0;
2097bb09086SDavid du Colombier up->scallnr = scallnr;
2107bb09086SDavid du Colombier if(scallnr == RFORK)
2117bb09086SDavid du Colombier fpusysrfork(ureg);
2127bb09086SDavid du Colombier spllo();
2137bb09086SDavid du Colombier
2147bb09086SDavid du Colombier sp = ureg->sp;
2157bb09086SDavid du Colombier up->nerrlab = 0;
2167bb09086SDavid du Colombier ret = -1;
2177bb09086SDavid du Colombier if(!waserror()){
2187bb09086SDavid du Colombier if(scallnr >= nsyscall){
2197bb09086SDavid du Colombier pprint("bad sys call number %d pc %#lux\n",
2207bb09086SDavid du Colombier scallnr, ureg->pc);
2217bb09086SDavid du Colombier postnote(up, 1, "sys: bad sys call", NDebug);
2227bb09086SDavid du Colombier error(Ebadarg);
2237bb09086SDavid du Colombier }
2247bb09086SDavid du Colombier
2257bb09086SDavid du Colombier if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
2267bb09086SDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0);
2277bb09086SDavid du Colombier
2287bb09086SDavid du Colombier up->s = *((Sargs*)(sp+BY2WD));
2297bb09086SDavid du Colombier up->psstate = sysctab[scallnr];
2307bb09086SDavid du Colombier
2317bb09086SDavid du Colombier /* iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */
2327bb09086SDavid du Colombier
2337bb09086SDavid du Colombier ret = systab[scallnr](up->s.args);
2347bb09086SDavid du Colombier poperror();
2357bb09086SDavid du Colombier }else{
2367bb09086SDavid du Colombier /* failure: save the error buffer for errstr */
2377bb09086SDavid du Colombier e = up->syserrstr;
2387bb09086SDavid du Colombier up->syserrstr = up->errstr;
2397bb09086SDavid du Colombier up->errstr = e;
2407bb09086SDavid du Colombier }
2417bb09086SDavid du Colombier if(up->nerrlab){
2427bb09086SDavid du Colombier print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
2437bb09086SDavid du Colombier for(i = 0; i < NERR; i++)
2447bb09086SDavid du Colombier print("sp=%#p pc=%#p\n",
2457bb09086SDavid du Colombier up->errlab[i].sp, up->errlab[i].pc);
2467bb09086SDavid du Colombier panic("error stack");
2477bb09086SDavid du Colombier }
2487bb09086SDavid du Colombier
2497bb09086SDavid du Colombier /*
2507bb09086SDavid du Colombier * Put return value in frame. On the x86 the syscall is
2517bb09086SDavid du Colombier * just another trap and the return value from syscall is
2527bb09086SDavid du Colombier * ignored. On other machines the return value is put into
2537bb09086SDavid du Colombier * the results register by caller of syscall.
2547bb09086SDavid du Colombier */
2557bb09086SDavid du Colombier ureg->r0 = ret;
2567bb09086SDavid du Colombier
2577bb09086SDavid du Colombier if(up->procctl == Proc_tracesyscall){
2587bb09086SDavid du Colombier up->procctl = Proc_stopme;
2597bb09086SDavid du Colombier s = splhi();
2607bb09086SDavid du Colombier procctl(up);
2617bb09086SDavid du Colombier splx(s);
2627bb09086SDavid du Colombier }
2637bb09086SDavid du Colombier
2647bb09086SDavid du Colombier up->insyscall = 0;
2657bb09086SDavid du Colombier up->psstate = 0;
2667bb09086SDavid du Colombier
2677bb09086SDavid du Colombier if(scallnr == NOTED)
2687bb09086SDavid du Colombier noted(ureg, *(ulong*)(sp+BY2WD));
2697bb09086SDavid du Colombier
2707bb09086SDavid du Colombier splhi();
2717bb09086SDavid du Colombier if(scallnr != RFORK && (up->procctl || up->nnote))
2727bb09086SDavid du Colombier notify(ureg);
2737bb09086SDavid du Colombier
2747bb09086SDavid du Colombier /* if we delayed sched because we held a lock, sched now */
2757bb09086SDavid du Colombier if(up->delaysched){
2767bb09086SDavid du Colombier sched();
2777bb09086SDavid du Colombier splhi();
2787bb09086SDavid du Colombier }
2797bb09086SDavid du Colombier kexit(ureg);
2807bb09086SDavid du Colombier }
2817bb09086SDavid du Colombier
2827bb09086SDavid du Colombier long /* void* */
execregs(ulong entry,ulong ssize,ulong nargs)2837bb09086SDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
2847bb09086SDavid du Colombier {
2857bb09086SDavid du Colombier ulong *sp;
2867bb09086SDavid du Colombier Ureg *ureg;
2877bb09086SDavid du Colombier
2887bb09086SDavid du Colombier sp = (ulong*)(USTKTOP - ssize);
2897bb09086SDavid du Colombier *--sp = nargs;
2907bb09086SDavid du Colombier
2917bb09086SDavid du Colombier ureg = up->dbgreg;
2927bb09086SDavid du Colombier // memset(ureg, 0, 15*sizeof(ulong));
2937bb09086SDavid du Colombier ureg->r13 = (ulong)sp;
2947bb09086SDavid du Colombier ureg->pc = entry;
2957bb09086SDavid du Colombier //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs);
2967bb09086SDavid du Colombier
2977bb09086SDavid du Colombier /*
2987bb09086SDavid du Colombier * return the address of kernel/user shared data
2997bb09086SDavid du Colombier * (e.g. clock stuff)
3007bb09086SDavid du Colombier */
3017bb09086SDavid du Colombier return USTKTOP-sizeof(Tos);
3027bb09086SDavid du Colombier }
3037bb09086SDavid du Colombier
3047bb09086SDavid du Colombier void
sysprocsetup(Proc * p)3057bb09086SDavid du Colombier sysprocsetup(Proc* p)
3067bb09086SDavid du Colombier {
3077bb09086SDavid du Colombier fpusysprocsetup(p);
3087bb09086SDavid du Colombier }
3097bb09086SDavid du Colombier
3107bb09086SDavid du Colombier /*
3117bb09086SDavid du Colombier * Craft a return frame which will cause the child to pop out of
3127bb09086SDavid du Colombier * the scheduler in user mode with the return register zero. Set
3137bb09086SDavid du Colombier * pc to point to a l.s return function.
3147bb09086SDavid du Colombier */
3157bb09086SDavid du Colombier void
forkchild(Proc * p,Ureg * ureg)3167bb09086SDavid du Colombier forkchild(Proc *p, Ureg *ureg)
3177bb09086SDavid du Colombier {
3187bb09086SDavid du Colombier Ureg *cureg;
3197bb09086SDavid du Colombier
3207bb09086SDavid du Colombier //print("%lud setting up for forking child %lud\n", up->pid, p->pid);
3217bb09086SDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
3227bb09086SDavid du Colombier p->sched.pc = (ulong)forkret;
3237bb09086SDavid du Colombier
3247bb09086SDavid du Colombier cureg = (Ureg*)(p->sched.sp);
3257bb09086SDavid du Colombier memmove(cureg, ureg, sizeof(Ureg));
3267bb09086SDavid du Colombier
3277bb09086SDavid du Colombier /* syscall returns 0 for child */
3287bb09086SDavid du Colombier cureg->r0 = 0;
3297bb09086SDavid du Colombier
3307bb09086SDavid du Colombier /* Things from bottom of syscall which were never executed */
3317bb09086SDavid du Colombier p->psstate = 0;
3327bb09086SDavid du Colombier p->insyscall = 0;
333b1c4f505SDavid du Colombier
334b1c4f505SDavid du Colombier fpusysrforkchild(p, cureg, up);
3357bb09086SDavid du Colombier }
336