|
|
1.1 ! root 1: /* ! 2: * File: ndp.c ! 3: * ! 4: * Purpose: all ndp-related functions, except for assembler routines ! 5: * ! 6: * $Log: ndp.c,v $ ! 7: * Revision 1.7 93/06/14 13:43:02 bin ! 8: * Hal: kernel 78 update ! 9: * ! 10: * Revision 1.2 93/04/14 10:27:57 root ! 11: * r75 ! 12: * ! 13: * Revision 1.1 92/11/09 17:09:23 root ! 14: * Just before adding vio segs. ! 15: * ! 16: */ ! 17: ! 18: /* ! 19: * ---------------------------------------------------------------------- ! 20: * Includes. ! 21: */ ! 22: #include <sys/coherent.h> ! 23: #include <errno.h> ! 24: #include <sys/seg.h> ! 25: ! 26: /* ! 27: * ---------------------------------------------------------------------- ! 28: * Definitions. ! 29: * Constants. ! 30: * Macros with argument lists. ! 31: * Typedefs. ! 32: * Enums. ! 33: */ ! 34: /* bit positions in u.u_ndpFlags */ ! 35: #define NF_NDP_USER 1 /* this process has used the ndp */ ! 36: #define NF_NDP_SAVED 2 /* ndp status is saved in u area */ ! 37: #define NF_EM_TRAPPED 4 /* no ndp, em trap has occurred */ ! 38: ! 39: /* supported coprocessor types - will autosense if initially unpatched */ ! 40: #define NDP_TYPE_UNPATCHED 0 ! 41: #define NDP_TYPE_NONE 1 ! 42: #define NDP_TYPE_287 2 ! 43: #define NDP_TYPE_387 3 ! 44: #define NDP_TYPE_486 4 ! 45: ! 46: #define NDP_IRQ 13 /* 387 uses Irq for unmasked exceptions */ ! 47: #define NDP_PORT 0xF0 /* 387 uses this port to clear exception */ ! 48: /* ! 49: * ---------------------------------------------------------------------- ! 50: * Functions. ! 51: * Import Functions. ! 52: * Export Functions. ! 53: * Local Functions. ! 54: */ ! 55: void emFinit(); ! 56: void emtrap(); ! 57: void fptrap(); ! 58: void ndpConRest(); ! 59: void ndpDetach(); ! 60: void ndpEmTraps(); ! 61: void ndpEndProc(); ! 62: void ndpIrq(); ! 63: void ndpMine(); ! 64: void ndpNewOwner(); ! 65: void ndpNewProc(); ! 66: char * ndpTypeName(); ! 67: int rdEmTrapped(); ! 68: int rdNdpSaved(); ! 69: int rdNdpSavedU(); ! 70: int rdNdpUser(); ! 71: void senseNdp(); ! 72: void wrEmTrapped(); ! 73: void wrNdpSaved(); ! 74: void wrNdpSavedU(); ! 75: void wrNdpUser(); ! 76: ! 77: /* ! 78: * ---------------------------------------------------------------------- ! 79: * Global Data. ! 80: * Import Variables. ! 81: * Export Variables. ! 82: * Local Variables. ! 83: */ ! 84: ! 85: /* ! 86: * ndp control word is 16 bits: ! 87: * 0000 RC:2 PC:2 01 PM:1 UM:1 OM:1 ZM:1 DM:1 IM:1 ! 88: * RC - rounding control ! 89: * PC - precision control ! 90: * PM - precision mask ! 91: * UM - underflow mask ! 92: * OM - overflow mask ! 93: * ZM - zero divide mask ! 94: * DM - denormal operand mask ! 95: * IM - invalid operation mask ! 96: * for masks, 1 masks the exception ! 97: * ! 98: * iBCS2 page 3-46 specifies the following: ! 99: * 0000 : 00 10 : 0 1 1 1 : 0 0 1 0 = 0x0272 ! 100: */ ! 101: ! 102: /* Patchable ndp-related variables. */ ! 103: short ndpCW = 0x0272; /* NDP Control Word at start of each NDP process. */ ! 104: short ndpDump = 0; /* Patch to 1 for NDP register dump on FP exceptions. */ ! 105: short ndpType = NDP_TYPE_UNPATCHED; /* Patch overrides NDP type sensing. */ ! 106: int ndpEmSig = SIGFPE; /* signal sent on receiving emulator traps */ ! 107: ! 108: /* Patchable emulator-related function pointers. */ ! 109: int (*ndpEmFn)() = 0; ! 110: int (*ndpKfsave)() = 0; ! 111: int (*ndpKfrstor)() = 0; ! 112: ! 113: static int kerEm = 1; /* RAM copy of CR0 EM bit */ ! 114: static int ndpUseg; /* system global address of U segment */ ! 115: static PROC * ndpOwner; /* process whose stuff is now in ndp */ ! 116: ! 117: /* ! 118: * ---------------------------------------------------------------------- ! 119: * Code. ! 120: */ ! 121: ! 122: /* ! 123: * Called from trap handler the first time a process executes an ndp ! 124: * instruction. ! 125: */ ! 126: void ! 127: ndpNewOwner() ! 128: { ! 129: UPROC * up; ! 130: ! 131: /* disable further emulator traps for this process */ ! 132: wrNdpUser(1); ! 133: ndpEmTraps(0); ! 134: ! 135: /* save old ndp status, if any process was using it */ ! 136: if (ndpOwner) { ! 137: int work = workAlloc(); ! 138: ptable1_v[work] = sysmem.u.pbase[btocrd(ndpUseg)] | SEG_RW; ! 139: mmuupd(); ! 140: up = (UPROC *)(ctob(work) + U_OFFSET); ! 141: ndpSave(&up->u_ndpCon); ! 142: wrNdpSavedU(1, up); ! 143: workFree(work); ! 144: } ! 145: ! 146: /* Make current process NDP owner */ ! 147: ndpMine(); ! 148: ! 149: /* give process a clean ndp */ ! 150: ndpInit(ndpCW); ! 151: } ! 152: ! 153: /* ! 154: * NDP initialization for a new process. ! 155: * Called at exec time. ! 156: * Sets defaults, before it is known whether the process uses NDP or not. ! 157: */ ! 158: void ! 159: ndpNewProc() ! 160: { ! 161: /* default for a process is to trap on NDP instructions */ ! 162: ndpEmTraps(1); ! 163: wrNdpUser(0); ! 164: wrNdpSaved(0); ! 165: wrEmTrapped(0); ! 166: } ! 167: ! 168: /* ! 169: * Restore some ndp info when doing a regular conrest(). ! 170: * Called just after conrest - u area has just been restored. ! 171: */ ! 172: void ! 173: ndpConRest() ! 174: { ! 175: UPROC * up; ! 176: ! 177: /* make CR0 EM bit match what this process needs */ ! 178: ndpEmTraps(rdNdpUser() ? 0 : 1); ! 179: ! 180: /* ! 181: * If current process uses ndp, may need to fix ndp state ! 182: * ! 183: * By the nature of NDP save op's, if the NDP owner's NDP state ! 184: * is saved, then it's not in the NDP. ! 185: * ! 186: * So, we have to be careful (1) not to save twice, and (2) to ! 187: * restore, even if we are NDP owner, if NDP state is saved. ! 188: */ ! 189: if (rdNdpUser()) { ! 190: if (ndpOwner != SELF) { ! 191: if (ndpOwner) { /* save old ndp state */ ! 192: int work = workAlloc(); ! 193: ptable1_v[work] = ! 194: sysmem.u.pbase[btocrd(ndpUseg)] | SEG_RW; ! 195: mmuupd(); ! 196: up = (UPROC *)(ctob(work) + U_OFFSET); ! 197: if (!rdNdpSavedU(up)) { ! 198: ndpSave(&up->u_ndpCon); ! 199: wrNdpSavedU(1, up); ! 200: } ! 201: workFree(work); ! 202: } ! 203: ! 204: /* Make current process NDP owner and reload ndp state */ ! 205: ndpMine(); ! 206: ndpRestore(&u.u_ndpCon); ! 207: wrNdpSaved(0); ! 208: } else if (rdNdpSaved()) { ! 209: ndpRestore(&u.u_ndpCon); ! 210: wrNdpSaved(0); ! 211: } ! 212: } ! 213: } ! 214: ! 215: /* ! 216: * When a process exits, it relinquishes the ndp. ! 217: */ ! 218: void ! 219: ndpEndProc() ! 220: { ! 221: if (SELF == ndpOwner) ! 222: ndpDetach(); ! 223: } ! 224: ! 225: /* ! 226: * ---------------------------------------------------------------------- ! 227: * Trap handlers. ! 228: */ ! 229: ! 230: /* ! 231: * fptrap() ! 232: * ! 233: * Entered when NDP generates a CPU error. ! 234: * err is either SIFP or 0x0D40 ! 235: */ ! 236: #define RDUMP() { \ ! 237: printf("\neax=%x ebx=%x ecx=%x edx=%x\n", eax, ebx, ecx, edx); \ ! 238: printf("esi=%x edi=%x ebp=%x esp=%x\n", esi, edi, ebp, esp); \ ! 239: printf("cs=%x ds=%x es=%x ss=%x fs=%x gs=%x\n", \ ! 240: cs&0xffff, ds&0xffff, es&0xffff, ss&0xffff, fs&0xffff, gs&0xffff); \ ! 241: printf("err #%d eip=%x uesp=%x cmd=%s\n", err, eip, uesp, u.u_comm); \ ! 242: printf("efl=%x ", efl); } ! 243: ! 244: void ! 245: fptrap(gs, fs, es, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax, trapno, err, ! 246: eip, cs, efl, uesp, ss) ! 247: char *eip; ! 248: { ! 249: unsigned short sw; /* ndp status word */ ! 250: struct _fpstate * fsp = &u.u_ndpCon; ! 251: ! 252: if (err == SIFP) ! 253: u.u_regl = &gs; /* hook in register set for consave/conrest */ ! 254: ! 255: /* ! 256: * Send user a signal. ! 257: */ ! 258: ndpSave(fsp); ! 259: /* Clear exception flag in NDP to prevent runaway trap. */ ! 260: sw = fsp->status = fsp->sw; ! 261: fsp->sw &= 0x7f00; ! 262: wrNdpSaved(1); ! 263: if (ndpDump) { ! 264: RDUMP(); ! 265: printf("\nfcs=%x fip=%x fos=%x foo=%x\n", ! 266: fsp->cssel&0xffff, fsp->ipoff, ! 267: fsp->datasel&0xffff, fsp->dataoff); ! 268: printf("User Floating Point Trap: "); ! 269: if (sw & 1) ! 270: printf("Invalid Operation"); ! 271: else if (sw & 2) ! 272: printf("Denormalized Operand"); ! 273: else if (sw & 4) ! 274: printf("Divide by Zero"); ! 275: else if (sw & 8) ! 276: printf("Overflow"); ! 277: else if (sw & 0x10) ! 278: printf("Underflow"); ! 279: else if (sw & 0x20) ! 280: printf("Precision"); ! 281: else ! 282: printf("???"); ! 283: } ! 284: sendsig(SIGFPE, SELF); ! 285: } ! 286: ! 287: /* ! 288: * emtrap() ! 289: * ! 290: * Entered when NDP opcode is executed and EM bit of CR0 is 1. ! 291: * err is SIXNP (Device Not Available Fault) ! 292: */ ! 293: void ! 294: emtrap(gs, fs, es, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax, trapno, err, ! 295: eip, cs, efl, uesp, ss) ! 296: char *eip; ! 297: { ! 298: switch (ndpType) { ! 299: case NDP_TYPE_287: ! 300: case NDP_TYPE_387: ! 301: case NDP_TYPE_486: ! 302: ndpNewOwner(); ! 303: break; ! 304: default: ! 305: if (ndpDump) { ! 306: RDUMP(); ! 307: } ! 308: if (!rdEmTrapped()) { ! 309: wrEmTrapped(1); ! 310: emFinit(&u.u_ndpCon); ! 311: } ! 312: if (ndpEmFn) { ! 313: int looker = 1; ! 314: ! 315: /* ! 316: * No emulator lookahead if ptraced or ! 317: * single step process. ! 318: */ ! 319: if ((SELF->p_flags & PFTRAC) || (u.u_regl[EFL] & MFTTB)) ! 320: looker = 0; ! 321: (*ndpEmFn)(&gs, &u.u_ndpCon, looker); ! 322: } else ! 323: sendsig(ndpEmSig, SELF); ! 324: } ! 325: } ! 326: ! 327: /* ! 328: * IRQ 13 handler. Not used with 486. ! 329: */ ! 330: void ! 331: ndpIrq() ! 332: { ! 333: struct _fpstate * fsp = &u.u_ndpCon; ! 334: unsigned short sw; ! 335: ! 336: outb(NDP_PORT, 0); ! 337: /* ! 338: * Send user a signal. ! 339: */ ! 340: ndpSave(fsp); ! 341: /* Clear exception flag in NDP to prevent runaway trap. */ ! 342: sw = fsp->status = fsp->sw; ! 343: fsp->sw &= 0x7f00; ! 344: wrNdpSaved(1); ! 345: if (ndpDump) { ! 346: printf("\nfcs=%x fip=%x fos=%x foo=%x\n", ! 347: fsp->cssel&0xffff, fsp->ipoff, ! 348: fsp->datasel&0xffff, fsp->dataoff); ! 349: printf("User 387 Trap: "); ! 350: if (sw & 1) ! 351: printf("Invalid Operation"); ! 352: else if (sw & 2) ! 353: printf("Denormalized Operand"); ! 354: else if (sw & 4) ! 355: printf("Divide by Zero"); ! 356: else if (sw & 8) ! 357: printf("Overflow"); ! 358: else if (sw & 0x10) ! 359: printf("Underflow"); ! 360: else if (sw & 0x20) ! 361: printf("Precision"); ! 362: else ! 363: printf("???"); ! 364: } ! 365: sendsig(SIGFPE, SELF); ! 366: } ! 367: ! 368: /* ! 369: * ---------------------------------------------------------------------- ! 370: * Routines concerned with whether current process has used the ndp. ! 371: */ ! 372: int ! 373: rdNdpUser() ! 374: { ! 375: return (u.u_ndpFlags & NF_NDP_USER) ? 1 : 0; ! 376: } ! 377: ! 378: void ! 379: wrNdpUser(n) ! 380: int n; ! 381: { ! 382: if (n) ! 383: u.u_ndpFlags |= NF_NDP_USER; ! 384: else ! 385: u.u_ndpFlags &= ~NF_NDP_USER; ! 386: } ! 387: ! 388: /* ! 389: * Since saving NDP state is destructive, we need to keep track ! 390: * of where the current NDP state is - u area, or NDP? ! 391: */ ! 392: int ! 393: rdNdpSaved() ! 394: { ! 395: return (u.u_ndpFlags & NF_NDP_SAVED) ? 1 : 0; ! 396: } ! 397: ! 398: int ! 399: rdNdpSavedU(up) ! 400: UPROC * up; ! 401: { ! 402: return (up->u_ndpFlags & NF_NDP_SAVED) ? 1 : 0; ! 403: } ! 404: ! 405: void ! 406: wrNdpSaved(n) ! 407: int n; ! 408: { ! 409: if (n) ! 410: u.u_ndpFlags |= NF_NDP_SAVED; ! 411: else ! 412: u.u_ndpFlags &= ~NF_NDP_SAVED; ! 413: } ! 414: ! 415: void ! 416: wrNdpSavedU(n, up) ! 417: int n; ! 418: UPROC * up; ! 419: { ! 420: if (n) ! 421: up->u_ndpFlags |= NF_NDP_SAVED; ! 422: else ! 423: up->u_ndpFlags &= ~NF_NDP_SAVED; ! 424: } ! 425: ! 426: /* ! 427: * Enable (1) or disable (0) emulator traps. ! 428: */ ! 429: void ! 430: ndpEmTraps(n) ! 431: int n; ! 432: { ! 433: if (kerEm != n) { ! 434: kerEm = n; ! 435: setEm(n); ! 436: } ! 437: } ! 438: ! 439: /* ! 440: * Make ndp owned by no one. ! 441: */ ! 442: void ! 443: ndpDetach() ! 444: { ! 445: ndpOwner = 0; ! 446: ndpUseg = 0; ! 447: } ! 448: ! 449: /* ! 450: * Make ndp owned by the current process. ! 451: */ ! 452: void ! 453: ndpMine() ! 454: { ! 455: SR * srp = &(u.u_segl[SIUSERP]); ! 456: SEG * sp = srp->sr_segp; ! 457: ! 458: ndpOwner = SELF; ! 459: ndpUseg = MAPIO(sp->s_vmem, U_OFFSET); ! 460: } ! 461: ! 462: /* ! 463: * ---------------------------------------------------------------------- ! 464: * Code concerned with identifying coprocessor type, and taking specialized ! 465: * action depending on the type. ! 466: */ ! 467: ! 468: /* ! 469: * Using usual algorithms, determine existence and type of NDP. ! 470: * If interrupt vector needs to be set for FP exception, do it. ! 471: * ! 472: * If 2's bit of int11 is on, NDP is present. ! 473: */ ! 474: void ! 475: senseNdp() ! 476: { ! 477: if (ndpType == NDP_TYPE_UNPATCHED) { ! 478: ndpEmTraps(0); /* Will need to do some FP code. */ ! 479: ndpType = ndpSense(); /* Rely on assembler tricks now. */ ! 480: ndpEmTraps(1); ! 481: } ! 482: if (ndpType == NDP_TYPE_387 || ndpType == NDP_TYPE_287) { ! 483: setivec(NDP_IRQ, ndpIrq); ! 484: } ! 485: } ! 486: ! 487: /* ! 488: * Called from main(). ! 489: * Return name string for the type of coprocessor detected. ! 490: */ ! 491: char * ! 492: ndpTypeName() ! 493: { ! 494: char * ret = "**ERROR: Bad ndp type**"; ! 495: ! 496: switch(ndpType) { ! 497: case NDP_TYPE_NONE: ! 498: ret = "No NDP. "; ! 499: break; ! 500: case NDP_TYPE_287: ! 501: ret = "NDP=287. "; ! 502: break; ! 503: case NDP_TYPE_387: ! 504: ret = "NDP=387. "; ! 505: break; ! 506: case NDP_TYPE_486: ! 507: ret = "NDP=486. "; ! 508: break; ! 509: } ! 510: return ret; ! 511: } ! 512: ! 513: /* ! 514: * ---------------------------------------------------------------------- ! 515: * Little routines for tracking emulator state. ! 516: */ ! 517: ! 518: int ! 519: rdEmTrapped() ! 520: { ! 521: return (u.u_ndpFlags & NF_EM_TRAPPED) ? 1 : 0; ! 522: } ! 523: ! 524: void ! 525: wrEmTrapped(n) ! 526: int n; ! 527: { ! 528: if (n) ! 529: u.u_ndpFlags |= NF_EM_TRAPPED; ! 530: else ! 531: u.u_ndpFlags &= ~NF_EM_TRAPPED; ! 532: } ! 533: ! 534: /* ! 535: * Provide the emulator with a fresh context. ! 536: */ ! 537: void ! 538: emFinit(fpsp) ! 539: struct _fpemstate * fpsp; ! 540: { ! 541: register int r; ! 542: ! 543: memset(fpsp, '\0', sizeof(struct _fpemstate)); /* mostly zeroes */ ! 544: fpsp->cw = ndpCW; ! 545: for(r = 0; r < 8; r++) ! 546: fpsp->regs[r].tag = 7; /* Empty */ ! 547: } ! 548: ! 549: /* ! 550: * ---------------------------------------------------------------------- ! 551: * Functions to interface with the emulator. ! 552: */ ! 553: get_fs_byte(cp) ! 554: char *cp; ! 555: { ! 556: char getubd(); ! 557: ! 558: return getubd(cp); ! 559: } ! 560: ! 561: get_fs_word(sp) ! 562: short *sp; ! 563: { ! 564: short getusd(); ! 565: ! 566: return getusd(sp); ! 567: } ! 568: ! 569: get_fs_long(lp) ! 570: long *lp; ! 571: { ! 572: long getuwd(); ! 573: ! 574: return getuwd(lp); ! 575: } ! 576: ! 577: void ! 578: put_fs_byte(data, cp) ! 579: char *cp; ! 580: char data; ! 581: { ! 582: putubd(cp, data); ! 583: } ! 584: ! 585: void ! 586: put_fs_word(data, sp) ! 587: short *sp; ! 588: short data; ! 589: { ! 590: putusd(sp, data); ! 591: } ! 592: ! 593: void ! 594: put_fs_long(data, lp) ! 595: long *lp; ! 596: long data; ! 597: { ! 598: putuwd(lp, data); ! 599: } ! 600: ! 601: /* ! 602: * Return zero if out of bounds for write. ! 603: */ ! 604: int ! 605: verify_area(cp, len) ! 606: int * cp; ! 607: int len; ! 608: { ! 609: int ret = useracc(cp, len, 1); ! 610: ! 611: if (!ret) { ! 612: #if 0 ! 613: printf("Bad Em write, base=%x, len=%x, r.a.=%x", ! 614: cp, len, *(int *)((&cp) - 1)); ! 615: #endif ! 616: sendsig(SIGSEGV, SELF); ! 617: } ! 618: return ret; ! 619: } ! 620: ! 621: /* ! 622: * print kernel message. ! 623: */ ! 624: printk(s) ! 625: char *s; ! 626: { ! 627: puts(s); ! 628: } ! 629: ! 630: emSendsig() ! 631: { ! 632: sendsig(SIGFPE, SELF); ! 633: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.