Annotation of XNU/osfmk/i386/fpu.c, revision 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.