Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* we use l1 and l2 cache ops to help stability. */
2
 
3
#include "u.h"
4
#include "../port/lib.h"
5
#include "mem.h"
6
#include "dat.h"
7
#include "fns.h"
8
#include "../port/error.h"
9
#include "../port/systab.h"
10
 
11
#include <tos.h>
12
#include "ureg.h"
13
 
14
#include "arm.h"
15
 
16
enum {
17
	Psrsysbits = PsrMask | PsrDfiq | PsrDirq | PsrDasabt | PsrMbz,
18
};
19
 
20
typedef struct {
21
	uintptr	ip;
22
	Ureg*	arg0;
23
	char*	arg1;
24
	char	msg[ERRMAX];
25
	Ureg*	old;
26
	Ureg	ureg;
27
} NFrame;
28
 
29
/*
30
 *   Return user to state before notify()
31
 */
32
static void
33
noted(Ureg* cur, uintptr arg0)
34
{
35
	NFrame *nf;
36
	Ureg *nur;
37
 
38
	qlock(&up->debug);
39
	if(arg0 != NRSTR && !up->notified){
40
		qunlock(&up->debug);
41
		pprint("call to noted() when not notified\n");
42
		pexit("Suicide", 0);
43
	}
44
	up->notified = 0;
45
	fpunoted();
46
 
47
	nf = up->ureg;
48
 
49
	/* sanity clause */
50
	if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
51
		qunlock(&up->debug);
52
		pprint("bad ureg in noted %#p\n", nf);
53
		pexit("Suicide", 0);
54
	}
55
 
56
	/* don't let user change system flags */
57
	nur = &nf->ureg;
58
	nur->psr &= Psrsysbits;
59
	nur->psr |= cur->psr & ~Psrsysbits;
60
 
61
	memmove(cur, nur, sizeof(Ureg));
62
 
63
	switch((int)arg0){
64
	case NCONT:
65
	case NRSTR:
66
		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
67
			qunlock(&up->debug);
68
			pprint("suicide: trap in noted\n");
69
			pexit("Suicide", 0);
70
		}
71
		up->ureg = nf->old;
72
		qunlock(&up->debug);
73
		break;
74
	case NSAVE:
75
		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
76
			qunlock(&up->debug);
77
			pprint("suicide: trap in noted\n");
78
			pexit("Suicide", 0);
79
		}
80
		qunlock(&up->debug);
81
 
82
		splhi();
83
		nf->arg1 = nf->msg;		/* arg 1 is string */
84
		nf->arg0 = &nf->ureg;		/* arg 0 XX(FP) is ureg* */
85
		nf->ip = 0;
86
		cur->sp = PTR2UINT(nf);
87
		cur->r0 = PTR2UINT(nf->arg0);	/* arg 0 in reg is ureg* */
88
		break;
89
	default:
90
		pprint("unknown noted arg %#p\n", arg0);
91
		up->lastnote.flag = NDebug;
92
		/*FALLTHROUGH*/
93
	case NDFLT:
94
		if(up->lastnote.flag == NDebug){ 
95
			qunlock(&up->debug);
96
			pprint("suicide: %s\n", up->lastnote.msg);
97
		}
98
		else
99
			qunlock(&up->debug);
100
		pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
101
	}
102
}
103
 
104
/*
105
 *  Call user, if necessary, with note.
106
 *  Pass user the Ureg struct and the note on his stack.
107
 */
108
int
109
notify(Ureg* ureg)
110
{
111
	int l;
112
	Note *n;
113
	u32int s;
114
	uintptr sp;
115
	NFrame *nf;
116
 
117
	if(up->procctl)
118
		procctl(up);
119
	if(up->nnote == 0)
120
		return 0;
121
 
122
	fpunotify(ureg);
123
 
124
	s = spllo();
125
	qlock(&up->debug);
126
 
127
	up->notepending = 0;
128
	n = &up->note[0];
129
	if(strncmp(n->msg, "sys:", 4) == 0){
130
		l = strlen(n->msg);
131
		if(l > ERRMAX-23)	/* " pc=0x0123456789abcdef\0" */
132
			l = ERRMAX-23;
133
		snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc);
134
	}
135
 
136
	if(n->flag != NUser && (up->notified || up->notify == 0)){
137
		if(n->flag == NDebug)
138
			pprint("suicide: %s\n", n->msg);
139
		qunlock(&up->debug);
140
		pexit(n->msg, n->flag != NDebug);
141
	}
142
 
143
	if(up->notified){
144
		qunlock(&up->debug);
145
		splhi();
146
		return 0;
147
	}
148
 
149
	if(up->notify == nil){
150
		qunlock(&up->debug);
151
		pexit(n->msg, n->flag != NDebug);
152
	}
153
	if(!okaddr(PTR2UINT(up->notify), 1, 0)){
154
		pprint("suicide: notify function address %#p\n", up->notify);
155
		qunlock(&up->debug);
156
		pexit("Suicide", 0);
157
	}
158
 
159
	sp = ureg->sp - sizeof(NFrame);
160
	if(!okaddr(sp, sizeof(NFrame), 1)){
161
		qunlock(&up->debug);
162
		pprint("suicide: notify stack address %#p\n", sp);
163
		pexit("Suicide", 0);
164
	}
165
 
166
	nf = UINT2PTR(sp);
167
	memmove(&nf->ureg, ureg, sizeof(Ureg));
168
	nf->old = up->ureg;
169
	up->ureg = nf;
170
	memmove(nf->msg, up->note[0].msg, ERRMAX);
171
	nf->arg1 = nf->msg;			/* arg 1 is string */
172
	nf->arg0 = &nf->ureg;			/* arg 0 XX(FP) is ureg* */
173
	ureg->r0 = PTR2UINT(nf->arg0);		/* arg 0 in r0 is ureg* */
174
	nf->ip = 0;
175
 
176
	ureg->sp = sp;
177
	ureg->pc = PTR2UINT(up->notify);
178
 
179
	up->notified = 1;
180
	up->nnote--;
181
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
182
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
183
 
184
	qunlock(&up->debug);
185
	splx(s);
186
 
187
	l1cache->wb();				/* is this needed? */
188
	return 1;
189
}
190
 
191
void
192
syscall(Ureg* ureg)
193
{
194
	char *e;
195
	u32int s;
196
	ulong sp;
197
	long ret;
198
	int i, scallnr;
199
	vlong startns, stopns;
200
 
201
	if(!userureg(ureg))
202
		panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
203
			ureg->pc, ureg->r14, ureg->psr);
204
 
205
	cycles(&up->kentry);
206
 
207
	m->syscall++;
208
	up->insyscall = 1;
209
	up->pc = ureg->pc;
210
	up->dbgreg = ureg;
211
 
212
	scallnr = ureg->r0;
213
	up->scallnr = scallnr;
214
	if(scallnr == RFORK)
215
		fpusysrfork(ureg);
216
	spllo();
217
	sp = ureg->sp;
218
 
219
	if(up->procctl == Proc_tracesyscall){
220
		/*
221
		 * Redundant validaddr.  Do we care?
222
		 * Tracing syscalls is not exactly a fast path...
223
		 * Beware, validaddr currently does a pexit rather
224
		 * than an error if there's a problem; that might
225
		 * change in the future.
226
		 */
227
		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
228
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
229
 
230
		syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD));
231
		up->procctl = Proc_stopme;
232
		procctl(up);
233
		if (up->syscalltrace) 
234
			free(up->syscalltrace);
235
		up->syscalltrace = nil;
236
	}
237
 
238
	up->nerrlab = 0;
239
	ret = -1;
240
	startns = todget(nil);
241
 
242
	l1cache->wb();			/* system is more stable with this */
243
	if(!waserror()){
244
		if(scallnr >= nsyscall){
245
			pprint("bad sys call number %d pc %#lux\n",
246
				scallnr, ureg->pc);
247
			postnote(up, 1, "sys: bad sys call", NDebug);
248
			error(Ebadarg);
249
		}
250
 
251
		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
252
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
253
 
254
		up->s = *((Sargs*)(sp+BY2WD));
255
		up->psstate = sysctab[scallnr];
256
 
257
	/*	iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */
258
 
259
		ret = systab[scallnr](up->s.args);
260
		poperror();
261
	}else{
262
		/* failure: save the error buffer for errstr */
263
		e = up->syserrstr;
264
		up->syserrstr = up->errstr;
265
		up->errstr = e;
266
	}
267
	if(up->nerrlab){
268
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
269
		for(i = 0; i < NERR; i++)
270
			print("sp=%#p pc=%#p\n",
271
				up->errlab[i].sp, up->errlab[i].pc);
272
		panic("error stack");
273
	}
274
 
275
	/*
276
	 *  Put return value in frame.  On the x86 the syscall is
277
	 *  just another trap and the return value from syscall is
278
	 *  ignored.  On other machines the return value is put into
279
	 *  the results register by caller of syscall.
280
	 */
281
	ureg->r0 = ret;
282
 
283
	if(up->procctl == Proc_tracesyscall){
284
		stopns = todget(nil);
285
		up->procctl = Proc_stopme;
286
		sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns);
287
		s = splhi();
288
		procctl(up);
289
		splx(s);
290
		if(up->syscalltrace)
291
			free(up->syscalltrace);
292
		up->syscalltrace = nil;
293
	}
294
 
295
	up->insyscall = 0;
296
	up->psstate = 0;
297
 
298
	if(scallnr == NOTED)
299
		noted(ureg, *(ulong*)(sp+BY2WD));
300
 
301
	splhi();
302
	if(scallnr != RFORK && (up->procctl || up->nnote))
303
		notify(ureg);
304
 
305
	l1cache->wb();			/* system is more stable with this */
306
 
307
	/* if we delayed sched because we held a lock, sched now */
308
	if(up->delaysched){
309
		sched();
310
		splhi();
311
	}
312
	kexit(ureg);
313
}
314
 
315
long
316
execregs(ulong entry, ulong ssize, ulong nargs)
317
{
318
	ulong *sp;
319
	Ureg *ureg;
320
 
321
	sp = (ulong*)(USTKTOP - ssize);
322
	*--sp = nargs;
323
 
324
	ureg = up->dbgreg;
325
//	memset(ureg, 0, 15*sizeof(ulong));
326
	ureg->r13 = (ulong)sp;
327
	ureg->pc = entry;
328
//print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs);
329
	allcache->wbse(ureg, sizeof *ureg);		/* is this needed? */
330
 
331
	/*
332
	 * return the address of kernel/user shared data
333
	 * (e.g. clock stuff)
334
	 */
335
	return USTKTOP-sizeof(Tos);
336
}
337
 
338
void
339
sysprocsetup(Proc* p)
340
{
341
	fpusysprocsetup(p);
342
}
343
 
344
/* 
345
 *  Craft a return frame which will cause the child to pop out of
346
 *  the scheduler in user mode with the return register zero.  Set
347
 *  pc to point to a l.s return function.
348
 */
349
void
350
forkchild(Proc *p, Ureg *ureg)
351
{
352
	Ureg *cureg;
353
 
354
	p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
355
	p->sched.pc = (ulong)forkret;
356
 
357
	cureg = (Ureg*)(p->sched.sp);
358
	memmove(cureg, ureg, sizeof(Ureg));
359
 
360
	/* syscall returns 0 for child */
361
	cureg->r0 = 0;
362
 
363
	/* Things from bottom of syscall which were never executed */
364
	p->psstate = 0;
365
	p->insyscall = 0;
366
 
367
	fpusysrforkchild(p, cureg, up);
368
}