trap.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
trap.c (22655B)
---
1 /*
2 * Heavily modified copy of /sys/src/9/pc/trap.c
3 * A shell of its former self.
4 */
5 #define WANT_M
6
7 #include "u.h"
8 #include "libvx32/vx32.h"
9 #include "tos.h"
10 #include "lib.h"
11 #include "mem.h"
12 #include "dat.h"
13 #include "fns.h"
14 #include "io.h"
15 #include "ureg.h"
16 #include "error.h"
17 #include "trace.h"
18 #include "systab.h"
19
20 int tracesyscalls;
21 static void noted(Ureg*, ulong);
22 static void mathemu(Ureg*, void*);
23 static void syscall(Ureg*);
24
25 /* going to user space */
26 void
27 kexit(Ureg *ureg)
28 {
29 uvlong t;
30 Tos *tos;
31
32 /* precise time accounting, kernel exit */
33 tos = (Tos*)(up->pmmu.uzero+USTKTOP-sizeof(Tos));
34 cycles(&t);
35 tos->kcycles += t - up->kentry;
36 tos->pcycles = up->pcycles;
37 tos->pid = up->pid;
38 }
39
40 static char* excname[32] = {
41 "divide error",
42 "debug exception",
43 "nonmaskable interrupt",
44 "breakpoint",
45 "overflow",
46 "bounds check",
47 "invalid opcode",
48 "coprocessor not available",
49 "double fault",
50 "coprocessor segment overrun",
51 "invalid TSS",
52 "segment not present",
53 "stack exception",
54 "general protection violation",
55 "page fault",
56 "15 (reserved)",
57 "coprocessor error",
58 "alignment check",
59 "machine check",
60 "19 (reserved)",
61 "20 (reserved)",
62 "21 (reserved)",
63 "22 (reserved)",
64 "23 (reserved)",
65 "24 (reserved)",
66 "25 (reserved)",
67 "26 (reserved)",
68 "27 (reserved)",
69 "28 (reserved)",
70 "29 (reserved)",
71 "30 (reserved)",
72 "31 (reserved)",
73 };
74
75 /*
76 * Handle a trap.
77 */
78 void
79 trap(Ureg *ureg)
80 {
81 char buf[ERRMAX];
82 int vno;
83
84 vno = ureg->trap;
85
86 switch(vno){
87 case VXTRAP_FPOFF:
88 mathemu(ureg, nil);
89 return;
90
91 case VXTRAP_SOFT+0x40: /* int $0x40 - system call */
92 if(tracesyscalls){
93 uint32 *sp = (uint32*)(up->pmmu.uzero + ureg->usp);
94 iprint("%d [%s] %s %#ux %08ux %08ux %08ux %08ux\n",
95 up->pid, up->text,
96 sysctab[ureg->ax], sp[0], sp[1], sp[2], sp[3]);
97 }
98 syscall(ureg);
99 if(tracesyscalls){
100 if(ureg->ax == -1)
101 iprint("%d [%s] -> %s\n", up->pid, up->text, up->syserrstr);
102 else
103 iprint("%d [%s] -> %#ux\n", up->pid, up->text, ureg->ax);
104 }
105 return;
106
107 case VXTRAP_IRQ+VXIRQ_TIMER:
108 sched();
109 break;
110
111 case 3: // breakpoint
112 /* restore pc to instruction that caused the trap */
113 ureg->pc--;
114 sprint(buf, "sys: breakpoint");
115 postnote(up, 1, buf, NDebug);
116 break;
117
118 default:
119 if(vno < nelem(excname)){
120 spllo();
121 sprint(buf, "sys: trap: %s", excname[vno]);
122 postnote(up, 1, buf, NDebug);
123 }else{
124 dumpregs(ureg);
125 if(vno < nelem(excname))
126 panic("%s", excname[vno]);
127 panic("unknown trap/intr: %#x", vno);
128 }
129 break;
130 }
131
132 if(up->procctl || up->nnote)
133 notify(ureg);
134 spllo(); /* no actual effect, just silences prints */
135 kexit(ureg);
136 }
137
138 void
139 dumpregs2(Ureg* ureg)
140 {
141 if(up)
142 print("cpu%d: registers for %s %lud\n",
143 m->machno, up->text, up->pid);
144 else
145 print("cpu%d: registers for kernel\n", m->machno);
146 print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
147 ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
148 print(" USP=%luX\n", ureg->usp);
149 print(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n",
150 ureg->ax, ureg->bx, ureg->cx, ureg->dx);
151 print(" SI %8.8luX DI %8.8luX BP %8.8luX\n",
152 ureg->si, ureg->di, ureg->bp);
153 }
154
155 void
156 dumpregs(Ureg* ureg)
157 {
158 dumpregs2(ureg);
159
160 /*
161 * Processor control registers.
162 * If machine check exception, time stamp counter, page size extensions
163 * or enhanced virtual 8086 mode extensions are supported, there is a
164 * CR4. If there is a CR4 and machine check extensions, read the machine
165 * check address and machine check type registers if RDMSR supported.
166 print(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
167 getcr0(), getcr2(), getcr3());
168 if(m->cpuiddx & 0x9A){
169 vlong mca, mct;
170 iprint(" CR4 %8.8lux", getcr4());
171 if((m->cpuiddx & 0xA0) == 0xA0){
172 rdmsr(0x00, &mca);
173 rdmsr(0x01, &mct);
174 iprint("\n MCA %8.8llux MCT %8.8llux", mca, mct);
175 }
176 }
177 print("\n ur %lux up %lux\n", ureg, up);
178 */
179 }
180
181 static void
182 fmtrwdata(Fmt *f, ulong s, int n, char *suffix)
183 {
184 char *t, *src;
185 int i;
186
187 if (! s) {
188 fmtprint(f, "0x0", suffix);
189 return;
190 }
191 src = uvalidaddr(s, 1, 0);
192 t = smalloc(n+1);
193 for(i = 0; i < n; i++)
194 if (isgraph(src[i]))
195 t[i] = src[i];
196 else
197 t[i] = '.';
198
199 fmtprint(f, "%08ux/\"%s\"%s", s, t, suffix);
200 free(t);
201 }
202
203 static void
204 fmtuserstring(Fmt *f, ulong s, char *suffix)
205 {
206 char *es, *t, *src;
207 int n;
208
209 if (! s){
210 fmtprint(f, "0/\"\"%s", suffix);
211 return;
212 }
213 src = uvalidaddr(s, 1, 0);
214 es = vmemchr(src, 0, 1<<16);
215 n = es - src;
216 t = smalloc(n+1);
217 memmove(t, src, n);
218 t[n] = 0;
219 fmtprint(f, "%08ux/\"%s\"%s", s, t, suffix);
220 free(t);
221 }
222
223 static void
224 syscallprint(Ureg *ureg)
225 {
226 uint32 *sp;
227 int syscallno;
228 vlong offset;
229 Fmt fmt;
230 int len;
231 uint32 argp, a;
232
233 sp = (uint32*)(up->pmmu.uzero + ureg->usp);
234 syscallno = ureg->ax;
235 offset = 0;
236 fmtstrinit(&fmt);
237 fmtprint(&fmt, "%d %s ", up->pid, up->text);
238 /* accomodate process-private system calls */
239
240 if(syscallno > nelem(sysctab))
241 fmtprint(&fmt, " %d %#x ", syscallno, sp[0]);
242 else
243 fmtprint(&fmt, "%s %#ux ", sysctab[syscallno], sp[0]);
244
245 if(up->syscalltrace)
246 free(up->syscalltrace);
247
248 switch(syscallno) {
249 case SYSR1:
250 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
251 break;
252 case _ERRSTR:
253 fmtuserstring(&fmt, sp[1], "");
254 break;
255 case BIND:
256 fmtuserstring(&fmt, sp[1], " ");
257 fmtuserstring(&fmt, sp[2], " ");
258 fmtprint(&fmt, "%#ux", sp[3]);
259 break;
260 case CHDIR:
261 fmtuserstring(&fmt, sp[1], "");
262 break;
263 case CLOSE:
264 fmtprint(&fmt, "%d", sp[1]);
265 break;
266 case DUP:
267 fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
268 break;
269 case ALARM:
270 fmtprint(&fmt, "%08ux ", sp[1]);
271 break;
272 case EXEC:
273 fmtuserstring(&fmt, sp[1], "");
274 argp = sp[2];
275 for(;;argp += BY2WD) {
276 a = *(uint32*)uvalidaddr(argp, BY2WD, 0);
277 if(a == 0)
278 break;
279 fmtprint(&fmt, " ");
280 fmtuserstring(&fmt, a, "");
281 }
282 break;
283 case EXITS:
284 fmtuserstring(&fmt, sp[1], "");
285 break;
286 case _FSESSION:
287 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
288 break;
289 case FAUTH:
290 fmtprint(&fmt, "%08ux", sp[1]);
291 fmtuserstring(&fmt, sp[2], "");
292 break;
293 case _FSTAT:
294 fmtprint(&fmt, "%08ux %#ux %08ux", sp[1], sp[2], sp[3]);
295 break;
296 case SEGBRK:
297 fmtprint(&fmt, "%#ux %#ux", sp[1], sp[2]);
298 break;
299 case _MOUNT:
300 fmtprint(&fmt, "%d %d ", sp[1], sp[2]);
301 fmtuserstring(&fmt, sp[3], " ");
302 fmtprint(&fmt, "%08ux ", sp[4]);
303 fmtuserstring(&fmt, sp[5], "");
304 break;
305 case OPEN:
306 fmtuserstring(&fmt, sp[1], " ");
307 fmtprint(&fmt, "%08ux", sp[2]);
308 break;
309 case OSEEK:
310 fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
311 break;
312 case SLEEP:
313 fmtprint(&fmt, "%d", sp[1]);
314 break;
315 case _STAT:
316 fmtuserstring(&fmt, sp[1], " ");
317 fmtprint(&fmt, "%#ux %d", sp[2], sp[3]);
318 break;
319 case RFORK:
320 fmtprint(&fmt, "%08ux", sp[1] );
321 break;
322 case PIPE:
323 break;
324 case CREATE:
325 fmtuserstring(&fmt, sp[1], " ");
326 fmtprint(&fmt, "%08ux %08ux", sp[2], sp[3]);
327 break;
328 case FD2PATH:
329 fmtprint(&fmt, "%d ", sp[1]);
330 break;
331 case BRK_:
332 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
333 break;
334 case REMOVE:
335 fmtuserstring(&fmt, sp[1], " ");
336 break;
337 /* deprecated */
338 case _WSTAT:
339 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
340 break;
341 case _FWSTAT:
342 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
343 break;
344 case NOTIFY:
345 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
346 break;
347 case NOTED:
348 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
349 break;
350 case SEGATTACH:
351 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
352 break;
353 case SEGDETACH:
354 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
355 break;
356 case SEGFREE:
357 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
358 break;
359 case SEGFLUSH:
360 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
361 break;
362 case RENDEZVOUS:
363 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
364 break;
365 case UNMOUNT:
366 fmtuserstring(&fmt, sp[1], " ");
367 break;
368 case _WAIT:
369 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
370 break;
371 case SEMACQUIRE:
372 fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
373 break;
374 case SEMRELEASE:
375 fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
376 break;
377 case SEEK:
378 fmtprint(&fmt, "%08ux %016ux %08ux", sp[1], *(vlong *)&sp[2], sp[4]);
379 break;
380 case FVERSION:
381 fmtprint(&fmt, "%08ux %08ux ", sp[1], sp[2]);
382 fmtuserstring(&fmt, sp[5], "");
383 break;
384 case ERRSTR:
385 fmtprint(&fmt, "%#ux/", sp[1]);
386 break;
387 case WSTAT:
388 case STAT:
389 fmtprint(&fmt, "%08ux ", sp[1]);
390 fmtuserstring(&fmt, sp[2], " ");
391 fmtprint(&fmt, "%08ux", sp[3]);
392 break;
393 case FSTAT:
394 case FWSTAT:
395 fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
396 break;
397 case MOUNT:
398 fmtprint(&fmt, "%d %d ", sp[1], sp[3]);
399 fmtuserstring(&fmt, sp[3], " ");
400 fmtprint(&fmt, "%08ux", sp[4]);
401 fmtuserstring(&fmt, sp[5], "");
402 break;
403 case AWAIT:
404 break;
405 case _READ:
406 case PREAD:
407 fmtprint(&fmt, "%d ", sp[1]);
408 break;
409 case _WRITE:
410 offset = -1;
411 case PWRITE:
412 fmtprint(&fmt, "%d ", sp[1]);
413 if (sp[3] < 64)
414 len = sp[3];
415 else
416 len = 64;
417 fmtrwdata(&fmt, sp[2], len, " ");
418 if(! offset)
419 offset = *(vlong *)&sp[4];
420 fmtprint(&fmt, "%d %#llx", sp[3], offset);
421 break;
422 }
423 up->syscalltrace = fmtstrflush(&fmt);
424 }
425
426 static void
427 retprint(Ureg *ureg, int syscallno, uvlong start, uvlong stop)
428 {
429 int errstrlen, len;
430 vlong offset;
431 char *errstr;
432 Fmt fmt;
433
434 fmtstrinit(&fmt);
435 len = 0;
436 errstrlen = 0;
437 offset = 0;
438 if (ureg->ax != -1)
439 errstr = "";
440 else
441 errstr = up->syserrstr;
442
443 if(up->syscalltrace)
444 free(up->syscalltrace);
445
446 switch(syscallno) {
447 case SYSR1:
448 case BIND:
449 case CHDIR:
450 case CLOSE:
451 case DUP:
452 case ALARM:
453 case EXEC:
454 case EXITS:
455 case _FSESSION:
456 case FAUTH:
457 case _FSTAT:
458 case SEGBRK:
459 case _MOUNT:
460 case OPEN:
461 case OSEEK:
462 case SLEEP:
463 case _STAT:
464 case _WRITE:
465 case PIPE:
466 case CREATE:
467 case BRK_:
468 case REMOVE:
469 case _WSTAT:
470 case _FWSTAT:
471 case NOTIFY:
472 case NOTED:
473 case SEGATTACH:
474 case SEGDETACH:
475 case SEGFREE:
476 case SEGFLUSH:
477 case RENDEZVOUS:
478 case UNMOUNT:
479 case _WAIT:
480 case SEMACQUIRE:
481 case SEMRELEASE:
482 case SEEK:
483 case FVERSION:
484 case STAT:
485 case FSTAT:
486 case WSTAT:
487 case FWSTAT:
488 case MOUNT:
489 case PWRITE:
490 case RFORK:
491 default:
492 break;
493 case AWAIT:
494 if(ureg->ax > 0){
495 fmtuserstring(&fmt, up->s.args[0], " ");
496 fmtprint(&fmt, "%d", up->s.args[1]);
497 } else {
498 fmtprint(&fmt, "%#ux/\"\" %d", up->s.args[0], up->s.args[1]);
499 }
500 break;
501 case _ERRSTR:
502 errstrlen = 64;
503 case ERRSTR:
504 if(! errstrlen)
505 errstrlen = up->s.args[1];
506 if(ureg->ax > 0){
507 fmtuserstring(&fmt, up->s.args[0], " ");
508 fmtprint(&fmt, "%d", errstrlen);
509 } else {
510 fmtprint(&fmt, "\"\" %d", errstrlen);
511 }
512 break;
513 case FD2PATH:
514 if(ureg->ax == -1)
515 fmtprint(&fmt, "\"\" %d", up->s.args[2]);
516 else {
517 fmtuserstring(&fmt, up->s.args[1], " ");
518 fmtprint(&fmt, "%d", errstrlen);
519 }
520 break;
521 case _READ:
522 offset = -1;
523 case PREAD:
524 if(ureg->ax == -1)
525 fmtprint(&fmt, "/\"\" %d 0x%ullx", up->s.args[2], *(vlong *)&up->s.args[3]);
526 else {
527 if (ureg->ax > 64)
528 len = 64;
529 else
530 len = ureg->ax;
531 fmtrwdata(&fmt, up->s.args[1], len, " ");
532 if(! offset)
533 offset = *(vlong *)&up->s.args[3];
534 fmtprint(&fmt, "%d %#llx", up->s.args[2], offset);
535 }
536 break;
537 }
538
539 if (syscallno == EXEC)
540 fmtprint(&fmt, " = %p \"%s\" %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
541 else
542 fmtprint(&fmt, " = %d \"%s\" %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
543
544 up->syscalltrace = fmtstrflush(&fmt);
545 }
546 /*
547 * Handle a system call.
548 */
549 static void
550 syscall(Ureg *ureg)
551 {
552 char *e;
553 ulong sp;
554 uchar *usp;
555 long ret;
556 int s;
557 ulong scallnr;
558 vlong startnsec, stopnsec;
559
560 USED(startnsec);
561 cycles(&up->kentry);
562 m->syscall++;
563 up->insyscall = 1;
564 up->pc = ureg->pc;
565 up->dbgreg = ureg;
566
567 if(up->procctl == Proc_tracesyscall){
568 up->procctl = Proc_stopme;
569 syscallprint(ureg);
570 procctl(up);
571 if(up->syscalltrace)
572 free(up->syscalltrace);
573 up->syscalltrace = nil;
574 startnsec = todget(nil);
575 }
576
577 scallnr = ureg->ax;
578 up->scallnr = scallnr;
579 if(scallnr == RFORK && up->fpstate == FPactive){
580 fpsave(&up->fpsave);
581 up->fpstate = FPinactive;
582 }
583 spllo();
584
585 sp = ureg->usp;
586 up->nerrlab = 0;
587 ret = -1;
588 if(!waserror()){
589 if(scallnr >= nsyscall || systab[scallnr] == 0){
590 pprint("bad sys call number %d pc %lux\n",
591 scallnr, ureg->pc);
592 postnote(up, 1, "sys: bad sys call", NDebug);
593 error(Ebadarg);
594 }
595
596
597 usp = uvalidaddr(sp, sizeof(Sargs)+BY2WD, 0);
598 up->s = *((Sargs*)(usp+BY2WD));
599 up->psstate = sysctab[scallnr];
600
601 ret = systab[scallnr](up->s.args);
602 poperror();
603 }else{
604 /* failure: save the error buffer for errstr */
605 e = up->syserrstr;
606 up->syserrstr = up->errstr;
607 up->errstr = e;
608 if(0 && up->pid == 1)
609 print("syscall %lud error %s\n", scallnr, up->syserrstr);
610 }
611 if(up->nerrlab){
612 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
613 // for(i = 0; i < NERR; i++)
614 // print("sp=%lux pc=%lux\n",
615 //XXX up->errlab[i].sp, up->errlab[i].pc);
616 panic("error stack");
617 }
618
619 // if(ret < 0)
620 // print("%d [%s] %s\n", up->pid, up->psstate, up->syserrstr);
621 // else
622 // print("%d [%s] %d\n", up->pid, up->psstate, ret);
623 // printmap();
624
625 /*
626 * Put return value in frame. On the x86 the syscall is
627 * just another trap and the return value from syscall is
628 * ignored. On other machines the return value is put into
629 * the results register by caller of syscall.
630 */
631 ureg->ax = ret;
632
633 if(up->procctl == Proc_tracesyscall){
634 stopnsec = todget(nil);
635 up->procctl = Proc_stopme;
636 retprint(ureg, scallnr, startnsec, stopnsec);
637 s = splhi();
638 procctl(up);
639 splx(s);
640 if(up->syscalltrace)
641 free(up->syscalltrace);
642 up->syscalltrace = nil;
643 }
644
645 up->insyscall = 0;
646 up->psstate = 0;
647
648 if(scallnr == NOTED)
649 noted(ureg, *(uint32*)(up->pmmu.uzero + sp+BY2WD));
650
651 if(scallnr!=RFORK && (up->procctl || up->nnote)){
652 splhi();
653 notify(ureg);
654 }
655 /* if we delayed sched because we held a lock, sched now */
656 if(up->delaysched)
657 sched();
658 kexit(ureg);
659 }
660
661 /*
662 * Call user, if necessary, with note.
663 * Pass user the Ureg struct and the note on his stack.
664 */
665 int
666 notify(Ureg* ureg)
667 {
668 int l;
669 ulong s, sp;
670 Note *n;
671 Ureg *upureg;
672
673 if(tracesyscalls)
674 iprint("notify\n");
675
676 if(up->procctl)
677 procctl(up);
678 if(up->nnote == 0)
679 return 0;
680
681 if(up->fpstate == FPactive){
682 fpsave(&up->fpsave);
683 up->fpstate = FPinactive;
684 }
685 up->fpstate |= FPillegal;
686
687 s = spllo();
688 qlock(&up->debug);
689 up->notepending = 0;
690 n = &up->note[0];
691 if(strncmp(n->msg, "sys:", 4) == 0){
692 l = strlen(n->msg);
693 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
694 l = ERRMAX-15;
695 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
696 }
697
698 if(n->flag!=NUser && (up->notified || up->notify==0)){
699 if(n->flag == NDebug)
700 pprint("suicide: %s\n", n->msg);
701 qunlock(&up->debug);
702 pexit(n->msg, n->flag!=NDebug);
703 }
704
705 if(up->notified){
706 qunlock(&up->debug);
707 splhi();
708 return 0;
709 }
710
711 if(!up->notify){
712 qunlock(&up->debug);
713 pexit(n->msg, n->flag!=NDebug);
714 }
715 sp = ureg->usp;
716 sp -= sizeof(Ureg);
717
718 if(!okaddr(up->notify, 1, 0)
719 || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
720 pprint("suicide: bad address in notify\n");
721 qunlock(&up->debug);
722 pexit("Suicide", 0);
723 }
724
725 uchar *uzero;
726 uzero = up->pmmu.uzero;
727 upureg = (void*)(uzero + sp);
728 memmove(upureg, ureg, sizeof(Ureg));
729 *(uint32*)(uzero + sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
730 up->ureg = sp;
731 sp -= BY2WD+ERRMAX;
732 memmove((char*)(uzero + sp), up->note[0].msg, ERRMAX);
733 sp -= 3*BY2WD;
734 *(uint32*)(uzero + sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
735 *(uint32*)(uzero + sp+1*BY2WD) = up->ureg; /* arg 1 is ureg* */
736 *(uint32*)(uzero + sp+0*BY2WD) = 0; /* arg 0 is pc */
737 ureg->usp = sp;
738 ureg->pc = up->notify;
739 up->notified = 1;
740 up->nnote--;
741 memmove(&up->lastnote, &up->note[0], sizeof(Note));
742 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
743
744 qunlock(&up->debug);
745 splx(s);
746 return 1;
747 }
748
749 /*
750 * Return user to state before notify()
751 */
752 static void
753 noted(Ureg* ureg, ulong arg0)
754 {
755 Ureg *nureg;
756 ulong oureg, sp;
757
758 qlock(&up->debug);
759 if(arg0!=NRSTR && !up->notified) {
760 qunlock(&up->debug);
761 pprint("call to noted() when not notified\n");
762 pexit("Suicide", 0);
763 }
764 up->notified = 0;
765
766 up->fpstate &= ~FPillegal;
767
768 /* sanity clause */
769 if(!okaddr(up->ureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
770 pprint("bad ureg in noted or call to noted when not notified\n");
771 qunlock(&up->debug);
772 pexit("Suicide", 0);
773 }
774
775 uchar *uzero;
776 uzero = up->pmmu.uzero;
777 oureg = up->ureg;
778 nureg = (Ureg*)(uzero + up->ureg);
779
780 /* don't let user change system flags */
781 nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
782
783 memmove(ureg, nureg, sizeof(Ureg));
784
785 switch(arg0){
786 case NCONT:
787 case NRSTR:
788 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
789 qunlock(&up->debug);
790 pprint("suicide: trap in noted\n");
791 pexit("Suicide", 0);
792 }
793 up->ureg = *(uint32*)(uzero+oureg-BY2WD);
794 qunlock(&up->debug);
795 break;
796
797 case NSAVE:
798 if(!okaddr(nureg->pc, BY2WD, 0)
799 || !okaddr(nureg->usp, BY2WD, 0)){
800 qunlock(&up->debug);
801 pprint("suicide: trap in noted\n");
802 pexit("Suicide", 0);
803 }
804 qunlock(&up->debug);
805 sp = oureg-4*BY2WD-ERRMAX;
806 splhi();
807 ureg->sp = sp;
808 ((uint32*)(uzero+sp))[1] = oureg; /* arg 1 0(FP) is ureg* */
809 ((uint32*)(uzero+sp))[0] = 0; /* arg 0 is pc */
810 break;
811
812 default:
813 pprint("unknown noted arg 0x%lux\n", arg0);
814 up->lastnote.flag = NDebug;
815 /* fall through */
816
817 case NDFLT:
818 if(up->lastnote.flag == NDebug){
819 qunlock(&up->debug);
820 pprint("suicide: %s\n", up->lastnote.msg);
821 } else
822 qunlock(&up->debug);
823 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
824 }
825 }
826
827 long
828 execregs(ulong entry, ulong ssize, ulong nargs)
829 {
830 uint32 *sp;
831 Ureg *ureg;
832
833 up->fpstate = FPinit;
834 fpoff();
835
836 sp = (uint32*)(up->pmmu.uzero + USTKTOP - ssize);
837 *--sp = nargs;
838
839 ureg = up->dbgreg;
840 ureg->usp = (uchar*)sp - up->pmmu.uzero;
841 //showexec(ureg->usp);
842 ureg->pc = entry;
843 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
844 }
845
846 /*
847 * return the userpc the last exception happened at
848 */
849 ulong
850 userpc(void)
851 {
852 Ureg *ureg;
853
854 ureg = (Ureg*)up->dbgreg;
855 return ureg->pc;
856 }
857
858 /* This routine must save the values of registers the user is not permitted
859 * to write from devproc and then restore the saved values before returning.
860 */
861 void
862 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
863 {
864 ulong flags;
865
866 flags = ureg->flags;
867 memmove(pureg, uva, n);
868 ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
869 }
870
871 static void
872 linkproc(void)
873 {
874 spllo();
875 up->kpfun(up->kparg);
876 pexit("kproc dying", 0);
877 }
878
879 void
880 kprocchild(Proc* p, void (*func)(void*), void* arg)
881 {
882 /*
883 * gotolabel() needs a word on the stack in
884 * which to place the return PC used to jump
885 * to linkproc().
886 */
887 labelinit(&p->sched, (ulong)linkproc, (ulong)p->kstack+KSTACK-BY2WD);
888
889 p->kpfun = func;
890 p->kparg = arg;
891 }
892
893 void
894 forkchild(Proc *p, Ureg *ureg)
895 {
896 Ureg *cureg;
897 void *sp;
898
899 /*
900 * Add 2*BY2WD to the stack to account for
901 * - the return PC
902 * - trap's argument (ur)
903 */
904 sp = (char*)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
905 labelinit(&p->sched, (ulong)forkret, (ulong)sp);
906
907 cureg = (Ureg*)((char*)sp+2*BY2WD);
908 memmove(cureg, ureg, sizeof(Ureg));
909 /* return value of syscall in child */
910 cureg->ax = 0;
911
912 /* Things from bottom of syscall which were never executed */
913 p->psstate = 0;
914 p->insyscall = 0;
915 }
916
917 /*
918 * Give enough context in the ureg to produce a kernel stack for
919 * a sleeping process. Or not.
920 */
921 void
922 setkernur(Ureg* ureg, Proc* p)
923 {
924 memset(ureg, 0, sizeof *ureg);
925 }
926
927 ulong
928 dbgpc(Proc *p)
929 {
930 Ureg *ureg;
931
932 ureg = p->dbgreg;
933 if(ureg == 0)
934 return 0;
935
936 return ureg->pc;
937 }
938
939 /*
940 * floating point and all its glory.
941 */
942
943 static char* mathmsg[] =
944 {
945 nil, /* handled below */
946 "denormalized operand",
947 "division by zero",
948 "numeric overflow",
949 "numeric underflow",
950 "precision loss",
951 };
952
953 static void
954 mathnote(void)
955 {
956 int i;
957 ulong status;
958 char *msg, note[ERRMAX];
959
960 status = up->fpsave.status;
961
962 /*
963 * Some attention should probably be paid here to the
964 * exception masks and error summary.
965 */
966 msg = "unknown exception";
967 for(i = 1; i <= 5; i++){
968 if(!((1<<i) & status))
969 continue;
970 msg = mathmsg[i];
971 break;
972 }
973 if(status & 0x01){
974 if(status & 0x40){
975 if(status & 0x200)
976 msg = "stack overflow";
977 else
978 msg = "stack underflow";
979 }else
980 msg = "invalid operation";
981 }
982 sprint(note, "sys: fp: %s fppc=0x%lux status=0x%lux", msg, up->fpsave.pc, status);
983 postnote(up, 1, note, NDebug);
984 }
985
986
987 /*
988 * math coprocessor emulation fault
989 */
990 static void
991 mathemu(Ureg *ureg, void *v)
992 {
993 if(up->fpstate & FPillegal){
994 /* someone did floating point in a note handler */
995 postnote(up, 1, "sys: floating point in note handler", NDebug);
996 return;
997 }
998 switch(up->fpstate){
999 case FPinit:
1000 fpinit();
1001 up->fpstate = FPactive;
1002 break;
1003 case FPinactive:
1004 /*
1005 * Before restoring the state, check for any pending
1006 * exceptions, there's no way to restore the state without
1007 * generating an unmasked exception.
1008 * More attention should probably be paid here to the
1009 * exception masks and error summary.
1010 */
1011 if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
1012 mathnote();
1013 break;
1014 }
1015 fprestore(&up->fpsave);
1016 up->fpstate = FPactive;
1017 break;
1018 case FPactive:
1019 panic("math emu pid %ld %s pc 0x%lux",
1020 up->pid, up->text, ureg->pc);
1021 break;
1022 }
1023 }
1024
1025 /*
1026 * math coprocessor segment overrun
1027 * TODO: When to call this?
1028 */
1029 void
1030 mathover(Ureg *u, void *v)
1031 {
1032 pexit("math overrun", 0);
1033 }
1034
1035 /*
1036 * math coprocessor error
1037 * TODO: When to call this?
1038 */
1039 void
1040 matherror(Ureg *ur, void *v)
1041 {
1042 /*
1043 * a write cycle to port 0xF0 clears the interrupt latch attached
1044 * to the error# line from the 387
1045 */
1046 // if(!(m->cpuiddx & 0x01))
1047 // outb(0xF0, 0xFF);
1048
1049 /*
1050 * save floating point state to check out error
1051 */
1052 fpenv(&up->fpsave);
1053 mathnote();
1054
1055 if(!okaddr(ur->pc, 1, 0))
1056 panic("fp: status %ux fppc=0x%lux pc=0x%lux",
1057 up->fpsave.status, up->fpsave.pc, ur->pc);
1058 }
1059
1060 /*
1061 * set up floating point for a new process
1062 */
1063 void
1064 procsetup(Proc*p)
1065 {
1066 p->fpstate = FPinit;
1067 fpoff();
1068 }
1069
1070 void
1071 procrestore(Proc *p)
1072 {
1073 uvlong t;
1074
1075 if(p->kp)
1076 return;
1077 cycles(&t);
1078 p->pcycles -= t;
1079 }
1080
1081 /*
1082 * Save the mach dependent part of the process state.
1083 */
1084 void
1085 procsave(Proc *p)
1086 {
1087 uvlong t;
1088
1089 cycles(&t);
1090 p->pcycles += t;
1091 if(p->fpstate == FPactive){
1092 if(p->state == Moribund)
1093 fpclear();
1094 else{
1095 /*
1096 * Fpsave() stores without handling pending
1097 * unmasked exeptions. Postnote() can't be called
1098 * here as sleep() already has up->rlock, so
1099 * the handling of pending exceptions is delayed
1100 * until the process runs again and generates an
1101 * emulation fault to activate the FPU.
1102 */
1103 fpsave(&p->fpsave);
1104 }
1105 p->fpstate = FPinactive;
1106 }
1107 }