Annotation of XNU/osfmk/i386/fpu.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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