xref: /plan9/sys/src/9/omap/syscall.c (revision c02f0a41ad5684e95822c8ca8364ded8ae8e0281)
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