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 %#p %#p %#p %#p", 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", 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 /* 420 * Don't re-enable, it confuses the crash dumps. 421 nmienable(); 422 */ 423 iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc); 424 while(m->machno != 0) 425 ; 426 } 427 dumpregs(ureg); 428 if(!user){ 429 ureg->sp = (ulong)&ureg->sp; 430 _dumpstack(ureg); 431 } 432 if(vno < nelem(excname)) 433 panic("%s", excname[vno]); 434 panic("unknown trap/intr: %d", vno); 435 } 436 splhi(); 437 438 /* delaysched set because we held a lock or because our quantum ended */ 439 if(up && up->delaysched && clockintr){ 440 sched(); 441 splhi(); 442 } 443 444 if(user){ 445 if(up->procctl || up->nnote) 446 notify(ureg); 447 kexit(ureg); 448 } 449 } 450 451 /* 452 * dump registers 453 */ 454 void 455 dumpregs2(Ureg* ureg) 456 { 457 if(up) 458 iprint("cpu%d: registers for %s %lud\n", 459 m->machno, up->text, up->pid); 460 else 461 iprint("cpu%d: registers for kernel\n", m->machno); 462 iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", 463 ureg->flags, ureg->trap, ureg->ecode, ureg->pc); 464 iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); 465 iprint(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", 466 ureg->ax, ureg->bx, ureg->cx, ureg->dx); 467 iprint(" SI %8.8luX DI %8.8luX BP %8.8luX\n", 468 ureg->si, ureg->di, ureg->bp); 469 iprint(" CS %4.4luX DS %4.4luX ES %4.4luX FS %4.4luX GS %4.4luX\n", 470 ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF, 471 ureg->fs & 0xFFFF, ureg->gs & 0xFFFF); 472 } 473 474 void 475 dumpregs(Ureg* ureg) 476 { 477 vlong mca, mct; 478 479 dumpregs2(ureg); 480 481 /* 482 * Processor control registers. 483 * If machine check exception, time stamp counter, page size extensions 484 * or enhanced virtual 8086 mode extensions are supported, there is a 485 * CR4. If there is a CR4 and machine check extensions, read the machine 486 * check address and machine check type registers if RDMSR supported. 487 */ 488 iprint(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux", 489 getcr0(), getcr2(), getcr3()); 490 if(m->cpuiddx & 0x9A){ 491 iprint(" CR4 %8.8lux", getcr4()); 492 if((m->cpuiddx & 0xA0) == 0xA0){ 493 rdmsr(0x00, &mca); 494 rdmsr(0x01, &mct); 495 iprint("\n MCA %8.8llux MCT %8.8llux", mca, mct); 496 } 497 } 498 iprint("\n ur %#p up %#p\n", ureg, up); 499 } 500 501 502 /* 503 * Fill in enough of Ureg to get a stack trace, and call a function. 504 * Used by debugging interface rdb. 505 */ 506 void 507 callwithureg(void (*fn)(Ureg*)) 508 { 509 Ureg ureg; 510 ureg.pc = getcallerpc(&fn); 511 ureg.sp = (ulong)&fn; 512 fn(&ureg); 513 } 514 515 static void 516 _dumpstack(Ureg *ureg) 517 { 518 uintptr l, v, i, estack; 519 extern ulong etext; 520 int x; 521 char *s; 522 523 if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){ 524 iprint("dumpstack disabled\n"); 525 return; 526 } 527 iprint("dumpstack\n"); 528 529 x = 0; 530 x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp); 531 i = 0; 532 if(up 533 && (uintptr)&l >= (uintptr)up->kstack 534 && (uintptr)&l <= (uintptr)up->kstack+KSTACK) 535 estack = (uintptr)up->kstack+KSTACK; 536 else if((uintptr)&l >= (uintptr)m->stack 537 && (uintptr)&l <= (uintptr)m+MACHSIZE) 538 estack = (uintptr)m+MACHSIZE; 539 else 540 return; 541 x += iprint("estackx %p\n", estack); 542 543 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){ 544 v = *(uintptr*)l; 545 if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){ 546 /* 547 * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8) 548 * and CALL indirect through AX 549 * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0), 550 * but this is too clever and misses faulting address. 551 */ 552 x += iprint("%.8p=%.8p ", l, v); 553 i++; 554 } 555 if(i == 4){ 556 i = 0; 557 x += iprint("\n"); 558 } 559 } 560 if(i) 561 iprint("\n"); 562 iprint("EOF\n"); 563 564 if(ureg->trap != VectorNMI) 565 return; 566 567 i = 0; 568 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){ 569 iprint("%.8p ", *(uintptr*)l); 570 if(++i == 8){ 571 i = 0; 572 iprint("\n"); 573 } 574 } 575 if(i) 576 iprint("\n"); 577 } 578 579 void 580 dumpstack(void) 581 { 582 callwithureg(_dumpstack); 583 } 584 585 static void 586 debugbpt(Ureg* ureg, void*) 587 { 588 char buf[ERRMAX]; 589 590 if(up == 0) 591 panic("kernel bpt"); 592 /* restore pc to instruction that caused the trap */ 593 ureg->pc--; 594 sprint(buf, "sys: breakpoint"); 595 postnote(up, 1, buf, NDebug); 596 } 597 598 static void 599 doublefault(Ureg*, void*) 600 { 601 panic("double fault"); 602 } 603 604 static void 605 unexpected(Ureg* ureg, void*) 606 { 607 print("unexpected trap %lud; ignoring\n", ureg->trap); 608 } 609 610 extern void checkpages(void); 611 extern void checkfault(ulong, ulong); 612 static void 613 fault386(Ureg* ureg, void*) 614 { 615 ulong addr; 616 int read, user, n, insyscall; 617 char buf[ERRMAX]; 618 619 addr = getcr2(); 620 read = !(ureg->ecode & 2); 621 622 user = (ureg->cs & 0xFFFF) == UESEL; 623 if(!user){ 624 if(vmapsync(addr)) 625 return; 626 if(addr >= USTKTOP) 627 panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 628 if(up == nil) 629 panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 630 } 631 if(up == nil) 632 panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr); 633 634 insyscall = up->insyscall; 635 up->insyscall = 1; 636 n = fault(addr, read); 637 if(n < 0){ 638 if(!user){ 639 dumpregs(ureg); 640 panic("fault: 0x%lux", addr); 641 } 642 checkpages(); 643 checkfault(addr, ureg->pc); 644 sprint(buf, "sys: trap: fault %s addr=0x%lux", 645 read ? "read" : "write", addr); 646 postnote(up, 1, buf, NDebug); 647 } 648 up->insyscall = insyscall; 649 } 650 651 /* 652 * system calls 653 */ 654 #include "../port/systab.h" 655 656 /* 657 * Syscall is called directly from assembler without going through trap(). 658 */ 659 void 660 syscall(Ureg* ureg) 661 { 662 char *e; 663 ulong sp; 664 long ret; 665 int i, s; 666 ulong scallnr; 667 668 if((ureg->cs & 0xFFFF) != UESEL) 669 panic("syscall: cs 0x%4.4luX", ureg->cs); 670 671 cycles(&up->kentry); 672 673 m->syscall++; 674 up->insyscall = 1; 675 up->pc = ureg->pc; 676 up->dbgreg = ureg; 677 678 if(up->procctl == Proc_tracesyscall){ 679 up->procctl = Proc_stopme; 680 procctl(up); 681 } 682 683 scallnr = ureg->ax; 684 up->scallnr = scallnr; 685 if(scallnr == RFORK && up->fpstate == FPactive){ 686 fpsave(&up->fpsave); 687 up->fpstate = FPinactive; 688 } 689 spllo(); 690 691 sp = ureg->usp; 692 up->nerrlab = 0; 693 ret = -1; 694 if(!waserror()){ 695 if(scallnr >= nsyscall || systab[scallnr] == 0){ 696 pprint("bad sys call number %lud pc %lux\n", 697 scallnr, ureg->pc); 698 postnote(up, 1, "sys: bad sys call", NDebug); 699 error(Ebadarg); 700 } 701 702 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) 703 validaddr(sp, sizeof(Sargs)+BY2WD, 0); 704 705 up->s = *((Sargs*)(sp+BY2WD)); 706 up->psstate = sysctab[scallnr]; 707 708 ret = systab[scallnr](up->s.args); 709 poperror(); 710 }else{ 711 /* failure: save the error buffer for errstr */ 712 e = up->syserrstr; 713 up->syserrstr = up->errstr; 714 up->errstr = e; 715 if(0 && up->pid == 1) 716 print("syscall %lud error %s\n", scallnr, up->syserrstr); 717 } 718 if(up->nerrlab){ 719 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab); 720 for(i = 0; i < NERR; i++) 721 print("sp=%lux pc=%lux\n", 722 up->errlab[i].sp, up->errlab[i].pc); 723 panic("error stack"); 724 } 725 726 /* 727 * Put return value in frame. On the x86 the syscall is 728 * just another trap and the return value from syscall is 729 * ignored. On other machines the return value is put into 730 * the results register by caller of syscall. 731 */ 732 ureg->ax = ret; 733 734 if(up->procctl == Proc_tracesyscall){ 735 up->procctl = Proc_stopme; 736 s = splhi(); 737 procctl(up); 738 splx(s); 739 } 740 741 up->insyscall = 0; 742 up->psstate = 0; 743 744 if(scallnr == NOTED) 745 noted(ureg, *(ulong*)(sp+BY2WD)); 746 747 if(scallnr!=RFORK && (up->procctl || up->nnote)){ 748 splhi(); 749 notify(ureg); 750 } 751 /* if we delayed sched because we held a lock, sched now */ 752 if(up->delaysched) 753 sched(); 754 kexit(ureg); 755 } 756 757 /* 758 * Call user, if necessary, with note. 759 * Pass user the Ureg struct and the note on his stack. 760 */ 761 int 762 notify(Ureg* ureg) 763 { 764 int l; 765 ulong s, sp; 766 Note *n; 767 768 if(up->procctl) 769 procctl(up); 770 if(up->nnote == 0) 771 return 0; 772 773 if(up->fpstate == FPactive){ 774 fpsave(&up->fpsave); 775 up->fpstate = FPinactive; 776 } 777 up->fpstate |= FPillegal; 778 779 s = spllo(); 780 qlock(&up->debug); 781 up->notepending = 0; 782 n = &up->note[0]; 783 if(strncmp(n->msg, "sys:", 4) == 0){ 784 l = strlen(n->msg); 785 if(l > ERRMAX-15) /* " pc=0x12345678\0" */ 786 l = ERRMAX-15; 787 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); 788 } 789 790 if(n->flag!=NUser && (up->notified || up->notify==0)){ 791 if(n->flag == NDebug) 792 pprint("suicide: %s\n", n->msg); 793 qunlock(&up->debug); 794 pexit(n->msg, n->flag!=NDebug); 795 } 796 797 if(up->notified){ 798 qunlock(&up->debug); 799 splhi(); 800 return 0; 801 } 802 803 if(!up->notify){ 804 qunlock(&up->debug); 805 pexit(n->msg, n->flag!=NDebug); 806 } 807 sp = ureg->usp; 808 sp -= 256; /* debugging: preserve context causing problem */ 809 sp -= sizeof(Ureg); 810 if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n", 811 up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg); 812 813 if(!okaddr((ulong)up->notify, 1, 0) 814 || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){ 815 pprint("suicide: bad address in notify\n"); 816 qunlock(&up->debug); 817 pexit("Suicide", 0); 818 } 819 820 memmove((Ureg*)sp, ureg, sizeof(Ureg)); 821 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ 822 up->ureg = (void*)sp; 823 sp -= BY2WD+ERRMAX; 824 memmove((char*)sp, up->note[0].msg, ERRMAX); 825 sp -= 3*BY2WD; 826 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ 827 *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */ 828 *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ 829 ureg->usp = sp; 830 ureg->pc = (ulong)up->notify; 831 up->notified = 1; 832 up->nnote--; 833 memmove(&up->lastnote, &up->note[0], sizeof(Note)); 834 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 835 836 qunlock(&up->debug); 837 splx(s); 838 return 1; 839 } 840 841 /* 842 * Return user to state before notify() 843 */ 844 void 845 noted(Ureg* ureg, ulong arg0) 846 { 847 Ureg *nureg; 848 ulong oureg, sp; 849 850 qlock(&up->debug); 851 if(arg0!=NRSTR && !up->notified) { 852 qunlock(&up->debug); 853 pprint("call to noted() when not notified\n"); 854 pexit("Suicide", 0); 855 } 856 up->notified = 0; 857 858 nureg = up->ureg; /* pointer to user returned Ureg struct */ 859 860 up->fpstate &= ~FPillegal; 861 862 /* sanity clause */ 863 oureg = (ulong)nureg; 864 if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ 865 pprint("bad ureg in noted or call to noted when not notified\n"); 866 qunlock(&up->debug); 867 pexit("Suicide", 0); 868 } 869 870 /* 871 * Check the segment selectors are all valid, otherwise 872 * a fault will be taken on attempting to return to the 873 * user process. 874 * Take care with the comparisons as different processor 875 * generations push segment descriptors in different ways. 876 */ 877 if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL 878 || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL 879 || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){ 880 pprint("bad segment selector in noted\n"); 881 qunlock(&up->debug); 882 pexit("Suicide", 0); 883 } 884 885 /* don't let user change system flags */ 886 nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5); 887 888 memmove(ureg, nureg, sizeof(Ureg)); 889 890 switch(arg0){ 891 case NCONT: 892 case NRSTR: 893 if(0) print("%s %lud: noted %.8lux %.8lux\n", 894 up->text, up->pid, nureg->pc, nureg->usp); 895 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ 896 qunlock(&up->debug); 897 pprint("suicide: trap in noted\n"); 898 pexit("Suicide", 0); 899 } 900 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); 901 qunlock(&up->debug); 902 break; 903 904 case NSAVE: 905 if(!okaddr(nureg->pc, BY2WD, 0) 906 || !okaddr(nureg->usp, BY2WD, 0)){ 907 qunlock(&up->debug); 908 pprint("suicide: trap in noted\n"); 909 pexit("Suicide", 0); 910 } 911 qunlock(&up->debug); 912 sp = oureg-4*BY2WD-ERRMAX; 913 splhi(); 914 ureg->sp = sp; 915 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ 916 ((ulong*)sp)[0] = 0; /* arg 0 is pc */ 917 break; 918 919 default: 920 pprint("unknown noted arg 0x%lux\n", arg0); 921 up->lastnote.flag = NDebug; 922 /* fall through */ 923 924 case NDFLT: 925 if(up->lastnote.flag == NDebug){ 926 qunlock(&up->debug); 927 pprint("suicide: %s\n", up->lastnote.msg); 928 } else 929 qunlock(&up->debug); 930 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); 931 } 932 } 933 934 long 935 execregs(ulong entry, ulong ssize, ulong nargs) 936 { 937 ulong *sp; 938 Ureg *ureg; 939 940 up->fpstate = FPinit; 941 fpoff(); 942 943 sp = (ulong*)(USTKTOP - ssize); 944 *--sp = nargs; 945 946 ureg = up->dbgreg; 947 ureg->usp = (ulong)sp; 948 ureg->pc = entry; 949 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */ 950 } 951 952 /* 953 * return the userpc the last exception happened at 954 */ 955 ulong 956 userpc(void) 957 { 958 Ureg *ureg; 959 960 ureg = (Ureg*)up->dbgreg; 961 return ureg->pc; 962 } 963 964 /* This routine must save the values of registers the user is not permitted 965 * to write from devproc and then restore the saved values before returning. 966 */ 967 void 968 setregisters(Ureg* ureg, char* pureg, char* uva, int n) 969 { 970 ulong cs, ds, es, flags, fs, gs, ss; 971 972 ss = ureg->ss; 973 flags = ureg->flags; 974 cs = ureg->cs; 975 ds = ureg->ds; 976 es = ureg->es; 977 fs = ureg->fs; 978 gs = ureg->gs; 979 memmove(pureg, uva, n); 980 ureg->gs = gs; 981 ureg->fs = fs; 982 ureg->es = es; 983 ureg->ds = ds; 984 ureg->cs = cs; 985 ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00); 986 ureg->ss = ss; 987 } 988 989 static void 990 linkproc(void) 991 { 992 spllo(); 993 up->kpfun(up->kparg); 994 pexit("kproc dying", 0); 995 } 996 997 void 998 kprocchild(Proc* p, void (*func)(void*), void* arg) 999 { 1000 /* 1001 * gotolabel() needs a word on the stack in 1002 * which to place the return PC used to jump 1003 * to linkproc(). 1004 */ 1005 p->sched.pc = (ulong)linkproc; 1006 p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD; 1007 1008 p->kpfun = func; 1009 p->kparg = arg; 1010 } 1011 1012 void 1013 forkchild(Proc *p, Ureg *ureg) 1014 { 1015 Ureg *cureg; 1016 1017 /* 1018 * Add 2*BY2WD to the stack to account for 1019 * - the return PC 1020 * - trap's argument (ur) 1021 */ 1022 p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); 1023 p->sched.pc = (ulong)forkret; 1024 1025 cureg = (Ureg*)(p->sched.sp+2*BY2WD); 1026 memmove(cureg, ureg, sizeof(Ureg)); 1027 /* return value of syscall in child */ 1028 cureg->ax = 0; 1029 1030 /* Things from bottom of syscall which were never executed */ 1031 p->psstate = 0; 1032 p->insyscall = 0; 1033 } 1034 1035 /* Give enough context in the ureg to produce a kernel stack for 1036 * a sleeping process 1037 */ 1038 void 1039 setkernur(Ureg* ureg, Proc* p) 1040 { 1041 ureg->pc = p->sched.pc; 1042 ureg->sp = p->sched.sp+4; 1043 } 1044 1045 ulong 1046 dbgpc(Proc *p) 1047 { 1048 Ureg *ureg; 1049 1050 ureg = p->dbgreg; 1051 if(ureg == 0) 1052 return 0; 1053 1054 return ureg->pc; 1055 } 1056