|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1992, 1993 NeXT Computer, Inc. ! 27: * ! 28: * Floating point support. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 21 June 1993 ? at NeXT ! 33: * Major rewrite to add special support for SoftPC. ! 34: * 10 September 1992 ? at NeXT ! 35: * Created. ! 36: */ ! 37: ! 38: #import <mach/mach_types.h> ! 39: #import <mach/exception.h> ! 40: ! 41: #import <machdep/i386/cpu_inline.h> ! 42: #import <machdep/i386/fp_inline.h> ! 43: #import <machdep/i386/fp_exported.h> ! 44: #import <machdep/i386/configure.h> ! 45: ! 46: #import <fp_emul.h> ! 47: #if FP_EMUL ! 48: #import <machdep/i386/table_inline.h> ! 49: #import <machdep/i386/desc_inline.h> ! 50: #endif ! 51: ! 52: #import <pc_support.h> ! 53: #if PC_SUPPORT ! 54: #import <machdep/i386/pc_support/PCprivate.h> ! 55: #endif ! 56: ! 57: static thread_t fp_thread; ! 58: ! 59: static ! 60: inline void fp_init(fp_state_t *fpstate), ! 61: fp_init_default(fp_state_t *fpstate), ! 62: fp_unowned(void), ! 63: fp_save(void), ! 64: fp_restore(void); ! 65: ! 66: static void fp_switch(void); ! 67: ! 68: #import <bsd/i386/reboot.h> ! 69: extern int boothowto; ! 70: ! 71: /* ! 72: * Determine whether this machine ! 73: * contains a hardware FPU and configure ! 74: * the CPU accordingly. ! 75: */ ! 76: ! 77: void ! 78: fp_configure(void) ! 79: { ! 80: cr0_t _cr0 = cr0(); ! 81: volatile ! 82: unsigned short status_word; ! 83: ! 84: /* ! 85: * Make sure that floating ! 86: * point operations do not ! 87: * cause a trap. ! 88: */ ! 89: _cr0.em = _cr0.ts = 0; ! 90: set_cr0(_cr0); ! 91: ! 92: /* ! 93: * Machines with a hardware ! 94: * FPU will return a status ! 95: * word of zero after an finit, ! 96: * Machines without an FPU will ! 97: * not modify the destination ! 98: * operand. ! 99: */ ! 100: status_word = 0x5a5a; ! 101: ! 102: asm volatile( ! 103: "fninit; ! 104: fnstsw %0" ! 105: : "=m" (status_word)); ! 106: ! 107: if (status_word != 0 || (boothowto&RB_NOFP) != 0) { ! 108: /* ! 109: * Either this machine ! 110: * does not have an FPU, ! 111: * or we want to test the ! 112: * floating point emulator. ! 113: * Turn on the EM bit in CR0 ! 114: * so that all floating point ! 115: * opcodes cause a trap. ! 116: */ ! 117: _cr0.em = 1; // cause floating point instructions to trap INT7 ! 118: _cr0.mp = 0; // cause WAIT instructions to trap INT7 ! 119: set_cr0(_cr0); ! 120: #if FP_EMUL ! 121: cpu_config.fpu_type = FPU_EMUL; ! 122: #endif ! 123: } ! 124: else { ! 125: _cr0.ne = 1; // cause unmasked floating point exceptions to trap INT16 ! 126: _cr0.mp = 1; ! 127: set_cr0(_cr0); ! 128: cpu_config.fpu_type = FPU_HDW; ! 129: } ! 130: } ! 131: ! 132: /* ! 133: * Called on occurance of INT7 from ! 134: * user mode. ! 135: */ ! 136: ! 137: void ! 138: fp_noextension( ! 139: thread_saved_state_t *state ! 140: ) ! 141: { ! 142: if (cpu_config.fpu_type == FPU_NONE) { ! 143: /* ! 144: * If we are not providing ! 145: * floating point support, ! 146: * just send an exception. ! 147: */ ! 148: exception(EXC_EMULATION, EXC_I386_NOEXTENSION, 0); ! 149: /* NOTREACHED */ ! 150: } ! 151: ! 152: /* ! 153: * Switch the fpu context ! 154: * if necessary. ! 155: */ ! 156: fp_switch(); ! 157: ! 158: #if FP_EMUL ! 159: if (cpu_config.fpu_type == FPU_EMUL) { ! 160: /* ! 161: * If we are using the ! 162: * kernel floating point ! 163: * emulator, call it. ! 164: */ ! 165: e80387(state); ! 166: } ! 167: #endif ! 168: } ! 169: ! 170: /* ! 171: * Called on occurance of INT16 from ! 172: * user mode. ! 173: */ ! 174: ! 175: void ! 176: fp_extension_fault( ! 177: thread_saved_state_t *state ! 178: ) ! 179: { ! 180: thread_t exception_thread = fp_thread; ! 181: ! 182: /* ! 183: * Stop the floating point unit ! 184: * dead in its tracks. We do not ! 185: * want another exception to occur. ! 186: */ ! 187: fp_save(); // sets fp_thread = THREAD_NULL ! 188: ! 189: if (exception_thread == current_thread()) { ! 190: exception(EXC_ARITHMETIC, EXC_I386_EXTENSION_FAULT, 0); ! 191: /* NOTREACHED */ ! 192: } ! 193: else ! 194: thread_ast_set(exception_thread, AST_FP_EXTEN); ! 195: } ! 196: ! 197: /* ! 198: * Called on occurance of INT16 from ! 199: * kernel mode. ! 200: */ ! 201: void ! 202: fp_kernel_extension_fault( ! 203: thread_saved_state_t *state ! 204: ) ! 205: { ! 206: thread_t exception_thread = fp_thread; ! 207: ! 208: /* ! 209: * Stop the floating point unit. ! 210: */ ! 211: fp_save(); // sets fp_thread = THREAD_NULL ! 212: ! 213: thread_ast_set(exception_thread, AST_FP_EXTEN); ! 214: if (exception_thread == current_thread()) ! 215: ast_propagate(exception_thread, cpu_number()); ! 216: } ! 217: ! 218: void ! 219: fp_ast( ! 220: thread_t thread ! 221: ) ! 222: { ! 223: thread_ast_clear(thread, AST_FP_EXTEN); ! 224: ! 225: exception(EXC_ARITHMETIC, EXC_I386_EXTENSION_FAULT, 0); ! 226: /* NOTREACHED */ ! 227: } ! 228: ! 229: /* ! 230: * Initialize a saved floating point ! 231: * context as if an FINIT was performed. ! 232: * Used to initialize a context for the ! 233: * software emulator, as well as to ! 234: * initialize an unused context so that ! 235: * thread_get_state() returns something ! 236: * sensible for a thread that has not ! 237: * performed any floating point operations. ! 238: */ ! 239: ! 240: /* ! 241: * Initialize the floating point ! 242: * state to the hardware default. ! 243: */ ! 244: static inline ! 245: void ! 246: fp_init_default( ! 247: fp_state_t *fpstate ! 248: ) ! 249: { ! 250: *(unsigned short *)&fpstate->environ.control = 0x037F; ! 251: *(unsigned short *)&fpstate->environ.status = 0x0000; ! 252: *(unsigned short *)&fpstate->environ.tag = 0xFFFF; ! 253: ! 254: fpstate->environ.ip = 0x00000000; ! 255: fpstate->environ.opcode = 0x0000; ! 256: fpstate->environ.cs = NULL_SEL; ! 257: fpstate->environ.dp = 0x00000000; ! 258: fpstate->environ.ds = NULL_SEL; ! 259: } ! 260: ! 261: /* ! 262: * Initialize the floating point ! 263: * state to that needed by the ! 264: * NEXTSTEP floating point model: ! 265: * double precision, round to ! 266: * nearest or even. ! 267: */ ! 268: static inline ! 269: void ! 270: fp_init( ! 271: fp_state_t *fpstate ! 272: ) ! 273: { ! 274: *(unsigned short *)&fpstate->environ.control = 0x027F; ! 275: *(unsigned short *)&fpstate->environ.status = 0x0000; ! 276: *(unsigned short *)&fpstate->environ.tag = 0xFFFF; ! 277: ! 278: fpstate->environ.ip = 0x00000000; ! 279: fpstate->environ.opcode = 0x0000; ! 280: fpstate->environ.cs = NULL_SEL; ! 281: fpstate->environ.dp = 0x00000000; ! 282: fpstate->environ.ds = NULL_SEL; ! 283: } ! 284: ! 285: /* ! 286: * Save the floating point context ! 287: * for the thread which owns the FPU ! 288: * and mark it unowned. N.B. This might ! 289: * not be the current thread. ! 290: */ ! 291: ! 292: static inline ! 293: void ! 294: fp_save(void) ! 295: { ! 296: thread_t thread = fp_thread; ! 297: ! 298: if (thread) { ! 299: #if PC_SUPPORT ! 300: PCshared_t shared = threadPCShared(thread); ! 301: ! 302: if (shared && shared->fpuOwned) { ! 303: if (cpu_config.fpu_type == FPU_HDW) ! 304: fnsave(&shared->fpuState); // clears TS flag ! 305: ! 306: shared->fpuStateValid = TRUE; ! 307: } ! 308: else { ! 309: #endif ! 310: if (cpu_config.fpu_type == FPU_HDW) ! 311: fnsave(&thread->pcb->fpstate); // clears TS flag ! 312: ! 313: thread->pcb->fpvalid = TRUE; ! 314: #if PC_SUPPORT ! 315: } ! 316: #endif ! 317: ! 318: fp_unowned(); ! 319: } ! 320: } ! 321: ! 322: /* ! 323: * Restore the floating point context of the ! 324: * current thread. The main assumption here ! 325: * is that the FPU is currently NOT owned by ! 326: * any thread. ! 327: */ ! 328: ! 329: static inline ! 330: void ! 331: fp_restore(void) ! 332: { ! 333: thread_t thread = current_thread(); ! 334: #if PC_SUPPORT ! 335: PCshared_t shared = threadPCShared(thread); ! 336: ! 337: if (shared) { ! 338: PCcontext_t context = currentContext(shared); ! 339: ! 340: if (context->running) { ! 341: if (shared->fpuStateValid) { ! 342: if (cpu_config.fpu_type == FPU_HDW) ! 343: frstor(&shared->fpuState); // clears TS flag ! 344: ! 345: shared->fpuStateValid = FALSE; ! 346: } ! 347: else { ! 348: fp_init_default(&shared->fpuState); ! 349: ! 350: if (cpu_config.fpu_type == FPU_HDW) ! 351: frstor(&shared->fpuState); // clears TS flag ! 352: } ! 353: ! 354: #if FP_EMUL ! 355: if (cpu_config.fpu_type == FPU_EMUL) ! 356: map_data(sel_to_gdt_entry(FPSTATE_SEL), ! 357: (vm_offset_t) &shared->fpuState ! 358: + KERNEL_LINEAR_BASE, ! 359: (vm_size_t) sizeof (shared->fpuState), ! 360: KERN_PRIV, FALSE); ! 361: #endif ! 362: ! 363: shared->fpuOwned = TRUE; ! 364: } ! 365: else { ! 366: shared->fpuOwned = FALSE; ! 367: goto restore_thread; ! 368: } ! 369: } ! 370: else { ! 371: restore_thread: ! 372: #endif ! 373: if (thread->pcb->fpvalid) { ! 374: if (cpu_config.fpu_type == FPU_HDW) ! 375: frstor(&thread->pcb->fpstate); // clears TS flag ! 376: ! 377: thread->pcb->fpvalid = FALSE; ! 378: } ! 379: else { ! 380: fp_init(&thread->pcb->fpstate); ! 381: ! 382: if (cpu_config.fpu_type == FPU_HDW) ! 383: frstor(&thread->pcb->fpstate); // clears TS flag ! 384: } ! 385: ! 386: #if FP_EMUL ! 387: if (cpu_config.fpu_type == FPU_EMUL) ! 388: map_data(sel_to_gdt_entry(FPSTATE_SEL), ! 389: (vm_offset_t) &thread->pcb->fpstate ! 390: + KERNEL_LINEAR_BASE, ! 391: (vm_size_t) sizeof (thread->pcb->fpstate), ! 392: KERN_PRIV, FALSE); ! 393: #endif ! 394: #if PC_SUPPORT ! 395: } ! 396: #endif ! 397: } ! 398: ! 399: /* ! 400: * Restore the floating point context ! 401: * of the current thread, saving the ! 402: * current context if necessary. ! 403: */ ! 404: ! 405: static ! 406: void ! 407: fp_switch(void) ! 408: { ! 409: thread_t thread = current_thread(); ! 410: ! 411: if (thread == fp_thread) { ! 412: #if PC_SUPPORT ! 413: PCshared_t shared = threadPCShared(thread); ! 414: ! 415: if (shared) { ! 416: PCcontext_t context = currentContext(shared); ! 417: ! 418: if (context->running) { ! 419: if (!shared->fpuOwned) { ! 420: if (cpu_config.fpu_type == FPU_HDW) ! 421: fnsave(&thread->pcb->fpstate); // clears TS flag ! 422: ! 423: thread->pcb->fpvalid = TRUE; ! 424: ! 425: if (shared->fpuStateValid) { ! 426: if (cpu_config.fpu_type == FPU_HDW) ! 427: frstor(&shared->fpuState); // clears TS flag ! 428: ! 429: shared->fpuStateValid = FALSE; ! 430: } ! 431: else { ! 432: fp_init_default(&shared->fpuState); ! 433: ! 434: if (cpu_config.fpu_type == FPU_HDW) ! 435: frstor(&shared->fpuState); // clears TS flag ! 436: } ! 437: ! 438: #if FP_EMUL ! 439: if (cpu_config.fpu_type == FPU_EMUL) ! 440: map_data(sel_to_gdt_entry(FPSTATE_SEL), ! 441: (vm_offset_t) &shared->fpuState ! 442: + KERNEL_LINEAR_BASE, ! 443: (vm_size_t) sizeof (shared->fpuState), ! 444: KERN_PRIV, FALSE); ! 445: #endif ! 446: ! 447: shared->fpuOwned = TRUE; ! 448: } ! 449: } ! 450: else { ! 451: if (shared->fpuOwned) { ! 452: if (cpu_config.fpu_type == FPU_HDW) ! 453: fnsave(&shared->fpuState); // clears TS flag ! 454: ! 455: shared->fpuStateValid = TRUE; ! 456: ! 457: if (thread->pcb->fpvalid) { ! 458: if (cpu_config.fpu_type == FPU_HDW) ! 459: frstor(&thread->pcb->fpstate);// clears TS flag ! 460: ! 461: thread->pcb->fpvalid = FALSE; ! 462: } ! 463: else { ! 464: fp_init(&thread->pcb->fpstate); ! 465: ! 466: if (cpu_config.fpu_type == FPU_HDW) ! 467: frstor(&thread->pcb->fpstate);// clears TS flag ! 468: } ! 469: ! 470: #if FP_EMUL ! 471: if (cpu_config.fpu_type == FPU_EMUL) ! 472: map_data(sel_to_gdt_entry(FPSTATE_SEL), ! 473: (vm_offset_t) &thread->pcb->fpstate ! 474: + KERNEL_LINEAR_BASE, ! 475: (vm_size_t) ! 476: sizeof (thread->pcb->fpstate), ! 477: KERN_PRIV, FALSE); ! 478: #endif ! 479: ! 480: shared->fpuOwned = FALSE; ! 481: } ! 482: } ! 483: } ! 484: #endif ! 485: } ! 486: else { ! 487: fp_save(); fp_thread = thread; fp_restore(); ! 488: } ! 489: ! 490: clts(); // make sure that the TS flag is cleared ! 491: } ! 492: ! 493: /* ! 494: * Mark the FPU as currently ! 495: * unowned. ! 496: */ ! 497: ! 498: static inline ! 499: void ! 500: fp_unowned(void) ! 501: { ! 502: fp_thread = THREAD_NULL; ! 503: setts(); ! 504: } ! 505: ! 506: /* ! 507: * Mark the FPU unowned if the ! 508: * thread currently owns it. The ! 509: * context is discarded. ! 510: */ ! 511: ! 512: void ! 513: fp_terminate( ! 514: thread_t thread ! 515: ) ! 516: { ! 517: if (thread == fp_thread) ! 518: fp_unowned(); ! 519: } ! 520: ! 521: /* ! 522: * Update the saved floating point ! 523: * context of the thread if necessary. ! 524: * Perform a software FINIT if the ! 525: * thread has not performed any floating ! 526: * point operations yet. ! 527: */ ! 528: ! 529: void ! 530: fp_synch( ! 531: thread_t thread ! 532: ) ! 533: { ! 534: if (thread == fp_thread) ! 535: fp_save(); ! 536: else { ! 537: if (!thread->pcb->fpvalid) ! 538: fp_init(&thread->pcb->fpstate); ! 539: } ! 540: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.