Annotation of kernel/machdep/i386/fp_support.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.