xref: /plan9-contrib/sys/src/9/vt4/syscall.c (revision f80d550d5bc48502e65b5d8bc4e8aaf82d4c6b0f)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "../port/systab.h"
8 
9 #include <tos.h>
10 #include "ureg.h"
11 
12 typedef struct {
13 	uintptr	pc;
14 	Ureg*	arg0;
15 	char*	arg1;
16 	char	msg[ERRMAX];
17 	Ureg*	old;
18 	Ureg	ureg;
19 } NFrame;
20 
21 /*
22  *   Return user to state before notify()
23  */
24 static void
noted(Ureg * cur,uintptr arg0)25 noted(Ureg* cur, uintptr arg0)
26 {
27 	Ureg *nur;
28 	NFrame *nf;
29 
30 	qlock(&up->debug);
31 	if(arg0 != NRSTR && !up->notified){
32 		qunlock(&up->debug);
33 		pprint("call to noted() when not notified\n");
34 		pexit("Suicide", 0);
35 	}
36 	up->notified = 0;
37 	fpunoted();
38 
39 	nf = up->ureg;
40 
41 	/* sanity clause */
42 	if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
43 		qunlock(&up->debug);
44 		pprint("bad ureg in noted %#p\n", nf);
45 		pexit("Suicide", 0);
46 	}
47 
48 	/* don't let user change system status */
49 	nur = &nf->ureg;
50 	nur->status = cur->status;
51 
52 	memmove(cur, nur, sizeof(Ureg));
53 
54 	switch((int)arg0){
55 	case NCONT:
56 	case NRSTR:
57 		if(!okaddr(nur->pc, BY2SE, 0) || !okaddr(nur->usp, BY2SE, 0)){
58 			qunlock(&up->debug);
59 			pprint("suicide: trap in noted\n");
60 			pexit("Suicide", 0);
61 		}
62 		up->ureg = nf->old;
63 		qunlock(&up->debug);
64 		break;
65 
66 	case NSAVE:
67 		if(!okaddr(nur->pc, BY2SE, 0) || !okaddr(nur->usp, BY2SE, 0)){
68 			qunlock(&up->debug);
69 			pprint("suicide: trap in noted\n");
70 			pexit("Suicide", 0);
71 		}
72 		qunlock(&up->debug);
73 
74 		splhi();
75 		nf->arg1 = nf->msg;
76 		nf->arg0 = &nf->ureg;
77 		cur->r3 = PTR2UINT(nf->arg0);
78 		nf->pc = 0;
79 		cur->sp = PTR2UINT(nf);
80 		break;
81 
82 	default:
83 		pprint("unknown noted arg %#p\n", arg0);
84 		up->lastnote.flag = NDebug;
85 		/* fall through */
86 	case NDFLT:
87 		if(up->lastnote.flag == NDebug){
88 			qunlock(&up->debug);
89 			pprint("suicide: %s\n", up->lastnote.msg);
90 		}
91 		else
92 			qunlock(&up->debug);
93 		pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
94 	}
95 }
96 
97 /*
98  *  Call user, if necessary, with note.
99  *  Pass user the Ureg struct and the note on his stack.
100  */
101 int
notify(Ureg * ureg)102 notify(Ureg* ureg)
103 {
104 	int l;
105 	Note *n;
106 	ulong s;
107 	uintptr sp;
108 	NFrame *nf;
109 
110 	if(up->procctl)
111 		procctl(up);
112 	if(up->nnote == 0)
113 		return 0;
114 
115 	fpunotify(ureg);
116 
117 	s = spllo();
118 	qlock(&up->debug);
119 	up->notepending = 0;
120 	n = &up->note[0];
121 	if(strncmp(n->msg, "sys:", 4) == 0){
122 		l = strlen(n->msg);
123 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
124 			l = ERRMAX-15;
125 		sprint(n->msg+l, " pc=%#.8lux", ureg->pc);
126 	}
127 
128 	if(n->flag!=NUser && (up->notified || up->notify==0)){
129 		if(n->flag == NDebug)
130 			pprint("suicide: %s\n", n->msg);
131 		qunlock(&up->debug);
132 		pexit(n->msg, n->flag!=NDebug);
133 	}
134 
135 	if(up->notified) {
136 		qunlock(&up->debug);
137 		splhi();
138 		return 0;
139 	}
140 
141 	if(up->notify == nil){
142 		qunlock(&up->debug);
143 		pexit(n->msg, n->flag!=NDebug);
144 	}
145 	if(!okaddr(PTR2UINT(up->notify), BY2WD, 0)){
146 		qunlock(&up->debug);
147 		pprint("suicide: notify function address %#p\n", up->notify);
148 		pexit("Suicide", 0);
149 	}
150 
151 	sp = ureg->usp & ~(BY2V-1);
152 	sp -= (sizeof(NFrame)+BY2V-1) & ~(BY2V-1);
153 
154 	if(!okaddr(sp, sizeof(NFrame), 1)){
155 		qunlock(&up->debug);
156 		pprint("suicide: notify stack address %#p\n", sp);
157 		pexit("Suicide", 0);
158 	}
159 
160 	nf = UINT2PTR(sp);
161 	memmove(&nf->ureg, ureg, sizeof(Ureg));
162 	nf->old = up->ureg;
163 	up->ureg = nf;
164 	memmove(nf->msg, up->note[0].msg, ERRMAX);
165 	nf->arg1 = nf->msg;
166 	nf->arg0 = up->ureg;
167 	ureg->r3 = PTR2UINT(up->ureg);
168 	nf->pc = 0;
169 
170 	ureg->usp = sp;
171 	ureg->pc = PTR2UINT(up->notify);
172 	up->notified = 1;
173 	up->nnote--;
174 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
175 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
176 
177 	qunlock(&up->debug);
178 	splx(s);
179 	return 1;
180 }
181 
182 /*
183  *  system calls and 'orrible notes
184  */
185 
186 /* TO DO: make this trap a separate asm entry point, as on some other RISC architectures */
187 void
syscall(Ureg * ureg)188 syscall(Ureg* ureg)
189 {
190 	char *e;
191 	u32int s;
192 	uintptr sp;
193 	long ret;
194 	int i, scallnr;
195 
196 	cycles(&up->kentry);
197 
198 	m->syscall++;
199 	up->insyscall = 1;
200 	up->pc = ureg->pc;
201 	up->dbgreg = ureg;
202 
203 	if(up->procctl == Proc_tracesyscall){
204 		up->procctl = Proc_stopme;
205 		procctl(up);
206 	}
207 
208 	scallnr = ureg->r3;
209 	up->scallnr = scallnr;
210 	if(scallnr == RFORK)
211 		fpusysrfork(ureg);
212 	spllo();
213 
214 	sp = ureg->sp;
215 	up->nerrlab = 0;
216 	ret = -1;
217 	if(!waserror()){
218 		if(scallnr >= nsyscall){
219 			pprint("bad sys call number %d pc %lux\n",
220 				scallnr, ureg->pc);
221 			postnote(up, 1, "sys: bad sys call", NDebug);
222 			error(Ebadarg);
223 		}
224 
225 		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
226 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
227 
228 		up->s = *((Sargs*)(sp+BY2WD));
229 		up->psstate = sysctab[scallnr];
230 
231 		ret = systab[scallnr](up->s.args);
232 		poperror();
233 	}else{
234 		/* failure: save the error buffer for errstr */
235 		e = up->syserrstr;
236 		up->syserrstr = up->errstr;
237 		up->errstr = e;
238 	}
239 	if(up->nerrlab){
240 		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
241 		for(i = 0; i < NERR; i++)
242 			print("sp=%#p pc=%#p\n",
243 				up->errlab[i].sp, up->errlab[i].pc);
244 		panic("error stack");
245 	}
246 
247 	/*
248 	 * Put return value in frame.
249 	 */
250 	ureg->r3 = ret;
251 
252 	if(up->procctl == Proc_tracesyscall){
253 		up->procctl = Proc_stopme;
254 		s = splhi();
255 		procctl(up);
256 		splx(s);
257 	}
258 
259 	up->insyscall = 0;
260 	up->psstate = 0;
261 
262 	if(scallnr == NOTED)
263 		noted(ureg, *(uintptr*)(sp+BY2SE));
264 
265 	splhi();
266 	if(scallnr != RFORK && (up->procctl || up->nnote))
267 		notify(ureg);
268 
269 	/* if we delayed sched because we held a lock, sched now */
270 	if(up->delaysched){
271 		sched();
272 		splhi();
273 	}
274 	kexit(ureg);
275 }
276 
277 /*
278  * called in syscallfmt.c, sysfile.c, sysproc.c
279  */
280 void
validalign(uintptr addr,unsigned align)281 validalign(uintptr addr, unsigned align)
282 {
283 	/*
284 	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
285 	 * does not usually have instructions which move 64-bit
286 	 * quantities directly, synthesizing the operations
287 	 * with 32-bit move instructions. Therefore, the compiler
288 	 * (and hardware) usually only enforce 32-bit alignment,
289 	 * if at all.
290 	 *
291 	 * Take this out if the architecture warrants it.
292 	 */
293 	if(align == sizeof(vlong))
294 		align = sizeof(long);
295 
296 	/*
297 	 * Check align is a power of 2, then addr alignment.
298 	 */
299 	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
300 		return;
301 	postnote(up, 1, "sys: odd address", NDebug);
302 	error(Ebadarg);
303 	/*NOTREACHED*/
304 }
305 
306 uintptr
sysexecstack(uintptr stack,int argc)307 sysexecstack(uintptr stack, int argc)
308 {
309 	/*
310 	 * Given a current bottom-of-stack and a count
311 	 * of pointer arguments to be pushed onto it followed
312 	 * by an integer argument count, return a suitably
313 	 * aligned new bottom-of-stack which will satisfy any
314 	 * hardware stack-alignment contraints.
315 	 * Rounding the stack down to be aligned with the
316 	 * natural size of a pointer variable usually suffices,
317 	 * but some architectures impose further restrictions,
318 	 * e.g. 32-bit SPARC, where the stack must be 8-byte
319 	 * aligned although pointers and integers are 32-bits.
320 	 */
321 	USED(argc);
322 
323 	return STACKALIGN(stack);
324 }
325 
326 long
execregs(ulong entry,ulong ssize,ulong nargs)327 execregs(ulong entry, ulong ssize, ulong nargs)
328 {
329 	ulong *sp;
330 	Ureg *ureg;
331 
332 	fpusysprocsetup(up);			/* up is a guess */
333 
334 	sp = (ulong*)(USTKTOP - ssize);
335 	*--sp = nargs;
336 
337 	ureg = up->dbgreg;
338 //	memset(ureg, 0, 31*sizeof(ulong));
339 	ureg->usp = (ulong)sp;
340 	ureg->pc = entry;
341 	ureg->srr1 &= ~MSR_FP;			/* disable floating point */
342 
343 	/*
344 	 * return the address of kernel/user shared data
345 	 * (e.g. clock stuff)
346 	 */
347 	return USTKTOP-sizeof(Tos);
348 }
349 
350 void
sysprocsetup(Proc * p)351 sysprocsetup(Proc* p)
352 {
353 	fpusysprocsetup(p);
354 }
355 
356 /*
357  *  Craft a return frame which will cause the child to pop out of
358  *  the scheduler in user mode with the return register zero.  Set
359  *  pc to point to a l.s return function.
360  */
361 void
forkchild(Proc * p,Ureg * ureg)362 forkchild(Proc *p, Ureg *ureg)
363 {
364 	Ureg *cureg;
365 
366 //print("%lud setting up for forking child %lud\n", up->pid, p->pid);
367 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2SE);
368 	p->sched.pc = (ulong)forkret;
369 
370 	cureg = (Ureg*)(p->sched.sp+2*BY2SE);
371 	memmove(cureg, ureg, sizeof(Ureg));
372 
373 	/* syscall returns 0 for child */
374 	cureg->r3 = 0;
375 
376 	/* Things from bottom of syscall which were never executed */
377 	p->psstate = 0;
378 	p->insyscall = 0;
379 
380 	fpusysrforkchild(p, cureg, up);
381 }
382