1 #include "u.h" 2 #include "tos.h" 3 #include "../port/lib.h" 4 #include "mem.h" 5 #include "dat.h" 6 #include "fns.h" 7 #include "io.h" 8 #include "ureg.h" 9 #include "../port/error.h" 10 #include <trace.h> 11 12 static int trapinited; 13 14 void noted(Ureg*, ulong); 15 16 static void debugbpt(Ureg*, void*); 17 static void fault386(Ureg*, void*); 18 static void doublefault(Ureg*, void*); 19 static void unexpected(Ureg*, void*); 20 static void _dumpstack(Ureg*); 21 22 static Lock vctllock; 23 static Vctl *vctl[256]; 24 25 enum 26 { 27 Ntimevec = 20 /* number of time buckets for each intr */ 28 }; 29 ulong intrtimes[256][Ntimevec]; 30 31 void 32 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) 33 { 34 int vno; 35 Vctl *v; 36 37 if(f == nil){ 38 print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n", 39 irq, tbdf, name); 40 return; 41 } 42 43 v = xalloc(sizeof(Vctl)); 44 v->isintr = 1; 45 v->irq = irq; 46 v->tbdf = tbdf; 47 v->f = f; 48 v->a = a; 49 strncpy(v->name, name, KNAMELEN-1); 50 v->name[KNAMELEN-1] = 0; 51 52 ilock(&vctllock); 53 vno = arch->intrenable(v); 54 if(vno == -1){ 55 iunlock(&vctllock); 56 print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n", 57 irq, tbdf, v->name); 58 xfree(v); 59 return; 60 } 61 if(vctl[vno]){ 62 if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi) 63 panic("intrenable: handler: %s %s %luX %luX %luX %luX\n", 64 vctl[vno]->name, v->name, 65 vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi); 66 v->next = vctl[vno]; 67 } 68 vctl[vno] = v; 69 iunlock(&vctllock); 70 } 71 72 int 73 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name) 74 { 75 Vctl **pv, *v; 76 int vno; 77 78 /* 79 * For now, none of this will work with the APIC code, 80 * there is no mapping between irq and vector as the IRQ 81 * is pretty meaningless. 82 */ 83 if(arch->intrvecno == nil) 84 return -1; 85 vno = arch->intrvecno(irq); 86 ilock(&vctllock); 87 pv = &vctl[vno]; 88 while (*pv && 89 ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a || 90 strcmp((*pv)->name, name))) 91 pv = &((*pv)->next); 92 assert(*pv); 93 94 v = *pv; 95 *pv = (*pv)->next; /* Link out the entry */ 96 97 if(vctl[vno] == nil && arch->intrdisable != nil) 98 arch->intrdisable(irq); 99 iunlock(&vctllock); 100 xfree(v); 101 return 0; 102 } 103 104 static long 105 irqallocread(Chan*, void *vbuf, long n, vlong offset) 106 { 107 char *buf, *p, str[2*(11+1)+KNAMELEN+1+1]; 108 int m, vno; 109 long oldn; 110 Vctl *v; 111 112 if(n < 0 || offset < 0) 113 error(Ebadarg); 114 115 oldn = n; 116 buf = vbuf; 117 for(vno=0; vno<nelem(vctl); vno++){ 118 for(v=vctl[vno]; v; v=v->next){ 119 m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name); 120 if(m <= offset) /* if do not want this, skip entry */ 121 offset -= m; 122 else{ 123 /* skip offset bytes */ 124 m -= offset; 125 p = str+offset; 126 offset = 0; 127 128 /* write at most max(n,m) bytes */ 129 if(m > n) 130 m = n; 131 memmove(buf, p, m); 132 n -= m; 133 buf += m; 134 135 if(n == 0) 136 return oldn; 137 } 138 } 139 } 140 return oldn - n; 141 } 142 143 void 144 trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) 145 { 146 Vctl *v; 147 148 if(vno < 0 || vno >= VectorPIC) 149 panic("trapenable: vno %d\n", vno); 150 v = xalloc(sizeof(Vctl)); 151 v->tbdf = BUSUNKNOWN; 152 v->f = f; 153 v->a = a; 154 strncpy(v->name, name, KNAMELEN); 155 v->name[KNAMELEN-1] = 0; 156 157 ilock(&vctllock); 158 if(vctl[vno]) 159 v->next = vctl[vno]->next; 160 vctl[vno] = v; 161 iunlock(&vctllock); 162 } 163 164 static void 165 nmienable(void) 166 { 167 int x; 168 169 /* 170 * Hack: should be locked with NVRAM access. 171 */ 172 outb(0x70, 0x80); /* NMI latch clear */ 173 outb(0x70, 0); 174 175 x = inb(0x61) & 0x07; /* Enable NMI */ 176 outb(0x61, 0x08|x); 177 outb(0x61, x); 178 } 179 180 /* 181 * Minimal trap setup. Just enough so that we can panic 182 * on traps (bugs) during kernel initialization. 183 * Called very early - malloc is not yet available. 184 */ 185 void 186 trapinit0(void) 187 { 188 int d1, v; 189 ulong vaddr; 190 Segdesc *idt; 191 192 idt = (Segdesc*)IDTADDR; 193 vaddr = (ulong)vectortable; 194 for(v = 0; v < 256; v++){ 195 d1 = (vaddr & 0xFFFF0000)|SEGP; 196 switch(v){ 197 198 case VectorBPT: 199 d1 |= SEGPL(3)|SEGIG; 200 break; 201 202 case VectorSYSCALL: 203 d1 |= SEGPL(3)|SEGIG; 204 break; 205 206 default: 207 d1 |= SEGPL(0)|SEGIG; 208 break; 209 } 210 idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16); 211 idt[v].d1 = d1; 212 vaddr += 6; 213 } 214 } 215 216 void 217 trapinit(void) 218 { 219 /* 220 * Special traps. 221 * Syscall() is called directly without going through trap(). 222 */ 223 trapenable(VectorBPT, debugbpt, 0, "debugpt"); 224 trapenable(VectorPF, fault386, 0, "fault386"); 225 trapenable(Vector2F, doublefault, 0, "doublefault"); 226 trapenable(Vector15, unexpected, 0, "unexpected"); 227 nmienable(); 228 229 addarchfile("irqalloc", 0444, irqallocread, nil); 230 trapinited = 1; 231 } 232 233 static char* excname[32] = { 234 "divide error", 235 "debug exception", 236 "nonmaskable interrupt", 237 "breakpoint", 238 "overflow", 239 "bounds check", 240 "invalid opcode", 241 "coprocessor not available", 242 "double fault", 243 "coprocessor segment overrun", 244 "invalid TSS", 245 "segment not present", 246 "stack exception", 247 "general protection violation", 248 "page fault", 249 "15 (reserved)", 250 "coprocessor error", 251 "alignment check", 252 "machine check", 253 "19 (reserved)", 254 "20 (reserved)", 255 "21 (reserved)", 256 "22 (reserved)", 257 "23 (reserved)", 258 "24 (reserved)", 259 "25 (reserved)", 260 "26 (reserved)", 261 "27 (reserved)", 262 "28 (reserved)", 263 "29 (reserved)", 264 "30 (reserved)", 265 "31 (reserved)", 266 }; 267 268 /* 269 * keep histogram of interrupt service times 270 */ 271 void 272 intrtime(Mach*, int vno) 273 { 274 ulong diff; 275 ulong x; 276 277 x = perfticks(); 278 diff = x - m->perf.intrts; 279 m->perf.intrts = x; 280 281 m->perf.inintr += diff; 282 if(up == nil && m->perf.inidle > diff) 283 m->perf.inidle -= diff; 284 285 diff /= m->cpumhz*100; // quantum = 100µsec 286 if(diff >= Ntimevec) 287 diff = Ntimevec-1; 288 intrtimes[vno][diff]++; 289 } 290 291 /* go to user space */ 292 void 293 kexit(Ureg*) 294 { 295 uvlong t; 296 Tos *tos; 297 298 /* precise time accounting, kernel exit */ 299 tos = (Tos*)(USTKTOP-sizeof(Tos)); 300 cycles(&t); 301 tos->kcycles += t - up->kentry; 302 tos->pcycles = up->pcycles; 303 tos->pid = up->pid; 304 } 305 306 /* 307 * All traps come here. It is slower to have all traps call trap() 308 * rather than directly vectoring the handler. However, this avoids a 309 * lot of code duplication and possible bugs. The only exception is 310 * VectorSYSCALL. 311 * Trap is called with interrupts disabled via interrupt-gates. 312 */ 313 void 314 trap(Ureg* ureg) 315 { 316 int clockintr, i, vno, user; 317 char buf[ERRMAX]; 318 Vctl *ctl, *v; 319 Mach *mach; 320 321 if(!trapinited){ 322 /* fault386 can give a better error message */ 323 if(ureg->trap == VectorPF) 324 fault386(ureg, nil); 325 panic("trap %lud: not ready", ureg->trap); 326 } 327 328 m->perf.intrts = perfticks(); 329 user = (ureg->cs & 0xFFFF) == UESEL; 330 if(user){ 331 up->dbgreg = ureg; 332 cycles(&up->kentry); 333 } 334 335 clockintr = 0; 336 337 vno = ureg->trap; 338 if(ctl = vctl[vno]){ 339 if(ctl->isintr){ 340 m->intr++; 341 if(vno >= VectorPIC && vno != VectorSYSCALL) 342 m->lastintr = ctl->irq; 343 } 344 345 if(ctl->isr) 346 ctl->isr(vno); 347 for(v = ctl; v != nil; v = v->next){ 348 if(v->f) 349 v->f(ureg, v->a); 350 } 351 if(ctl->eoi) 352 ctl->eoi(vno); 353 354 if(ctl->isintr){ 355 intrtime(m, vno); 356 357 if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER) 358 clockintr = 1; 359 360 if(up && !clockintr) 361 preempted(); 362 } 363 } 364 else if(vno <= nelem(excname) && user){ 365 spllo(); 366 sprint(buf, "sys: trap: %s", excname[vno]); 367 postnote(up, 1, buf, NDebug); 368 } 369 else if(vno >= VectorPIC && vno != VectorSYSCALL){ 370 /* 371 * An unknown interrupt. 372 * Check for a default IRQ7. This can happen when 373 * the IRQ input goes away before the acknowledge. 374 * In this case, a 'default IRQ7' is generated, but 375 * the corresponding bit in the ISR isn't set. 376 * In fact, just ignore all such interrupts. 377 */ 378 379 /* call all interrupt routines, just in case */ 380 for(i = VectorPIC; i <= MaxIrqLAPIC; i++){ 381 ctl = vctl[i]; 382 if(ctl == nil) 383 continue; 384 if(!ctl->isintr) 385 continue; 386 for(v = ctl; v != nil; v = v->next){ 387 if(v->f) 388 v->f(ureg, v->a); 389 } 390 /* should we do this? */ 391 if(ctl->eoi) 392 ctl->eoi(i); 393 } 394 395 /* clear the interrupt */ 396 i8259isr(vno); 397 398 if(0)print("cpu%d: spurious interrupt %d, last %d\n", 399 m->machno, vno, m->lastintr); 400 if(0)if(conf.nmach > 1){ 401 for(i = 0; i < 32; i++){ 402 if(!(active.machs & (1<<i))) 403 continue; 404 mach = MACHP(i); 405 if(m->machno == mach->machno) 406 continue; 407 print(" cpu%d: last %d", 408 mach->machno, mach->lastintr); 409 } 410 print("\n"); 411 } 412 m->spuriousintr++; 413 if(user) 414 kexit(ureg); 415 return; 416 } 417 else{ 418 if(vno == VectorNMI){ 419 nmienable(); 420 if(m->machno != 0){ 421 print("cpu%d: PC %8.8luX\n", 422 m->machno, ureg->pc); 423 for(;;); 424 } 425 } 426 dumpregs(ureg); 427 if(!user){ 428 ureg->sp = (ulong)&ureg->sp; 429 _dumpstack(ureg); 430 } 431 if(vno < nelem(excname)) 432 panic("%s", excname[vno]); 433 panic("unknown trap/intr: %d\n", vno); 434 } 435 splhi(); 436 437 /* delaysched set because we held a lock or because our quantum ended */ 438 if(up && up->delaysched && clockintr){ 439 sched(); 440 splhi(); 441 } 442 443 if(user){ 444 if(up->procctl || up->nnote) 445 notify(ureg); 446 kexit(ureg); 447 } 448 } 449 450 /* 451 * dump registers 452 */ 453 void 454 dumpregs2(Ureg* ureg) 455 { 456 if(up) 457 print("cpu%d: registers for %s %lud\n", 458 m->machno, up->text, up->pid); 459 else 460 print("cpu%d: registers for kernel\n", m->machno); 461 print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", 462 ureg->flags, ureg->trap, ureg->ecode, ureg->pc); 463 print(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); 464 print(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", 465 ureg->ax, ureg->bx, ureg->cx, ureg->dx); 466 print(" SI %8.8luX DI %8.8luX BP %8.8luX\n", 467 ureg->si, ureg->di, ureg->bp); 468 print(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n", 469 ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF, 470 ureg->fs & 0xFFFF, ureg->gs & 0xFFFF); 471 } 472 473 void 474 dumpregs(Ureg* ureg) 475 { 476 vlong mca, mct; 477 478 dumpregs2(ureg); 479 480 /* 481 * Processor control registers. 482 * If machine check exception, time stamp counter, page size extensions 483 * or enhanced virtual 8086 mode extensions are supported, there is a 484 * CR4. If there is a CR4 and machine check extensions, read the machine 485 * check address and machine check type registers if RDMSR supported. 486 */ 487 print(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux", 488 getcr0(), getcr2(), getcr3()); 489 if(m->cpuiddx & 0x9A){ 490 print(" CR4 %8.8lux", getcr4()); 491 if((m->cpuiddx & 0xA0) == 0xA0){ 492 rdmsr(0x00, &mca); 493 rdmsr(0x01, &mct); 494 print("\n MCA %8.8llux MCT %8.8llux", mca, mct); 495 } 496 } 497 print("\n ur %lux up %lux\n", ureg, up); 498 } 499 500 501 /* 502 * Fill in enough of Ureg to get a stack trace, and call a function. 503 * Used by debugging interface rdb. 504 */ 505 void 506 callwithureg(void (*fn)(Ureg*)) 507 { 508 Ureg ureg; 509 ureg.pc = getcallerpc(&fn); 510 ureg.sp = (ulong)&fn; 511 fn(&ureg); 512 } 513 514 static void 515 _dumpstack(Ureg *ureg) 516 { 517 ulong l, v, i, estack; 518 extern ulong etext; 519 int x; 520 521 if(getconf("*nodumpstack")){ 522 iprint("dumpstack disabled\n"); 523 return; 524 } 525 iprint("dumpstack\n"); 526 527 x = 0; 528 x += print("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp); 529 i = 0; 530 if(up 531 && (ulong)&l >= (ulong)up->kstack 532 && (ulong)&l <= (ulong)up->kstack+KSTACK) 533 estack = (ulong)up->kstack+KSTACK; 534 else if((ulong)&l >= (ulong)m->stack 535 && (ulong)&l <= (ulong)m+BY2PG) 536 estack = (ulong)m+MACHSIZE; 537 else 538 return; 539 x += print("estackx %.8lux\n", estack); 540 541 for(l=(ulong)&l; l<estack; l+=4){ 542 v = *(ulong*)l; 543 if((KTZERO < v && v < (ulong)&etext) || estack-l<32){ 544 /* 545 * we could Pick off general CALL (((uchar*)v)[-5] == 0xE8) 546 * and CALL indirect through AX (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0), 547 * but this is too clever and misses faulting address. 548 */ 549 x += print("%.8lux=%.8lux ", l, v); 550 i++; 551 } 552 if(i == 4){ 553 i = 0; 554 x += print("\n"); 555 } 556 } 557 if(i) 558 print("\n"); 559 print("EOF\n"); 560 } 561 562 void 563 dumpstack(void) 564 { 565 callwithureg(_dumpstack); 566 } 567 568 static void 569 debugbpt(Ureg* ureg, void*) 570 { 571 char buf[ERRMAX]; 572 573 if(up == 0) 574 panic("kernel bpt"); 575 /* restore pc to instruction that caused the trap */ 576 ureg->pc--; 577 sprint(buf, "sys: breakpoint"); 578 postnote(up, 1, buf, NDebug); 579 } 580 581 static void 582 doublefault(Ureg*, void*) 583 { 584 panic("double fault"); 585 } 586 587 static void 588 unexpected(Ureg* ureg, void*) 589 { 590 print("unexpected trap %lud; ignoring\n", ureg->trap); 591 } 592 593 extern void checkpages(void); 594 extern void checkfault(ulong, ulong); 595 static void 596 fault386(Ureg* ureg, void*) 597 { 598 ulong addr; 599 int read, user, n, insyscall; 600 char buf[ERRMAX]; 601 602 addr = getcr2(); 603 read = !(ureg->ecode & 2); 604 605 user = (ureg->cs & 0xFFFF) == UESEL; 606 if(!user){ 607 if(vmapsync(addr)) 608 return; 609 if(addr >= USTKTOP) 610 panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 611 if(up == nil) 612 panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 613 } 614 if(up == nil) 615 panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 616 617 insyscall = up->insyscall; 618 up->insyscall = 1; 619 n = fault(addr, read); 620 if(n < 0){ 621 if(!user){ 622 dumpregs(ureg); 623 panic("fault: 0x%lux\n", addr); 624 } 625 checkpages(); 626 checkfault(addr, ureg->pc); 627 sprint(buf, "sys: trap: fault %s addr=0x%lux", 628 read ? "read" : "write", addr); 629 postnote(up, 1, buf, NDebug); 630 } 631 up->insyscall = insyscall; 632 } 633 634 /* 635 * system calls 636 */ 637 #include "../port/systab.h" 638 639 /* 640 * Syscall is called directly from assembler without going through trap(). 641 */ 642 void 643 syscall(Ureg* ureg) 644 { 645 char *e; 646 ulong sp; 647 long ret; 648 int i, s; 649 ulong scallnr; 650 651 if((ureg->cs & 0xFFFF) != UESEL) 652 panic("syscall: cs 0x%4.4luX\n", ureg->cs); 653 654 cycles(&up->kentry); 655 656 m->syscall++; 657 up->insyscall = 1; 658 up->pc = ureg->pc; 659 up->dbgreg = ureg; 660 661 if(up->procctl == Proc_tracesyscall){ 662 up->procctl = Proc_stopme; 663 procctl(up); 664 } 665 666 scallnr = ureg->ax; 667 up->scallnr = scallnr; 668 if(scallnr == RFORK && up->fpstate == FPactive){ 669 fpsave(&up->fpsave); 670 up->fpstate = FPinactive; 671 } 672 spllo(); 673 674 sp = ureg->usp; 675 up->nerrlab = 0; 676 ret = -1; 677 if(!waserror()){ 678 if(scallnr >= nsyscall || systab[scallnr] == 0){ 679 pprint("bad sys call number %d pc %lux\n", 680 scallnr, ureg->pc); 681 postnote(up, 1, "sys: bad sys call", NDebug); 682 error(Ebadarg); 683 } 684 685 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) 686 validaddr(sp, sizeof(Sargs)+BY2WD, 0); 687 688 up->s = *((Sargs*)(sp+BY2WD)); 689 up->psstate = sysctab[scallnr]; 690 691 ret = systab[scallnr](up->s.args); 692 poperror(); 693 }else{ 694 /* failure: save the error buffer for errstr */ 695 e = up->syserrstr; 696 up->syserrstr = up->errstr; 697 up->errstr = e; 698 if(0 && up->pid == 1) 699 print("syscall %lud error %s\n", scallnr, up->syserrstr); 700 } 701 if(up->nerrlab){ 702 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab); 703 for(i = 0; i < NERR; i++) 704 print("sp=%lux pc=%lux\n", 705 up->errlab[i].sp, up->errlab[i].pc); 706 panic("error stack"); 707 } 708 709 /* 710 * Put return value in frame. On the x86 the syscall is 711 * just another trap and the return value from syscall is 712 * ignored. On other machines the return value is put into 713 * the results register by caller of syscall. 714 */ 715 ureg->ax = ret; 716 717 if(up->procctl == Proc_tracesyscall){ 718 up->procctl = Proc_stopme; 719 s = splhi(); 720 procctl(up); 721 splx(s); 722 } 723 724 up->insyscall = 0; 725 up->psstate = 0; 726 727 if(scallnr == NOTED) 728 noted(ureg, *(ulong*)(sp+BY2WD)); 729 730 if(scallnr!=RFORK && (up->procctl || up->nnote)){ 731 splhi(); 732 notify(ureg); 733 } 734 /* if we delayed sched because we held a lock, sched now */ 735 if(up->delaysched) 736 sched(); 737 kexit(ureg); 738 } 739 740 /* 741 * Call user, if necessary, with note. 742 * Pass user the Ureg struct and the note on his stack. 743 */ 744 int 745 notify(Ureg* ureg) 746 { 747 int l; 748 ulong s, sp; 749 Note *n; 750 751 if(up->procctl) 752 procctl(up); 753 if(up->nnote == 0) 754 return 0; 755 756 if(up->fpstate == FPactive){ 757 fpsave(&up->fpsave); 758 up->fpstate = FPinactive; 759 } 760 up->fpstate |= FPillegal; 761 762 s = spllo(); 763 qlock(&up->debug); 764 up->notepending = 0; 765 n = &up->note[0]; 766 if(strncmp(n->msg, "sys:", 4) == 0){ 767 l = strlen(n->msg); 768 if(l > ERRMAX-15) /* " pc=0x12345678\0" */ 769 l = ERRMAX-15; 770 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); 771 } 772 773 if(n->flag!=NUser && (up->notified || up->notify==0)){ 774 if(n->flag == NDebug) 775 pprint("suicide: %s\n", n->msg); 776 qunlock(&up->debug); 777 pexit(n->msg, n->flag!=NDebug); 778 } 779 780 if(up->notified){ 781 qunlock(&up->debug); 782 splhi(); 783 return 0; 784 } 785 786 if(!up->notify){ 787 qunlock(&up->debug); 788 pexit(n->msg, n->flag!=NDebug); 789 } 790 sp = ureg->usp; 791 sp -= sizeof(Ureg); 792 793 if(!okaddr((ulong)up->notify, 1, 0) 794 || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){ 795 pprint("suicide: bad address in notify\n"); 796 qunlock(&up->debug); 797 pexit("Suicide", 0); 798 } 799 800 up->ureg = (void*)sp; 801 memmove((Ureg*)sp, ureg, sizeof(Ureg)); 802 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ 803 up->ureg = (void*)sp; 804 sp -= BY2WD+ERRMAX; 805 memmove((char*)sp, up->note[0].msg, ERRMAX); 806 sp -= 3*BY2WD; 807 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ 808 *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */ 809 *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ 810 ureg->usp = sp; 811 ureg->pc = (ulong)up->notify; 812 up->notified = 1; 813 up->nnote--; 814 memmove(&up->lastnote, &up->note[0], sizeof(Note)); 815 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 816 817 qunlock(&up->debug); 818 splx(s); 819 return 1; 820 } 821 822 /* 823 * Return user to state before notify() 824 */ 825 void 826 noted(Ureg* ureg, ulong arg0) 827 { 828 Ureg *nureg; 829 ulong oureg, sp; 830 831 qlock(&up->debug); 832 if(arg0!=NRSTR && !up->notified) { 833 qunlock(&up->debug); 834 pprint("call to noted() when not notified\n"); 835 pexit("Suicide", 0); 836 } 837 up->notified = 0; 838 839 nureg = up->ureg; /* pointer to user returned Ureg struct */ 840 841 up->fpstate &= ~FPillegal; 842 843 /* sanity clause */ 844 oureg = (ulong)nureg; 845 if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ 846 pprint("bad ureg in noted or call to noted when not notified\n"); 847 qunlock(&up->debug); 848 pexit("Suicide", 0); 849 } 850 851 /* 852 * Check the segment selectors are all valid, otherwise 853 * a fault will be taken on attempting to return to the 854 * user process. 855 * Take care with the comparisons as different processor 856 * generations push segment descriptors in different ways. 857 */ 858 if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL 859 || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL 860 || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){ 861 pprint("bad segment selector in noted\n"); 862 qunlock(&up->debug); 863 pexit("Suicide", 0); 864 } 865 866 /* don't let user change system flags */ 867 nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5); 868 869 memmove(ureg, nureg, sizeof(Ureg)); 870 871 switch(arg0){ 872 case NCONT: 873 case NRSTR: 874 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ 875 qunlock(&up->debug); 876 pprint("suicide: trap in noted\n"); 877 pexit("Suicide", 0); 878 } 879 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); 880 qunlock(&up->debug); 881 break; 882 883 case NSAVE: 884 if(!okaddr(nureg->pc, BY2WD, 0) 885 || !okaddr(nureg->usp, BY2WD, 0)){ 886 qunlock(&up->debug); 887 pprint("suicide: trap in noted\n"); 888 pexit("Suicide", 0); 889 } 890 qunlock(&up->debug); 891 sp = oureg-4*BY2WD-ERRMAX; 892 splhi(); 893 ureg->sp = sp; 894 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ 895 ((ulong*)sp)[0] = 0; /* arg 0 is pc */ 896 break; 897 898 default: 899 pprint("unknown noted arg 0x%lux\n", arg0); 900 up->lastnote.flag = NDebug; 901 /* fall through */ 902 903 case NDFLT: 904 if(up->lastnote.flag == NDebug){ 905 qunlock(&up->debug); 906 pprint("suicide: %s\n", up->lastnote.msg); 907 } else 908 qunlock(&up->debug); 909 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); 910 } 911 } 912 913 long 914 execregs(ulong entry, ulong ssize, ulong nargs) 915 { 916 ulong *sp; 917 Ureg *ureg; 918 919 up->fpstate = FPinit; 920 fpoff(); 921 922 sp = (ulong*)(USTKTOP - ssize); 923 *--sp = nargs; 924 925 ureg = up->dbgreg; 926 ureg->usp = (ulong)sp; 927 ureg->pc = entry; 928 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */ 929 } 930 931 /* 932 * return the userpc the last exception happened at 933 */ 934 ulong 935 userpc(void) 936 { 937 Ureg *ureg; 938 939 ureg = (Ureg*)up->dbgreg; 940 return ureg->pc; 941 } 942 943 /* This routine must save the values of registers the user is not permitted 944 * to write from devproc and then restore the saved values before returning. 945 */ 946 void 947 setregisters(Ureg* ureg, char* pureg, char* uva, int n) 948 { 949 ulong flags; 950 ulong cs; 951 ulong ss; 952 953 flags = ureg->flags; 954 cs = ureg->cs; 955 ss = ureg->ss; 956 memmove(pureg, uva, n); 957 ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00); 958 ureg->cs = cs; 959 ureg->ss = ss; 960 } 961 962 static void 963 linkproc(void) 964 { 965 spllo(); 966 up->kpfun(up->kparg); 967 pexit("kproc dying", 0); 968 } 969 970 void 971 kprocchild(Proc* p, void (*func)(void*), void* arg) 972 { 973 /* 974 * gotolabel() needs a word on the stack in 975 * which to place the return PC used to jump 976 * to linkproc(). 977 */ 978 p->sched.pc = (ulong)linkproc; 979 p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD; 980 981 p->kpfun = func; 982 p->kparg = arg; 983 } 984 985 void 986 forkchild(Proc *p, Ureg *ureg) 987 { 988 Ureg *cureg; 989 990 /* 991 * Add 2*BY2WD to the stack to account for 992 * - the return PC 993 * - trap's argument (ur) 994 */ 995 p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); 996 p->sched.pc = (ulong)forkret; 997 998 cureg = (Ureg*)(p->sched.sp+2*BY2WD); 999 memmove(cureg, ureg, sizeof(Ureg)); 1000 /* return value of syscall in child */ 1001 cureg->ax = 0; 1002 1003 /* Things from bottom of syscall which were never executed */ 1004 p->psstate = 0; 1005 p->insyscall = 0; 1006 } 1007 1008 /* Give enough context in the ureg to produce a kernel stack for 1009 * a sleeping process 1010 */ 1011 void 1012 setkernur(Ureg* ureg, Proc* p) 1013 { 1014 ureg->pc = p->sched.pc; 1015 ureg->sp = p->sched.sp+4; 1016 } 1017 1018 ulong 1019 dbgpc(Proc *p) 1020 { 1021 Ureg *ureg; 1022 1023 ureg = p->dbgreg; 1024 if(ureg == 0) 1025 return 0; 1026 1027 return ureg->pc; 1028 } 1029