|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1992-1990 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: ! 53: #include <cpus.h> ! 54: #include <platforms.h> ! 55: ! 56: #include <mach/exception_types.h> ! 57: #include <mach/i386/thread_status.h> ! 58: #include <mach/i386/fp_reg.h> ! 59: ! 60: #include <kern/mach_param.h> ! 61: #include <kern/thread.h> ! 62: #include <kern/zalloc.h> ! 63: #include <kern/misc_protos.h> ! 64: #include <kern/spl.h> ! 65: #include <kern/assert.h> ! 66: ! 67: #include <i386/thread.h> ! 68: #include <i386/fpu.h> ! 69: #include <i386/trap.h> ! 70: #include <i386/pio.h> ! 71: #include <i386/misc_protos.h> ! 72: ! 73: #if 0 ! 74: #include <i386/ipl.h> ! 75: extern int curr_ipl; ! 76: #define ASSERT_IPL(L) \ ! 77: { \ ! 78: if (curr_ipl != L) { \ ! 79: printf("IPL is %d, expected %d\n", curr_ipl, L); \ ! 80: panic("fpu: wrong ipl"); \ ! 81: } \ ! 82: } ! 83: #else ! 84: #define ASSERT_IPL(L) ! 85: #endif ! 86: ! 87: int fp_kind = FP_387; /* 80387 present */ ! 88: zone_t ifps_zone; /* zone for FPU save area */ ! 89: ! 90: #if NCPUS == 1 ! 91: volatile thread_act_t fp_act = THR_ACT_NULL; ! 92: /* thread whose state is in FPU */ ! 93: /* always THR_ACT_NULL if emulating FPU */ ! 94: volatile thread_act_t fp_intr_act = THR_ACT_NULL; ! 95: ! 96: ! 97: #define clear_fpu() \ ! 98: { \ ! 99: set_ts(); \ ! 100: fp_act = THR_ACT_NULL; \ ! 101: } ! 102: ! 103: #else /* NCPUS > 1 */ ! 104: #define clear_fpu() \ ! 105: { \ ! 106: set_ts(); \ ! 107: } ! 108: ! 109: #endif ! 110: ! 111: /* Forward */ ! 112: ! 113: extern void fpinit(void); ! 114: extern void fp_save( ! 115: thread_act_t thr_act); ! 116: extern void fp_load( ! 117: thread_act_t thr_act); ! 118: ! 119: /* ! 120: * Look for FPU and initialize it. ! 121: * Called on each CPU. ! 122: */ ! 123: void ! 124: init_fpu(void) ! 125: { ! 126: unsigned short status, control; ! 127: ! 128: /* ! 129: * Check for FPU by initializing it, ! 130: * then trying to read the correct bit patterns from ! 131: * the control and status registers. ! 132: */ ! 133: set_cr0(get_cr0() & ~(CR0_EM|CR0_TS)); /* allow use of FPU */ ! 134: ! 135: fninit(); ! 136: status = fnstsw(); ! 137: fnstcw(&control); ! 138: ! 139: if ((status & 0xff) == 0 && ! 140: (control & 0x103f) == 0x3f) ! 141: { ! 142: #if 0 ! 143: /* ! 144: * We have a FPU of some sort. ! 145: * Compare -infinity against +infinity ! 146: * to check whether we have a 287 or a 387. ! 147: */ ! 148: volatile double fp_infinity, fp_one, fp_zero; ! 149: fp_one = 1.0; ! 150: fp_zero = 0.0; ! 151: fp_infinity = fp_one / fp_zero; ! 152: if (fp_infinity == -fp_infinity) { ! 153: /* ! 154: * We have an 80287. ! 155: */ ! 156: fp_kind = FP_287; ! 157: __asm__ volatile(".byte 0xdb; .byte 0xe4"); /* fnsetpm */ ! 158: } ! 159: else ! 160: #endif ! 161: { ! 162: /* ! 163: * We have a 387. ! 164: */ ! 165: fp_kind = FP_387; ! 166: } ! 167: /* ! 168: * Trap wait instructions. Turn off FPU for now. ! 169: */ ! 170: set_cr0(get_cr0() | CR0_TS | CR0_MP); ! 171: } ! 172: else ! 173: { ! 174: /* ! 175: * NO FPU. ! 176: */ ! 177: fp_kind = FP_NO; ! 178: set_cr0(get_cr0() | CR0_EM); ! 179: } ! 180: } ! 181: ! 182: /* ! 183: * Initialize FP handling. ! 184: */ ! 185: void ! 186: fpu_module_init(void) ! 187: { ! 188: ifps_zone = zinit(sizeof(struct i386_fpsave_state), ! 189: THREAD_MAX * sizeof(struct i386_fpsave_state), ! 190: THREAD_CHUNK * sizeof(struct i386_fpsave_state), ! 191: "i386 fpsave state"); ! 192: } ! 193: ! 194: /* ! 195: * Free a FPU save area. ! 196: * Called only when thread terminating - no locking necessary. ! 197: */ ! 198: void ! 199: fp_free(fps) ! 200: struct i386_fpsave_state *fps; ! 201: { ! 202: ASSERT_IPL(SPL0); ! 203: #if NCPUS == 1 ! 204: if ((fp_act != THR_ACT_NULL) && (fp_act->mact.pcb->ims.ifps == fps)) { ! 205: /* ! 206: * Make sure we don't get FPU interrupts later for ! 207: * this thread ! 208: */ ! 209: fwait(); ! 210: ! 211: /* Mark it free and disable access */ ! 212: clear_fpu(); ! 213: } ! 214: #endif /* NCPUS == 1 */ ! 215: zfree(ifps_zone, (vm_offset_t) fps); ! 216: } ! 217: ! 218: /* ! 219: * Set the floating-point state for a thread. ! 220: * If the thread is not the current thread, it is ! 221: * not running (held). Locking needed against ! 222: * concurrent fpu_set_state or fpu_get_state. ! 223: */ ! 224: kern_return_t ! 225: fpu_set_state( ! 226: thread_act_t thr_act, ! 227: struct i386_float_state *state) ! 228: { ! 229: register pcb_t pcb; ! 230: register struct i386_fpsave_state *ifps; ! 231: register struct i386_fpsave_state *new_ifps; ! 232: ! 233: ASSERT_IPL(SPL0); ! 234: if (fp_kind == FP_NO) ! 235: return KERN_FAILURE; ! 236: ! 237: assert(thr_act != THR_ACT_NULL); ! 238: pcb = thr_act->mact.pcb; ! 239: ! 240: #if NCPUS == 1 ! 241: ! 242: /* ! 243: * If this thread`s state is in the FPU, ! 244: * discard it; we are replacing the entire ! 245: * FPU state. ! 246: */ ! 247: if (fp_act == thr_act) { ! 248: fwait(); /* wait for possible interrupt */ ! 249: clear_fpu(); /* no state in FPU */ ! 250: } ! 251: #endif ! 252: ! 253: if (state->initialized == 0) { ! 254: /* ! 255: * new FPU state is 'invalid'. ! 256: * Deallocate the fp state if it exists. ! 257: */ ! 258: simple_lock(&pcb->lock); ! 259: ifps = pcb->ims.ifps; ! 260: pcb->ims.ifps = 0; ! 261: simple_unlock(&pcb->lock); ! 262: ! 263: if (ifps != 0) { ! 264: zfree(ifps_zone, (vm_offset_t) ifps); ! 265: } ! 266: } ! 267: else { ! 268: /* ! 269: * Valid state. Allocate the fp state if there is none. ! 270: */ ! 271: register struct i386_fp_save *user_fp_state; ! 272: register struct i386_fp_regs *user_fp_regs; ! 273: ! 274: user_fp_state = (struct i386_fp_save *) &state->hw_state[0]; ! 275: user_fp_regs = (struct i386_fp_regs *) ! 276: &state->hw_state[sizeof(struct i386_fp_save)]; ! 277: ! 278: new_ifps = 0; ! 279: Retry: ! 280: simple_lock(&pcb->lock); ! 281: ifps = pcb->ims.ifps; ! 282: if (ifps == 0) { ! 283: if (new_ifps == 0) { ! 284: simple_unlock(&pcb->lock); ! 285: new_ifps = (struct i386_fpsave_state *) zalloc(ifps_zone); ! 286: goto Retry; ! 287: } ! 288: ifps = new_ifps; ! 289: new_ifps = 0; ! 290: pcb->ims.ifps = ifps; ! 291: } ! 292: ! 293: /* ! 294: * Ensure that reserved parts of the environment are 0. ! 295: */ ! 296: bzero((char *)&ifps->fp_save_state, sizeof(struct i386_fp_save)); ! 297: ! 298: ifps->fp_save_state.fp_control = user_fp_state->fp_control; ! 299: ifps->fp_save_state.fp_status = user_fp_state->fp_status; ! 300: ifps->fp_save_state.fp_tag = user_fp_state->fp_tag; ! 301: ifps->fp_save_state.fp_eip = user_fp_state->fp_eip; ! 302: ifps->fp_save_state.fp_cs = user_fp_state->fp_cs; ! 303: ifps->fp_save_state.fp_opcode = user_fp_state->fp_opcode; ! 304: ifps->fp_save_state.fp_dp = user_fp_state->fp_dp; ! 305: ifps->fp_save_state.fp_ds = user_fp_state->fp_ds; ! 306: ifps->fp_regs = *user_fp_regs; ! 307: ! 308: simple_unlock(&pcb->lock); ! 309: if (new_ifps != 0) ! 310: zfree(ifps_zone, (vm_offset_t) ifps); ! 311: } ! 312: ! 313: return KERN_SUCCESS; ! 314: } ! 315: ! 316: /* ! 317: * Get the floating-point state for a thread. ! 318: * If the thread is not the current thread, it is ! 319: * not running (held). Locking needed against ! 320: * concurrent fpu_set_state or fpu_get_state. ! 321: */ ! 322: kern_return_t ! 323: fpu_get_state( ! 324: thread_act_t thr_act, ! 325: register struct i386_float_state *state) ! 326: { ! 327: register pcb_t pcb; ! 328: register struct i386_fpsave_state *ifps; ! 329: ! 330: ASSERT_IPL(SPL0); ! 331: if (fp_kind == FP_NO) ! 332: return KERN_FAILURE; ! 333: ! 334: assert(thr_act != THR_ACT_NULL); ! 335: pcb = thr_act->mact.pcb; ! 336: ! 337: simple_lock(&pcb->lock); ! 338: ifps = pcb->ims.ifps; ! 339: if (ifps == 0) { ! 340: /* ! 341: * No valid floating-point state. ! 342: */ ! 343: simple_unlock(&pcb->lock); ! 344: bzero((char *)state, sizeof(struct i386_float_state)); ! 345: return KERN_SUCCESS; ! 346: } ! 347: ! 348: /* Make sure we`ve got the latest fp state info */ ! 349: /* If the live fpu state belongs to our target */ ! 350: #if NCPUS == 1 ! 351: if (thr_act == fp_act) ! 352: #else ! 353: if (thr_act == current_act()) ! 354: #endif ! 355: { ! 356: clear_ts(); ! 357: fp_save(thr_act); ! 358: clear_fpu(); ! 359: } ! 360: ! 361: state->fpkind = fp_kind; ! 362: state->exc_status = 0; ! 363: ! 364: { ! 365: register struct i386_fp_save *user_fp_state; ! 366: register struct i386_fp_regs *user_fp_regs; ! 367: ! 368: state->initialized = ifps->fp_valid; ! 369: ! 370: user_fp_state = (struct i386_fp_save *) &state->hw_state[0]; ! 371: user_fp_regs = (struct i386_fp_regs *) ! 372: &state->hw_state[sizeof(struct i386_fp_save)]; ! 373: ! 374: /* ! 375: * Ensure that reserved parts of the environment are 0. ! 376: */ ! 377: bzero((char *)user_fp_state, sizeof(struct i386_fp_save)); ! 378: ! 379: user_fp_state->fp_control = ifps->fp_save_state.fp_control; ! 380: user_fp_state->fp_status = ifps->fp_save_state.fp_status; ! 381: user_fp_state->fp_tag = ifps->fp_save_state.fp_tag; ! 382: user_fp_state->fp_eip = ifps->fp_save_state.fp_eip; ! 383: user_fp_state->fp_cs = ifps->fp_save_state.fp_cs; ! 384: user_fp_state->fp_opcode = ifps->fp_save_state.fp_opcode; ! 385: user_fp_state->fp_dp = ifps->fp_save_state.fp_dp; ! 386: user_fp_state->fp_ds = ifps->fp_save_state.fp_ds; ! 387: *user_fp_regs = ifps->fp_regs; ! 388: } ! 389: simple_unlock(&pcb->lock); ! 390: ! 391: return KERN_SUCCESS; ! 392: } ! 393: ! 394: /* ! 395: * Initialize FPU. ! 396: * ! 397: * Raise exceptions for: ! 398: * invalid operation ! 399: * divide by zero ! 400: * overflow ! 401: * ! 402: * Use 53-bit precision. ! 403: */ ! 404: void ! 405: fpinit(void) ! 406: { ! 407: unsigned short control; ! 408: ! 409: ASSERT_IPL(SPL0); ! 410: clear_ts(); ! 411: fninit(); ! 412: fnstcw(&control); ! 413: control &= ~(FPC_PC|FPC_RC); /* Clear precision & rounding control */ ! 414: control |= (FPC_PC_53 | /* Set precision */ ! 415: FPC_RC_RN | /* round-to-nearest */ ! 416: FPC_ZE | /* Suppress zero-divide */ ! 417: FPC_OE | /* and overflow */ ! 418: FPC_UE | /* underflow */ ! 419: FPC_IE | /* Allow NaNQs and +-INF */ ! 420: FPC_DE | /* Allow denorms as operands */ ! 421: FPC_PE); /* No trap for precision loss */ ! 422: fldcw(control); ! 423: } ! 424: ! 425: /* ! 426: * Coprocessor not present. ! 427: */ ! 428: ! 429: void ! 430: fpnoextflt(void) ! 431: { ! 432: /* ! 433: * Enable FPU use. ! 434: */ ! 435: ASSERT_IPL(SPL0); ! 436: clear_ts(); ! 437: #if NCPUS == 1 ! 438: ! 439: /* ! 440: * If this thread`s state is in the FPU, we are done. ! 441: */ ! 442: if (fp_act == current_act()) ! 443: return; ! 444: ! 445: /* Make sure we don't do fpsave() in fp_intr while doing fpsave() ! 446: * here if the current fpu instruction generates an error. ! 447: */ ! 448: fwait(); ! 449: /* ! 450: * If another thread`s state is in the FPU, save it. ! 451: */ ! 452: if (fp_act != THR_ACT_NULL) { ! 453: fp_save(fp_act); ! 454: } ! 455: ! 456: /* ! 457: * Give this thread the FPU. ! 458: */ ! 459: fp_act = current_act(); ! 460: ! 461: #endif /* NCPUS == 1 */ ! 462: ! 463: /* ! 464: * Load this thread`s state into the FPU. ! 465: */ ! 466: fp_load(current_act()); ! 467: } ! 468: ! 469: /* ! 470: * FPU overran end of segment. ! 471: * Re-initialize FPU. Floating point state is not valid. ! 472: */ ! 473: ! 474: void ! 475: fpextovrflt(void) ! 476: { ! 477: register thread_act_t thr_act = current_act(); ! 478: register pcb_t pcb; ! 479: register struct i386_fpsave_state *ifps; ! 480: ! 481: #if NCPUS == 1 ! 482: ! 483: /* ! 484: * Is exception for the currently running thread? ! 485: */ ! 486: if (fp_act != thr_act) { ! 487: /* Uh oh... */ ! 488: panic("fpextovrflt"); ! 489: } ! 490: #endif ! 491: ! 492: /* ! 493: * This is a non-recoverable error. ! 494: * Invalidate the thread`s FPU state. ! 495: */ ! 496: pcb = thr_act->mact.pcb; ! 497: simple_lock(&pcb->lock); ! 498: ifps = pcb->ims.ifps; ! 499: pcb->ims.ifps = 0; ! 500: simple_unlock(&pcb->lock); ! 501: ! 502: /* ! 503: * Re-initialize the FPU. ! 504: */ ! 505: clear_ts(); ! 506: fninit(); ! 507: ! 508: /* ! 509: * And disable access. ! 510: */ ! 511: clear_fpu(); ! 512: ! 513: if (ifps) ! 514: zfree(ifps_zone, (vm_offset_t) ifps); ! 515: ! 516: /* ! 517: * Raise exception. ! 518: */ ! 519: i386_exception(EXC_BAD_ACCESS, VM_PROT_READ|VM_PROT_EXECUTE, 0); ! 520: /*NOTREACHED*/ ! 521: } ! 522: ! 523: /* ! 524: * FPU error. Called by AST. ! 525: */ ! 526: ! 527: void ! 528: fpexterrflt(void) ! 529: { ! 530: register thread_act_t thr_act = current_act(); ! 531: ! 532: ASSERT_IPL(SPL0); ! 533: #if NCPUS == 1 ! 534: /* ! 535: * Since FPU errors only occur on ESC or WAIT instructions, ! 536: * the current thread should own the FPU. If it didn`t, ! 537: * we should have gotten the task-switched interrupt first. ! 538: */ ! 539: if (fp_act != THR_ACT_NULL) { ! 540: panic("fpexterrflt"); ! 541: return; ! 542: } ! 543: ! 544: /* ! 545: * Check if we got a context switch between the interrupt and the AST ! 546: * This can happen if the interrupt arrived after the FPU AST was ! 547: * checked. In this case, raise the exception in fp_load when this ! 548: * thread next time uses the FPU. Remember exception condition in ! 549: * fp_valid (extended boolean 2). ! 550: */ ! 551: if (fp_intr_act != thr_act) { ! 552: if (fp_intr_act == THR_ACT_NULL) { ! 553: panic("fpexterrflt: fp_intr_act == THR_ACT_NULL"); ! 554: return; ! 555: } ! 556: fp_intr_act->mact.pcb->ims.ifps->fp_valid = 2; ! 557: fp_intr_act = THR_ACT_NULL; ! 558: return; ! 559: } ! 560: fp_intr_act = THR_ACT_NULL; ! 561: #else /* NCPUS == 1 */ ! 562: /* ! 563: * Save the FPU state and turn off the FPU. ! 564: */ ! 565: fp_save(thr_act); ! 566: #endif /* NCPUS == 1 */ ! 567: ! 568: /* ! 569: * Raise FPU exception. ! 570: * Locking not needed on pcb->ims.ifps, ! 571: * since thread is running. ! 572: */ ! 573: i386_exception(EXC_ARITHMETIC, ! 574: EXC_I386_EXTERR, ! 575: thr_act->mact.pcb->ims.ifps->fp_save_state.fp_status); ! 576: /*NOTREACHED*/ ! 577: } ! 578: ! 579: /* ! 580: * Save FPU state. ! 581: * ! 582: * Locking not needed: ! 583: * . if called from fpu_get_state, pcb already locked. ! 584: * . if called from fpnoextflt or fp_intr, we are single-cpu ! 585: * . otherwise, thread is running. ! 586: */ ! 587: ! 588: void ! 589: fp_save( ! 590: thread_act_t thr_act) ! 591: { ! 592: register pcb_t pcb = thr_act->mact.pcb; ! 593: register struct i386_fpsave_state *ifps = pcb->ims.ifps; ! 594: ! 595: if (ifps != 0 && !ifps->fp_valid) { ! 596: /* registers are in FPU */ ! 597: ifps->fp_valid = TRUE; ! 598: fnsave(&ifps->fp_save_state); ! 599: } ! 600: } ! 601: ! 602: /* ! 603: * Restore FPU state from PCB. ! 604: * ! 605: * Locking not needed; always called on the current thread. ! 606: */ ! 607: ! 608: void ! 609: fp_load( ! 610: thread_act_t thr_act) ! 611: { ! 612: register pcb_t pcb = thr_act->mact.pcb; ! 613: register struct i386_fpsave_state *ifps; ! 614: ! 615: ASSERT_IPL(SPL0); ! 616: ifps = pcb->ims.ifps; ! 617: if (ifps == 0) { ! 618: ifps = (struct i386_fpsave_state *) zalloc(ifps_zone); ! 619: bzero((char *)ifps, sizeof *ifps); ! 620: pcb->ims.ifps = ifps; ! 621: fpinit(); ! 622: #if 1 ! 623: /* ! 624: * I'm not sure this is needed. Does the fpu regenerate the interrupt in ! 625: * frstor or not? Without this code we may miss some exceptions, with it ! 626: * we might send too many exceptions. ! 627: */ ! 628: } else if (ifps->fp_valid == 2) { ! 629: /* delayed exception pending */ ! 630: ! 631: ifps->fp_valid = TRUE; ! 632: clear_fpu(); ! 633: /* ! 634: * Raise FPU exception. ! 635: * Locking not needed on pcb->ims.ifps, ! 636: * since thread is running. ! 637: */ ! 638: i386_exception(EXC_ARITHMETIC, ! 639: EXC_I386_EXTERR, ! 640: thr_act->mact.pcb->ims.ifps->fp_save_state.fp_status); ! 641: /*NOTREACHED*/ ! 642: #endif ! 643: } else { ! 644: frstor(ifps->fp_save_state); ! 645: } ! 646: ifps->fp_valid = FALSE; /* in FPU */ ! 647: } ! 648: ! 649: /* ! 650: * Allocate and initialize FP state for current thread. ! 651: * Don't load state. ! 652: * ! 653: * Locking not needed; always called on the current thread. ! 654: */ ! 655: void ! 656: fp_state_alloc(void) ! 657: { ! 658: pcb_t pcb = current_act()->mact.pcb; ! 659: struct i386_fpsave_state *ifps; ! 660: ! 661: ifps = (struct i386_fpsave_state *)zalloc(ifps_zone); ! 662: bzero((char *)ifps, sizeof *ifps); ! 663: pcb->ims.ifps = ifps; ! 664: ! 665: ifps->fp_valid = TRUE; ! 666: ifps->fp_save_state.fp_control = (0x037f ! 667: & ~(FPC_IM|FPC_ZM|FPC_OM|FPC_PC)) ! 668: | (FPC_PC_53|FPC_IC_AFF); ! 669: ifps->fp_save_state.fp_status = 0; ! 670: ifps->fp_save_state.fp_tag = 0xffff; /* all empty */ ! 671: } ! 672: ! 673: ! 674: /* ! 675: * fpflush(thread_act_t) ! 676: * Flush the current act's state, if needed ! 677: * (used by thread_terminate_self to ensure fp faults ! 678: * aren't satisfied by overly general trap code in the ! 679: * context of the reaper thread) ! 680: */ ! 681: void ! 682: fpflush(thread_act_t thr_act) ! 683: { ! 684: #if NCPUS == 1 ! 685: if (fp_act && thr_act == fp_act) { ! 686: clear_ts(); ! 687: fwait(); ! 688: clear_fpu(); ! 689: } ! 690: #else ! 691: /* not needed on MP x86s; fp not lazily evaluated */ ! 692: #endif ! 693: } ! 694: ! 695: ! 696: /* ! 697: * Handle a coprocessor error interrupt on the AT386. ! 698: * This comes in on line 5 of the slave PIC at SPL1. ! 699: */ ! 700: ! 701: void ! 702: fpintr(void) ! 703: { ! 704: spl_t s; ! 705: thread_act_t thr_act = current_act(); ! 706: ! 707: ASSERT_IPL(SPL1); ! 708: /* ! 709: * Turn off the extended 'busy' line. ! 710: */ ! 711: outb(0xf0, 0); ! 712: ! 713: /* ! 714: * Save the FPU context to the thread using it. ! 715: */ ! 716: #if NCPUS == 1 ! 717: if (fp_act == THR_ACT_NULL) { ! 718: printf("fpintr: FPU not belonging to anyone!\n"); ! 719: clear_ts(); ! 720: fninit(); ! 721: clear_fpu(); ! 722: return; ! 723: } ! 724: ! 725: if (fp_act != thr_act) { ! 726: /* ! 727: * FPU exception is for a different thread. ! 728: * When that thread again uses the FPU an exception will be ! 729: * raised in fp_load. Remember the condition in fp_valid (== 2). ! 730: */ ! 731: clear_ts(); ! 732: fp_save(fp_act); ! 733: fp_act->mact.pcb->ims.ifps->fp_valid = 2; ! 734: fninit(); ! 735: clear_fpu(); ! 736: /* leave fp_intr_act THR_ACT_NULL */ ! 737: return; ! 738: } ! 739: if (fp_intr_act != THR_ACT_NULL) ! 740: panic("fp_intr: already caught intr"); ! 741: fp_intr_act = thr_act; ! 742: #endif /* NCPUS == 1 */ ! 743: ! 744: clear_ts(); ! 745: fp_save(thr_act); ! 746: fninit(); ! 747: clear_fpu(); ! 748: ! 749: /* ! 750: * Since we are running on the interrupt stack, we must ! 751: * signal the thread to take the exception when we return ! 752: * to user mode. Use an AST to do this. ! 753: * ! 754: * Don`t set the thread`s AST field. If the thread is ! 755: * descheduled before it takes the AST, it will notice ! 756: * the FPU error when it reloads its FPU state. ! 757: */ ! 758: s = splsched(); ! 759: mp_disable_preemption(); ! 760: ast_on(AST_I386_FP); ! 761: mp_enable_preemption(); ! 762: splx(s); ! 763: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.