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