1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "ureg.h" 7 #include "../port/error.h" 8 #include "tos.h" 9 #include <trace.h> 10 11 static Lock vctllock; 12 Vctl *vctl[256]; 13 14 int intrstack[5]; 15 uvlong intrtime[5]; 16 vlong lastoffset; 17 int inintr; 18 int nintr[10]; 19 int nintro; 20 int dblintr[64]; 21 ulong thisto[32]; 22 ulong thistoo; 23 vlong vnot[64]; 24 ulong vnon[64]; 25 26 void 27 intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name) 28 { 29 int vno; 30 Vctl *v; 31 32 if(f == nil){ 33 print("intrenable: nil handler for %d for %s\n", 34 irq, name); 35 return; 36 } 37 38 v = xalloc(sizeof(Vctl)); 39 v->isintr = 1; 40 v->irq = irq; 41 v->f = f; 42 v->a = a; 43 strncpy(v->name, name, KNAMELEN-1); 44 v->name[KNAMELEN-1] = 0; 45 46 ilock(&vctllock); 47 vno = vectorenable(v); 48 if(vno == -1){ 49 iunlock(&vctllock); 50 print("intrenable: couldn't enable irq %d for %s\n", 51 irq, v->name); 52 xfree(v); 53 return; 54 } 55 v->next = vctl[vno]; 56 vctl[vno] = v; 57 iunlock(&vctllock); 58 } 59 60 void 61 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name) 62 { 63 Vctl **pv, *v; 64 65 ilock(&vctllock); 66 pv = &vctl[irq]; 67 while (*pv && 68 ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a || 69 strcmp((*pv)->name, name))) 70 pv = &((*pv)->next); 71 72 if(*pv == nil){ 73 print("intrdisable: irq %d not found\n", irq); 74 iunlock(&vctllock); 75 return; 76 } 77 78 v = *pv; 79 *pv = (*pv)->next; /* Link out the entry */ 80 81 if(vctl[irq] == nil) 82 vectordisable(v); 83 iunlock(&vctllock); 84 xfree(v); 85 } 86 87 void syscall(Ureg*); 88 void noted(Ureg*, ulong); 89 static void _dumpstack(Ureg*); 90 91 char *excname[] = 92 { 93 "reserved 0", 94 "system reset", 95 "machine check", 96 "data access", 97 "instruction access", 98 "external interrupt", 99 "alignment", 100 "program exception", 101 "floating-point unavailable", 102 "decrementer", 103 "reserved A", 104 "reserved B", 105 "system call", 106 "trace trap", 107 "floating point assist", 108 "reserved F", 109 "reserved 10", 110 "data load translation miss", 111 "data store translation miss", 112 "instruction address breakpoint", 113 "system management interrupt", 114 }; 115 116 char *fpcause[] = 117 { 118 "inexact operation", 119 "division by zero", 120 "underflow", 121 "overflow", 122 "invalid operation", 123 }; 124 char *fpexcname(Ureg*, ulong, char*); 125 #define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */ 126 127 128 char *regname[]={ 129 "CAUSE", "SRR1", 130 "PC", "GOK", 131 "LR", "CR", 132 "XER", "CTR", 133 "R0", "R1", 134 "R2", "R3", 135 "R4", "R5", 136 "R6", "R7", 137 "R8", "R9", 138 "R10", "R11", 139 "R12", "R13", 140 "R14", "R15", 141 "R16", "R17", 142 "R18", "R19", 143 "R20", "R21", 144 "R22", "R23", 145 "R24", "R25", 146 "R26", "R27", 147 "R28", "R29", 148 "R30", "R31", 149 "DCMP", "ICMP", 150 "DMISS", "IMISS", 151 "HASH1", "HASH2", 152 "DAR", "DSISR", 153 }; 154 155 void 156 kexit(Ureg*) 157 { 158 uvlong t; 159 Tos *tos; 160 161 /* precise time accounting, kernel exit */ 162 tos = (Tos*)(USTKTOP-sizeof(Tos)); 163 cycles(&t); 164 tos->kcycles += t - up->kentry; 165 tos->pcycles = up->pcycles; 166 tos->pid = up->pid; 167 } 168 169 void 170 trap(Ureg *ureg) 171 { 172 int ecode, user; 173 char buf[ERRMAX], *s; 174 extern FPsave initfp; 175 176 ecode = (ureg->cause >> 8) & 0xff; 177 user = (ureg->srr1 & MSR_PR) != 0; 178 if(user){ 179 cycles(&up->kentry); 180 up->dbgreg = ureg; 181 } 182 if(ureg->status & MSR_RI == 0) 183 print("double fault?: ecode = %d\n", ecode); 184 185 switch(ecode) { 186 case CEI: 187 m->intr++; 188 intr(ureg); 189 break; 190 case CDEC: 191 clockintr(ureg); 192 break; 193 case CDSI: 194 m->pfault++; 195 if (up == nil){ 196 dumpregs(ureg); 197 panic("kernel fault"); 198 } 199 up->mmureg = ureg; 200 faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0); 201 break; 202 case CISI: 203 m->pfault++; 204 if (up == nil){ 205 dumpregs(ureg); 206 panic("kernel fault"); 207 } 208 up->mmureg = ureg; 209 faultpower(ureg, ureg->pc, 1); 210 break; 211 case CIMISS: /* instruction miss */ 212 if (up == nil){ 213 dumpregs(ureg); 214 panic("kernel fault"); 215 } 216 up->mmureg = ureg; 217 faultpower(ureg, ureg->imiss, 1); 218 break; 219 case CLMISS: /* data load miss */ 220 if (up == nil){ 221 dumpregs(ureg); 222 panic("kernel fault"); 223 } 224 up->mmureg = ureg; 225 faultpower(ureg, ureg->dmiss, 1); 226 break; 227 case CSMISS: /* data store miss */ 228 if (up == nil){ 229 dumpregs(ureg); 230 panic("kernel fault"); 231 } 232 up->mmureg = ureg; 233 faultpower(ureg, ureg->dmiss, 0); 234 break; 235 236 case CSYSCALL: 237 if(!user) 238 panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1); 239 syscall(ureg); 240 if (up->delaysched){ 241 sched(); 242 splhi(); 243 } 244 kexit(ureg); 245 return; /* syscall() calls notify itself, don't do it again */ 246 247 case CFPU: 248 if(!user || up == nil) { 249 dumpregs(ureg); 250 panic("floating point in kernel"); 251 } 252 switch(up->fpstate){ 253 case FPinit: 254 fprestore(&initfp); 255 up->fpstate = FPactive; 256 break; 257 case FPinactive: 258 fprestore(&up->fpsave); 259 up->fpstate = FPactive; 260 break; 261 case FPactive: 262 print("up->fpstate %d\n", up->fpstate); 263 delay(100); 264 dumpregs(ureg); 265 delay(200); 266 panic("fpstate"); 267 break; 268 default: 269 if(user){ 270 spllo(); 271 sprint(buf, "sys: floating point in note handler:"); 272 postnote(up, 1, buf, NDebug); 273 break; 274 } 275 panic("kernel fpstate illegal"); 276 } 277 ureg->srr1 |= MSR_FP; 278 break; 279 case CPROG: 280 if(ureg->status & (1<<19)) 281 s = "floating point exception"; 282 else if(ureg->status & (1<<18)) 283 s = "illegal instruction"; 284 else if(ureg->status & (1<<17)) 285 s = "privileged instruction"; 286 else 287 s = "undefined program exception"; 288 if(user){ 289 spllo(); 290 sprint(buf, "sys: trap: %s", s); 291 postnote(up, 1, buf, NDebug); 292 break; 293 } 294 dumpregs(ureg); 295 panic(s); 296 break; 297 default: 298 if(ecode < nelem(excname) && user){ 299 spllo(); 300 sprint(buf, "sys: trap: %s", excname[ecode]); 301 postnote(up, 1, buf, NDebug); 302 break; 303 } 304 dumpregs(ureg); 305 if(ecode < nelem(excname)) 306 panic("%s", excname[ecode]); 307 panic("unknown trap/intr: %d\n", ecode); 308 } 309 310 /* restoreureg must execute at high IPL */ 311 splhi(); 312 313 /* delaysched set because we held a lock or because our quantum ended */ 314 if(up && up->delaysched && ecode == CDEC){ 315 sched(); 316 splhi(); 317 } 318 319 if(user) { 320 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){ 321 postnote(up, 1, buf, NDebug); 322 } 323 notify(ureg); 324 if(up->fpstate != FPactive) 325 ureg->srr1 &= ~MSR_FP; 326 kexit(ureg); 327 } 328 } 329 330 void 331 faultpower(Ureg *ureg, ulong addr, int read) 332 { 333 int user, insyscall, n; 334 char buf[ERRMAX]; 335 336 user = (ureg->srr1 & MSR_PR) != 0; 337 insyscall = up->insyscall; 338 up->insyscall = 1; 339 n = fault(addr, read); 340 if(n < 0){ 341 if(!user){ 342 dumpregs(ureg); 343 panic("fault: 0x%lux", addr); 344 } 345 sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr); 346 postnote(up, 1, buf, NDebug); 347 } 348 up->insyscall = insyscall; 349 } 350 351 void 352 sethvec(int v, void (*r)(void)) 353 { 354 ulong *vp, pa, o; 355 356 vp = KADDR(v); 357 vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ 358 vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ 359 vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ 360 pa = PADDR(r); 361 o = pa >> 25; 362 if(o != 0 && o != 0x7F){ 363 /* a branch too far */ 364 vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ 365 vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ 366 vp[5] = 0x7c0803a6; /* MOVW R0, LR */ 367 vp[6] = 0x4e800021; /* BL (LR) */ 368 }else 369 vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ 370 } 371 372 void 373 setmvec(int v, void (*r)(void), void (*t)(void)) 374 { 375 ulong *vp, pa, o, n; 376 377 vp = KADDR(v); 378 n = 0; 379 vp[n++] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ 380 vp[n++] = 0x7c0802a6; /* MOVW LR, R0 */ 381 vp[n++] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ 382 pa = PADDR(r); 383 o = pa >> 25; 384 if(o != 0 && o != 0x7F){ 385 /* a branch too far */ 386 vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ 387 vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ 388 vp[n++] = 0x7c0803a6; /* MOVW R0, LR */ 389 vp[n++] = 0x4e800021; /* BL (LR) */ 390 }else 391 vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ 392 pa = PADDR(t); 393 o = pa >> 25; 394 if(o != 0 && o != 0x7F){ 395 /* a branch too far */ 396 vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ 397 vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ 398 vp[n++] = 0x7c0803a6; /* MOVW R0, LR */ 399 vp[n] = 0x4e800021; /* BL (LR) */ 400 }else 401 vp[n] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ 402 } 403 404 405 void 406 intr(Ureg *ureg) 407 { 408 int vno, pvno, i; 409 Vctl *ctl, *v; 410 void (*pt)(Proc*, int, vlong); 411 uvlong tt, x; 412 413 cycles(&tt); 414 pt = proctrace; 415 pvno = -1; 416 for(i = 0; i < 64; i++){ 417 vno = intvec(); 418 if(vno == 0) 419 break; 420 cycles(&x); 421 vnot[vno] -= x; 422 if(vno == pvno) 423 dblintr[vno]++; 424 pvno = vno; 425 if(pt && up && up->trace) 426 pt(up, (vno << 16) | SInts, 0); 427 428 if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) { 429 iprint("spurious intr %d\n", vno); 430 return; 431 } 432 433 for(v = ctl; v != nil; v = v->next) 434 if(v->f) 435 v->f(ureg, v->a); 436 437 intend(vno); /* reenable the interrupt */ 438 439 if(pt && up && up->trace) 440 pt(up, (vno << 16) | SInte, 0); 441 cycles(&x); 442 vnot[vno] += x; 443 vnon[vno]++; 444 } 445 if(i < nelem(nintr)) 446 nintr[i]++; 447 else 448 nintro++; 449 cycles(&x); 450 tt = x - tt; 451 i = tt / 3600; /* 100 microseconds units */ 452 if(i < nelem(thisto)) 453 thisto[i]++; 454 else 455 thistoo++; 456 457 if(up) 458 preempted(); 459 } 460 461 char* 462 fpexcname(Ureg *ur, ulong fpscr, char *buf) 463 { 464 int i; 465 char *s; 466 ulong fppc; 467 468 fppc = ur->pc; 469 s = 0; 470 fpscr >>= 3; /* trap enable bits */ 471 fpscr &= (fpscr>>22); /* anded with exceptions */ 472 for(i=0; i<5; i++) 473 if(fpscr & (1<<i)) 474 s = fpcause[i]; 475 if(s == 0) 476 return "no floating point exception"; 477 sprint(buf, "%s fppc=0x%lux", s, fppc); 478 return buf; 479 } 480 481 /* 482 * Fill in enough of Ureg to get a stack trace, and call a function. 483 * Used by debugging interface rdb. 484 */ 485 486 static void 487 getpcsp(ulong *pc, ulong *sp) 488 { 489 *pc = getcallerpc(&pc); 490 *sp = (ulong)&pc-4; 491 } 492 493 void 494 callwithureg(void (*fn)(Ureg*)) 495 { 496 Ureg ureg; 497 498 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp); 499 ureg.lr = getcallerpc(&fn); 500 fn(&ureg); 501 } 502 503 static void 504 _dumpstack(Ureg *ureg) 505 { 506 ulong l, sl, el, v; 507 int i; 508 509 l = (ulong)&l; 510 if(up == 0){ 511 el = (ulong)m+BY2PG; 512 sl = el-KSTACK; 513 } 514 else{ 515 sl = (ulong)up->kstack; 516 el = sl + KSTACK; 517 } 518 if(l > el || l < sl){ 519 el = (ulong)m+BY2PG; 520 sl = el-KSTACK; 521 } 522 if(l > el || l < sl) 523 return; 524 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr); 525 i = 0; 526 for(; l < el; l += 4){ 527 v = *(ulong*)l; 528 if(KTZERO < v && v < (ulong)etext){ 529 print("%.8lux=%.8lux ", l, v); 530 if(i++ == 4){ 531 print("\n"); 532 i = 0; 533 } 534 } 535 } 536 } 537 538 void 539 dumpstack(void) 540 { 541 callwithureg(_dumpstack); 542 } 543 544 void 545 dumpregs(Ureg *ur) 546 { 547 int i; 548 ulong *l; 549 550 if(up) { 551 print("registers for %s %ld\n", up->text, up->pid); 552 if(ur->srr1 & MSR_PR == 0) 553 if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK) 554 print("invalid stack ptr\n"); 555 } 556 else 557 print("registers for kernel\n"); 558 559 for(i=0; i<16; i+=2) 560 print("sr[%x]\t0x%.8lux\tsr[%x]\t0x%.8lux\n", i, getsr(i<<28), i+1, getsr((i+1)<<28)); 561 l = &ur->cause; 562 for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2) 563 print("%s\t0x%.8lux\t%s\t0x%.8lux\n", regname[i], l[0], regname[i+1], l[1]); 564 delay(500); 565 } 566 567 static void 568 linkproc(void) 569 { 570 spllo(); 571 (*up->kpfun)(up->kparg); 572 pexit("", 0); 573 } 574 575 void 576 kprocchild(Proc *p, void (*func)(void*), void *arg) 577 { 578 p->sched.pc = (ulong)linkproc; 579 p->sched.sp = (ulong)p->kstack+KSTACK; 580 581 p->kpfun = func; 582 p->kparg = arg; 583 } 584 585 /* 586 * called in syscallfmt.c, sysfile.c, sysproc.c 587 */ 588 void 589 validalign(uintptr addr, unsigned align) 590 { 591 /* 592 * Plan 9 is a 32-bit O/S, and the hardware it runs on 593 * does not usually have instructions which move 64-bit 594 * quantities directly, synthesizing the operations 595 * with 32-bit move instructions. Therefore, the compiler 596 * (and hardware) usually only enforce 32-bit alignment, 597 * if at all. 598 * 599 * Take this out if the architecture warrants it. 600 */ 601 if(align == sizeof(vlong)) 602 align = sizeof(long); 603 604 /* 605 * Check align is a power of 2, then addr alignment. 606 */ 607 if((align != 0 && !(align & (align-1))) && !(addr & (align-1))) 608 return; 609 postnote(up, 1, "sys: odd address", NDebug); 610 error(Ebadarg); 611 /*NOTREACHED*/ 612 } 613 614 long 615 execregs(ulong entry, ulong ssize, ulong nargs) 616 { 617 ulong *sp; 618 Ureg *ureg; 619 620 sp = (ulong*)(USTKTOP - ssize); 621 *--sp = nargs; 622 623 ureg = up->dbgreg; 624 ureg->usp = (ulong)sp; 625 ureg->pc = entry; 626 ureg->srr1 &= ~MSR_FP; /* disable floating point */ 627 up->fpstate = FPinit; 628 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */ 629 } 630 631 void 632 forkchild(Proc *p, Ureg *ur) 633 { 634 Ureg *cur; 635 636 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE; 637 p->sched.pc = (ulong)forkret; 638 639 cur = (Ureg*)(p->sched.sp+2*BY2WD); 640 memmove(cur, ur, sizeof(Ureg)); 641 cur->r3 = 0; 642 643 /* Things from bottom of syscall we never got to execute */ 644 p->psstate = 0; 645 p->insyscall = 0; 646 } 647 648 ulong 649 userpc(void) 650 { 651 Ureg *ureg; 652 653 ureg = (Ureg*)up->dbgreg; 654 return ureg->pc; 655 } 656 657 658 /* This routine must save the values of registers the user is not 659 * permitted to write from devproc and then restore the saved values 660 * before returning 661 */ 662 void 663 setregisters(Ureg *xp, char *pureg, char *uva, int n) 664 { 665 ulong status; 666 667 status = xp->status; 668 memmove(pureg, uva, n); 669 xp->status = status; 670 } 671 672 /* Give enough context in the ureg to produce a kernel stack for 673 * a sleeping process 674 */ 675 void 676 setkernur(Ureg* ureg, Proc* p) 677 { 678 ureg->pc = p->sched.pc; 679 ureg->sp = p->sched.sp+4; 680 } 681 682 ulong 683 dbgpc(Proc *p) 684 { 685 Ureg *ureg; 686 687 ureg = p->dbgreg; 688 if(ureg == 0) 689 return 0; 690 691 return ureg->pc; 692 } 693 694 /* 695 * system calls 696 */ 697 #include "../port/systab.h" 698 699 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */ 700 void 701 syscall(Ureg* ureg) 702 { 703 int i; 704 char *e; 705 long ret; 706 ulong sp, scallnr; 707 708 m->syscall++; 709 up->insyscall = 1; 710 up->pc = ureg->pc; 711 up->dbgreg = ureg; 712 713 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){ 714 print("fpstate check, entry syscall\n"); 715 delay(200); 716 dumpregs(ureg); 717 print("fpstate check, entry syscall\n"); 718 } 719 720 scallnr = ureg->r3; 721 up->scallnr = ureg->r3; 722 if(scallnr == RFORK && up->fpstate == FPactive){ 723 fpsave(&up->fpsave); 724 up->fpstate = FPinactive; 725 } 726 spllo(); 727 728 sp = ureg->usp; 729 up->nerrlab = 0; 730 ret = -1; 731 if(!waserror()){ 732 if(scallnr >= nsyscall || systab[scallnr] == nil){ 733 pprint("bad sys call number %ld pc %lux\n", scallnr, ureg->pc); 734 postnote(up, 1, "sys: bad sys call", NDebug); 735 error(Ebadarg); 736 } 737 738 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) 739 validaddr(sp, sizeof(Sargs)+BY2WD, 0); 740 741 up->s = *((Sargs*)(sp+BY2WD)); 742 up->psstate = sysctab[scallnr]; 743 744 ret = systab[scallnr](up->s.args); 745 poperror(); 746 }else{ 747 /* failure: save the error buffer for errstr */ 748 e = up->syserrstr; 749 up->syserrstr = up->errstr; 750 up->errstr = e; 751 } 752 if(up->nerrlab){ 753 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab); 754 print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr); 755 for(i = 0; i < NERR; i++) 756 print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc); 757 panic("error stack"); 758 } 759 760 up->insyscall = 0; 761 up->psstate = 0; 762 763 /* 764 * Put return value in frame. On the x86 the syscall is 765 * just another trap and the return value from syscall is 766 * ignored. On other machines the return value is put into 767 * the results register by caller of syscall. 768 */ 769 ureg->r3 = ret; 770 771 if(scallnr == NOTED) 772 noted(ureg, *(ulong*)(sp+BY2WD)); 773 774 /* restoreureg must execute at high IPL */ 775 splhi(); 776 if(scallnr!=RFORK) 777 notify(ureg); 778 779 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){ 780 print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid); 781 dumpregs(ureg); 782 } 783 if(up->fpstate != FPactive) 784 ureg->srr1 &= ~MSR_FP; 785 } 786 787 /* 788 * Call user, if necessary, with note. 789 * Pass user the Ureg struct and the note on his stack. 790 */ 791 int 792 notify(Ureg* ur) 793 { 794 int l; 795 ulong s, sp; 796 Note *n; 797 798 if(up->procctl) 799 procctl(up); 800 if(up->nnote == 0) 801 return 0; 802 803 s = spllo(); 804 qlock(&up->debug); 805 up->notepending = 0; 806 n = &up->note[0]; 807 if(strncmp(n->msg, "sys:", 4) == 0){ 808 l = strlen(n->msg); 809 if(l > ERRMAX-15) /* " pc=0x12345678\0" */ 810 l = ERRMAX-15; 811 sprint(n->msg+l, " pc=0x%.8lux", ur->pc); 812 } 813 814 if(n->flag!=NUser && (up->notified || up->notify==0)){ 815 if(n->flag == NDebug) 816 pprint("suicide: %s\n", n->msg); 817 qunlock(&up->debug); 818 pexit(n->msg, n->flag!=NDebug); 819 } 820 821 if(up->notified) { 822 qunlock(&up->debug); 823 splhi(); 824 return 0; 825 } 826 827 if(!up->notify) { 828 qunlock(&up->debug); 829 pexit(n->msg, n->flag!=NDebug); 830 } 831 832 if(up->fpstate == FPactive){ 833 fpsave(&up->fpsave); 834 up->fpstate = FPinactive; 835 } 836 up->fpstate |= FPillegal; 837 838 sp = ur->usp & ~(BY2V-1); 839 sp -= sizeof(Ureg); 840 841 if(!okaddr((ulong)up->notify, BY2WD, 0) || 842 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) { 843 pprint("suicide: bad address or sp in notify\n"); 844 qunlock(&up->debug); 845 pexit("Suicide", 0); 846 } 847 848 memmove((Ureg*)sp, ur, sizeof(Ureg)); 849 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ 850 up->ureg = (void*)sp; 851 sp -= BY2WD+ERRMAX; 852 memmove((char*)sp, up->note[0].msg, ERRMAX); 853 sp -= 3*BY2WD; 854 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ 855 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */ 856 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */ 857 ((ulong*)sp)[0] = 0; /* arg 0 is pc */ 858 ur->usp = sp; 859 ur->pc = (ulong)up->notify; 860 up->notified = 1; 861 up->nnote--; 862 memmove(&up->lastnote, &up->note[0], sizeof(Note)); 863 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 864 865 qunlock(&up->debug); 866 splx(s); 867 return 1; 868 } 869 870 871 /* 872 * Return user to state before notify() 873 */ 874 void 875 noted(Ureg* ureg, ulong arg0) 876 { 877 Ureg *nureg; 878 ulong oureg, sp; 879 880 qlock(&up->debug); 881 if(arg0!=NRSTR && !up->notified) { 882 qunlock(&up->debug); 883 pprint("call to noted() when not notified\n"); 884 pexit("Suicide", 0); 885 } 886 up->notified = 0; 887 888 nureg = up->ureg; /* pointer to user returned Ureg struct */ 889 890 /* sanity clause */ 891 oureg = (ulong)nureg; 892 if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ 893 pprint("bad ureg in noted or call to noted when not notified\n"); 894 qunlock(&up->debug); 895 pexit("Suicide", 0); 896 } 897 898 memmove(ureg, nureg, sizeof(Ureg)); 899 900 switch(arg0){ 901 case NCONT: 902 case NRSTR: 903 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ 904 pprint("suicide: trap in noted\n"); 905 qunlock(&up->debug); 906 pexit("Suicide", 0); 907 } 908 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); 909 qunlock(&up->debug); 910 break; 911 912 case NSAVE: 913 if(!okaddr(nureg->pc, BY2WD, 0) 914 || !okaddr(nureg->usp, BY2WD, 0)){ 915 pprint("suicide: trap in noted\n"); 916 qunlock(&up->debug); 917 pexit("Suicide", 0); 918 } 919 qunlock(&up->debug); 920 sp = oureg-4*BY2WD-ERRMAX; 921 splhi(); 922 ureg->sp = sp; 923 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ 924 ((ulong*)sp)[0] = 0; /* arg 0 is pc */ 925 break; 926 927 default: 928 pprint("unknown noted arg 0x%lux\n", arg0); 929 up->lastnote.flag = NDebug; 930 /* fall through */ 931 932 case NDFLT: 933 if(up->lastnote.flag == NDebug) 934 pprint("suicide: %s\n", up->lastnote.msg); 935 qunlock(&up->debug); 936 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); 937 } 938 up->fpstate &= ~FPillegal; 939 if (up->fpstate == FPactive) 940 ureg->srr1 |= MSR_FP; 941 else 942 ureg->srr1 &= ~MSR_FP; 943 } 944