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 }