1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #include "../port/error.h"
8
9 #include "/sys/src/libc/9syscall/sys.h"
10
11 #include <tos.h>
12 #include <ptrace.h>
13
14 #include "amd64.h"
15 #include "ureg.h"
16
17 typedef struct {
18 uintptr ip;
19 Ureg* arg0;
20 char* arg1;
21 char msg[ERRMAX];
22 Ureg* old;
23 Ureg ureg;
24 } NFrame;
25
26 /*
27 * Return user to state before notify()
28 */
29 static void
noted(Ureg * cur,uintptr arg0)30 noted(Ureg* cur, uintptr arg0)
31 {
32 NFrame *nf;
33 Note note;
34 Ureg *nur;
35
36 qlock(&up->debug);
37 if(arg0 != NRSTR && !up->notified){
38 qunlock(&up->debug);
39 pprint("suicide: call to noted when not notified\n");
40 pexit("Suicide", 0);
41 }
42 up->notified = 0;
43 fpunoted();
44
45 nf = up->ureg;
46
47 /* sanity clause */
48 if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
49 qunlock(&up->debug);
50 pprint("suicide: bad ureg %#p in noted\n", nf);
51 pexit("Suicide", 0);
52 }
53
54 /*
55 * Check the segment selectors are all valid.
56 */
57 nur = &nf->ureg;
58 #ifdef notdef
59 if(nur->cs != SSEL(SiUCS, SsRPL3) || nur->ss != SSEL(SiUDS, SsRPL3)
60 || nur->ds != SSEL(SiUDS, SsRPL3) || nur->es != SSEL(SiUDS, SsRPL3)
61 || nur->fs != SSEL(SiUDS, SsRPL3) || nur->gs != SSEL(SiUDS, SsRPL3)){
62 qunlock(&up->debug);
63 pprint("suicide: bad segment selector in noted\n");
64 pexit("Suicide", 0);
65 }
66 #endif /* notdef */
67
68 /* don't let user change system flags */
69 nur->flags &= (Of|Df|Sf|Zf|Af|Pf|Cf);
70 nur->flags |= cur->flags & ~(Of|Df|Sf|Zf|Af|Pf|Cf);
71
72 memmove(cur, nur, sizeof(Ureg));
73
74 switch((int)arg0){
75 case NCONT:
76 case NRSTR:
77 if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
78 qunlock(&up->debug);
79 pprint("suicide: trap in noted pc=%#p sp=%#p\n",
80 nur->ip, nur->sp);
81 pexit("Suicide", 0);
82 }
83 up->ureg = nf->old;
84 qunlock(&up->debug);
85 break;
86 case NSAVE:
87 if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
88 qunlock(&up->debug);
89 pprint("suicide: trap in noted pc=%#p sp=%#p\n",
90 nur->ip, nur->sp);
91 pexit("Suicide", 0);
92 }
93 qunlock(&up->debug);
94
95 splhi();
96 nf->arg1 = nf->msg;
97 nf->arg0 = &nf->ureg;
98 cur->bp = PTR2UINT(nf->arg0);
99 nf->ip = 0;
100 cur->sp = PTR2UINT(nf);
101 break;
102 default:
103 memmove(¬e, &up->lastnote, sizeof(Note));
104 qunlock(&up->debug);
105 pprint("suicide: bad arg %#p in noted: %s\n", arg0, note.msg);
106 pexit(note.msg, 0);
107 break;
108 case NDFLT:
109 memmove(¬e, &up->lastnote, sizeof(Note));
110 qunlock(&up->debug);
111 if(note.flag == NDebug)
112 pprint("suicide: %s\n", note.msg);
113 pexit(note.msg, note.flag != NDebug);
114 break;
115 }
116 }
117
118 /*
119 * Call user, if necessary, with note.
120 * Pass user the Ureg struct and the note on his stack.
121 */
122 int
notify(Ureg * ureg)123 notify(Ureg* ureg)
124 {
125 int l;
126 Mreg s;
127 Note note;
128 uintptr sp;
129 NFrame *nf;
130
131 if(up->procctl)
132 procctl(up);
133 if(up->nnote == 0)
134 return 0;
135
136 fpunotify(ureg);
137
138 s = spllo();
139 qlock(&up->debug);
140
141 up->notepending = 0;
142 memmove(¬e, &up->note[0], sizeof(Note));
143 if(strncmp(note.msg, "sys:", 4) == 0){
144 l = strlen(note.msg);
145 if(l > ERRMAX-sizeof(" pc=0x0123456789abcdef"))
146 l = ERRMAX-sizeof(" pc=0x0123456789abcdef");
147 sprint(note.msg+l, " pc=%#p", ureg->ip);
148 }
149
150 if(note.flag != NUser && (up->notified || up->notify == nil)){
151 qunlock(&up->debug);
152 if(note.flag == NDebug)
153 pprint("suicide: %s\n", note.msg);
154 pexit(note.msg, note.flag != NDebug);
155 }
156
157 if(up->notified){
158 qunlock(&up->debug);
159 splhi();
160 return 0;
161 }
162
163 if(up->notify == nil){
164 qunlock(&up->debug);
165 pexit(note.msg, note.flag != NDebug);
166 }
167 if(!okaddr(PTR2UINT(up->notify), sizeof(ureg->ip), 0)){
168 qunlock(&up->debug);
169 pprint("suicide: bad function address %#p in notify\n",
170 up->notify);
171 pexit("Suicide", 0);
172 }
173
174 sp = ureg->sp - sizeof(NFrame);
175 if(!okaddr(sp, sizeof(NFrame), 1)){
176 qunlock(&up->debug);
177 pprint("suicide: bad stack address %#p in notify\n", sp);
178 pexit("Suicide", 0);
179 }
180
181 nf = UINT2PTR(sp);
182 memmove(&nf->ureg, ureg, sizeof(Ureg));
183 nf->old = up->ureg;
184 up->ureg = nf;
185 memmove(nf->msg, note.msg, ERRMAX);
186 nf->arg1 = nf->msg;
187 nf->arg0 = &nf->ureg;
188 ureg->bp = PTR2UINT(nf->arg0);
189 nf->ip = 0;
190
191 ureg->sp = sp;
192 ureg->ip = PTR2UINT(up->notify);
193 up->notified = 1;
194 up->nnote--;
195 memmove(&up->lastnote, ¬e, sizeof(Note));
196 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
197
198 qunlock(&up->debug);
199 splx(s);
200
201 return 1;
202 }
203
204 void
syscall(int scallnr,Ureg * ureg)205 syscall(int scallnr, Ureg* ureg)
206 {
207 char *e;
208 uintptr sp;
209 int i, s;
210 vlong startns, stopns;
211 Ar0 ar0;
212 static Ar0 zar0;
213 void (*pt)(Proc*, int, vlong, vlong);
214
215 if(!userureg(ureg))
216 panic("syscall: cs %#llux\n", ureg->cs);
217
218 cycles(&up->kentry);
219
220 m->syscall++;
221 up->insyscall = 1;
222 up->pc = ureg->ip;
223 sp = ureg->sp;
224 up->scallnr = scallnr;
225 up->dbgreg = ureg;
226 startns = 0;
227
228 if(up->trace && (pt = proctrace) != nil)
229 pt(up, STrap, todget(nil), STrapSC|scallnr);
230
231 if(up->procctl == Proc_tracesyscall){
232 /*
233 * Redundant validaddr. Do we care?
234 * Tracing syscalls is not exactly a fast path...
235 * Beware, validaddr currently does a pexit rather
236 * than an error if there's a problem; that might
237 * change in the future.
238 */
239 if(sp < (USTKTOP-PGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2V))
240 validaddr((void *)sp, sizeof(up->arg)+BY2V, 0);
241
242 syscallfmt(scallnr, (va_list)(sp+BY2V));
243 up->procctl = Proc_stopme;
244 procctl(up);
245 if(up->syscalltrace)
246 free(up->syscalltrace);
247 up->syscalltrace = nil;
248 startns = todget(nil);
249 }
250
251 if(scallnr == RFORK)
252 fpusysrfork(ureg);
253 spllo();
254
255 up->nerrlab = 0;
256 ar0 = zar0;
257 if(!waserror()){
258 if(scallnr >= nsyscall || systab[scallnr].f == nil){
259 pprint("bad sys call number %d pc %#llux\n",
260 scallnr, ureg->ip);
261 postnote(up, 1, "sys: bad sys call", NDebug);
262 error(Ebadarg);
263 }
264
265 if(sp < (USTKTOP-PGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE))
266 validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0);
267
268 memmove(up->arg, UINT2PTR(sp+BY2SE), sizeof(up->arg));
269 up->psstate = systab[scallnr].n;
270
271 systab[scallnr].f(&ar0, (va_list)up->arg);
272 poperror();
273 }
274 else{
275 /* failure: save the error buffer for errstr */
276 e = up->syserrstr;
277 up->syserrstr = up->errstr;
278 up->errstr = e;
279 if(DBGFLG && up->pid == 1)
280 iprint("%s: syscall %s error %s\n",
281 up->text, systab[scallnr].n, up->syserrstr);
282 ar0 = systab[scallnr].r;
283 }
284 if(up->nerrlab){
285 print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
286 for(i = 0; i < NERR; i++)
287 print("sp=%#p pc=%#p\n",
288 up->errlab[i].sp, up->errlab[i].pc);
289 panic("error stack");
290 }
291
292 /*
293 * Put return value in frame.
294 * Which element of Ar0 to use is based on specific
295 * knowledge of the architecture.
296 */
297 ureg->ax = ar0.p;
298
299 if(up->procctl == Proc_tracesyscall){
300 stopns = todget(nil);
301 up->procctl = Proc_stopme;
302 sysretfmt(scallnr, (va_list)(sp+BY2V), &ar0, startns, stopns);
303 s = splhi();
304 procctl(up);
305 splx(s);
306 if(up->syscalltrace)
307 free(up->syscalltrace);
308 up->syscalltrace = nil;
309 }
310
311 up->insyscall = 0;
312 up->psstate = 0;
313
314 if(scallnr == NOTED)
315 noted(ureg, *(uintptr*)(sp+BY2SE));
316
317 splhi();
318 if(scallnr != RFORK && scallnr != NSEC && (up->procctl || up->nnote))
319 notify(ureg);
320
321 /* if we delayed sched because we held a lock, sched now */
322 if(up->delaysched){
323 sched();
324 splhi();
325 }
326 kexit(ureg);
327 }
328
329 uintptr
sysexecstack(uintptr stack,int argc)330 sysexecstack(uintptr stack, int argc)
331 {
332 /*
333 * Given a current bottom-of-stack and a count
334 * of pointer arguments to be pushed onto it followed
335 * by an integer argument count, return a suitably
336 * aligned new bottom-of-stack which will satisfy any
337 * hardware stack-alignment contraints.
338 * Rounding the stack down to be aligned with the
339 * natural size of a pointer variable usually suffices,
340 * but some architectures impose further restrictions,
341 * e.g. 32-bit SPARC, where the stack must be 8-byte
342 * aligned although pointers and integers are 32-bits.
343 */
344 USED(argc);
345
346 return STACKALIGN(stack);
347 }
348
349 void*
sysexecregs(uintptr entry,ulong ssize,ulong nargs)350 sysexecregs(uintptr entry, ulong ssize, ulong nargs)
351 {
352 uintptr *sp;
353 Ureg *ureg;
354
355 sp = (uintptr*)(USTKTOP - ssize);
356 *--sp = nargs;
357
358 ureg = up->dbgreg;
359 ureg->sp = PTR2UINT(sp);
360 ureg->ip = entry;
361 ureg->type = 64; /* fiction for acid */
362
363 /*
364 * return the address of kernel/user shared data
365 * (e.g. clock stuff)
366 */
367 return UINT2PTR(USTKTOP-sizeof(Tos));
368 }
369
370 void
sysprocsetup(Proc * p)371 sysprocsetup(Proc* p)
372 {
373 fpusysprocsetup(p);
374 }
375
376 void
sysrforkchild(Proc * child,Proc * parent)377 sysrforkchild(Proc* child, Proc* parent)
378 {
379 Ureg *cureg;
380
381 /*
382 * Add 3*BY2SE to the stack to account for
383 * - the return PC
384 * - trap's arguments (syscallnr, ureg)
385 */
386 child->sched.sp = PTR2UINT(child->kstack+KSTACK-(sizeof(Ureg)+3*BY2SE));
387 child->sched.pc = PTR2UINT(sysrforkret);
388
389 cureg = (Ureg*)(child->sched.sp+3*BY2SE);
390 memmove(cureg, parent->dbgreg, sizeof(Ureg));
391
392 /* Things from bottom of syscall which were never executed */
393 child->psstate = 0;
394 child->insyscall = 0;
395
396 fpusysrforkchild(child, parent);
397 }
398