[BACK]Return to fpu.c CVS log [TXT][DIR] Up to [local] / sys / arch / amd64 / amd64

Annotation of sys/arch/amd64/amd64/fpu.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: fpu.c,v 1.12 2006/11/29 12:24:17 miod Exp $   */
        !             2: /*     $NetBSD: fpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $     */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1994, 1995, 1998 Charles M. Hannum.  All rights reserved.
        !             6:  * Copyright (c) 1990 William Jolitz.
        !             7:  * Copyright (c) 1991 The Regents of the University of California.
        !             8:  * All rights reserved.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. Neither the name of the University nor the names of its contributors
        !            19:  *    may be used to endorse or promote products derived from this software
        !            20:  *    without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            32:  * SUCH DAMAGE.
        !            33:  *
        !            34:  *     @(#)npx.c       7.2 (Berkeley) 5/12/91
        !            35:  */
        !            36:
        !            37: /*
        !            38:  * XXXfvdl update copyright notice. this started out as a stripped isa/npx.c
        !            39:  */
        !            40:
        !            41: #include <sys/param.h>
        !            42: #include <sys/systm.h>
        !            43: #include <sys/conf.h>
        !            44: #include <sys/file.h>
        !            45: #include <sys/proc.h>
        !            46: #include <sys/user.h>
        !            47: #include <sys/ioctl.h>
        !            48: #include <sys/device.h>
        !            49: #include <sys/vmmeter.h>
        !            50: #include <sys/signalvar.h>
        !            51:
        !            52: #include <uvm/uvm_extern.h>
        !            53:
        !            54: #include <machine/bus.h>
        !            55: #include <machine/cpu.h>
        !            56: #include <machine/intr.h>
        !            57: #include <machine/cpufunc.h>
        !            58: #include <machine/pcb.h>
        !            59: #include <machine/trap.h>
        !            60: #include <machine/specialreg.h>
        !            61: #include <machine/fpu.h>
        !            62:
        !            63: #include <dev/isa/isareg.h>
        !            64: #include <dev/isa/isavar.h>
        !            65:
        !            66: /*
        !            67:  * We do lazy initialization and switching using the TS bit in cr0 and the
        !            68:  * MDP_USEDFPU bit in mdproc.
        !            69:  *
        !            70:  * DNA exceptions are handled like this:
        !            71:  *
        !            72:  * 1) If there is no FPU, return and go to the emulator.
        !            73:  * 2) If someone else has used the FPU, save its state into that process' PCB.
        !            74:  * 3a) If MDP_USEDFPU is not set, set it and initialize the FPU.
        !            75:  * 3b) Otherwise, reload the process' previous FPU state.
        !            76:  *
        !            77:  * When a process is created or exec()s, its saved cr0 image has the TS bit
        !            78:  * set and the MDP_USEDFPU bit clear.  The MDP_USEDFPU bit is set when the
        !            79:  * process first gets a DNA and the FPU is initialized.  The TS bit is turned
        !            80:  * off when the FPU is used, and turned on again later when the process' FPU
        !            81:  * state is saved.
        !            82:  */
        !            83:
        !            84: #define        fninit()                __asm("fninit")
        !            85: #define fwait()                        __asm("fwait")
        !            86: #define fnclex()               __asm("fnclex")
        !            87: #define        fxsave(addr)            __asm("fxsave %0" : "=m" (*addr))
        !            88: #define        fxrstor(addr)           __asm("fxrstor %0" : : "m" (*addr))
        !            89: #define        ldmxcsr(addr)           __asm("ldmxcsr %0" : : "m" (*addr))
        !            90: #define fldcw(addr)            __asm("fldcw %0" : : "m" (*addr))
        !            91: #define        clts()                  __asm("clts")
        !            92: #define        stts()                  lcr0(rcr0() | CR0_TS)
        !            93:
        !            94: void fpudna(struct cpu_info *);
        !            95: static int x86fpflags_to_siginfo(u_int32_t);
        !            96:
        !            97: /*
        !            98:  * Init the FPU.
        !            99:  */
        !           100: void
        !           101: fpuinit(struct cpu_info *ci)
        !           102: {
        !           103:        lcr0(rcr0() & ~(CR0_EM|CR0_TS));
        !           104:        fninit();
        !           105:        lcr0(rcr0() | (CR0_TS));
        !           106: }
        !           107:
        !           108: /*
        !           109:  * Record the FPU state and reinitialize it all except for the control word.
        !           110:  * Then generate a SIGFPE.
        !           111:  *
        !           112:  * Reinitializing the state allows naive SIGFPE handlers to longjmp without
        !           113:  * doing any fixups.
        !           114:  */
        !           115:
        !           116: void
        !           117: fputrap(struct trapframe *frame)
        !           118: {
        !           119:        struct proc *p = curcpu()->ci_fpcurproc;
        !           120:        struct savefpu *sfp = &p->p_addr->u_pcb.pcb_savefpu;
        !           121:        u_int32_t statbits;
        !           122:        u_int16_t cw;
        !           123:        int code;
        !           124:        union sigval sv;
        !           125:
        !           126: #ifdef DIAGNOSTIC
        !           127:        /*
        !           128:         * At this point, fpcurproc should be curproc.  If it wasn't,
        !           129:         * the TS bit should be set, and we should have gotten a DNA exception.
        !           130:         */
        !           131:        if (p != curproc)
        !           132:                panic("fputrap: wrong proc");
        !           133: #endif
        !           134:
        !           135:        fxsave(sfp);
        !           136:        if (frame->tf_trapno == T_XMM) {
        !           137:                statbits = sfp->fp_fxsave.fx_mxcsr;
        !           138:        } else {
        !           139:                fninit();
        !           140:                fwait();
        !           141:                cw = sfp->fp_fxsave.fx_fcw;
        !           142:                fldcw(&cw);
        !           143:                fwait();
        !           144:                statbits = sfp->fp_fxsave.fx_fsw;
        !           145:        }
        !           146:        sfp->fp_ex_tw = sfp->fp_fxsave.fx_ftw;
        !           147:        sfp->fp_ex_sw = sfp->fp_fxsave.fx_fsw;
        !           148:        code = x86fpflags_to_siginfo (statbits);
        !           149:        sv.sival_ptr = (void *)frame->tf_rip;   /* XXX - ? */
        !           150:        KERNEL_PROC_LOCK(p);
        !           151:        trapsignal(p, SIGFPE, frame->tf_err, code, sv);
        !           152:        KERNEL_PROC_UNLOCK(p);
        !           153: }
        !           154:
        !           155: static int
        !           156: x86fpflags_to_siginfo(u_int32_t flags)
        !           157: {
        !           158:         int i;
        !           159:         static int x86fp_siginfo_table[] = {
        !           160:                 FPE_FLTINV, /* bit 0 - invalid operation */
        !           161:                 FPE_FLTRES, /* bit 1 - denormal operand */
        !           162:                 FPE_FLTDIV, /* bit 2 - divide by zero   */
        !           163:                 FPE_FLTOVF, /* bit 3 - fp overflow      */
        !           164:                 FPE_FLTUND, /* bit 4 - fp underflow     */
        !           165:                 FPE_FLTRES, /* bit 5 - fp precision     */
        !           166:                 FPE_FLTINV, /* bit 6 - stack fault      */
        !           167:         };
        !           168:
        !           169:         for (i=0;i < sizeof(x86fp_siginfo_table)/sizeof(int); i++) {
        !           170:                 if (flags & (1 << i))
        !           171:                         return (x86fp_siginfo_table[i]);
        !           172:         }
        !           173:         /* punt if flags not set */
        !           174:         return (FPE_FLTINV);
        !           175: }
        !           176:
        !           177: /*
        !           178:  * Implement device not available (DNA) exception
        !           179:  *
        !           180:  * If we were the last process to use the FPU, we can simply return.
        !           181:  * Otherwise, we save the previous state, if necessary, and restore our last
        !           182:  * saved state.
        !           183:  */
        !           184: void
        !           185: fpudna(struct cpu_info *ci)
        !           186: {
        !           187:        struct proc *p;
        !           188:        int s;
        !           189:
        !           190:        if (ci->ci_fpsaving) {
        !           191:                printf("recursive fpu trap; cr0=%x\n", rcr0());
        !           192:                return;
        !           193:        }
        !           194:
        !           195:        s = splipi();
        !           196:
        !           197: #ifdef MULTIPROCESSOR
        !           198:        p = ci->ci_curproc;
        !           199: #else
        !           200:        p = curproc;
        !           201: #endif
        !           202:
        !           203:        /*
        !           204:         * Initialize the FPU state to clear any exceptions.  If someone else
        !           205:         * was using the FPU, save their state.
        !           206:         */
        !           207:        if (ci->ci_fpcurproc != NULL && ci->ci_fpcurproc != p) {
        !           208:                fpusave_cpu(ci, 1);
        !           209:                uvmexp.fpswtch++;
        !           210:        } else {
        !           211:                clts();
        !           212:                fninit();
        !           213:                fwait();
        !           214:                stts();
        !           215:        }
        !           216:        splx(s);
        !           217:
        !           218:        if (p == NULL) {
        !           219:                clts();
        !           220:                return;
        !           221:        }
        !           222:
        !           223:        KDASSERT(ci->ci_fpcurproc == NULL);
        !           224: #ifndef MULTIPROCESSOR
        !           225:        KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL);
        !           226: #else
        !           227:        if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
        !           228:                fpusave_proc(p, 1);
        !           229: #endif
        !           230:
        !           231:        p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS;
        !           232:        clts();
        !           233:
        !           234:        s = splipi();
        !           235:        ci->ci_fpcurproc = p;
        !           236:        p->p_addr->u_pcb.pcb_fpcpu = ci;
        !           237:        splx(s);
        !           238:
        !           239:        if ((p->p_md.md_flags & MDP_USEDFPU) == 0) {
        !           240:                fldcw(&p->p_addr->u_pcb.pcb_savefpu.fp_fxsave.fx_fcw);
        !           241:                ldmxcsr(&p->p_addr->u_pcb.pcb_savefpu.fp_fxsave.fx_mxcsr);
        !           242:                p->p_md.md_flags |= MDP_USEDFPU;
        !           243:        } else {
        !           244:                static double   zero = 0.0;
        !           245:
        !           246:                /*
        !           247:                 * amd fpu does not restore fip, fdp, fop on fxrstor
        !           248:                 * thus leaking other process's execution history.
        !           249:                 */
        !           250:                fnclex();
        !           251:                __asm __volatile("ffree %%st(7)\n\tfld %0" : : "m" (zero));
        !           252:                fxrstor(&p->p_addr->u_pcb.pcb_savefpu);
        !           253:        }
        !           254: }
        !           255:
        !           256:
        !           257: void
        !           258: fpusave_cpu(struct cpu_info *ci, int save)
        !           259: {
        !           260:        struct proc *p;
        !           261:        int s;
        !           262:
        !           263:        KDASSERT(ci == curcpu());
        !           264:
        !           265:        p = ci->ci_fpcurproc;
        !           266:        if (p == NULL)
        !           267:                return;
        !           268:
        !           269:        if (save) {
        !           270: #ifdef DIAGNOSTIC
        !           271:                if (ci->ci_fpsaving != 0)
        !           272:                        panic("fpusave_cpu: recursive save!");
        !           273: #endif
        !           274:                 /*
        !           275:                  * Set ci->ci_fpsaving, so that any pending exception will be
        !           276:                  * thrown away.  (It will be caught again if/when the FPU
        !           277:                  * state is restored.)
        !           278:                  */
        !           279:                clts();
        !           280:                ci->ci_fpsaving = 1;
        !           281:                fxsave(&p->p_addr->u_pcb.pcb_savefpu);
        !           282:                ci->ci_fpsaving = 0;
        !           283:        }
        !           284:
        !           285:        stts();
        !           286:        p->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
        !           287:
        !           288:        s = splipi();
        !           289:        p->p_addr->u_pcb.pcb_fpcpu = NULL;
        !           290:        ci->ci_fpcurproc = NULL;
        !           291:        splx(s);
        !           292: }
        !           293:
        !           294: /*
        !           295:  * Save p's FPU state, which may be on this processor or another processor.
        !           296:  */
        !           297: void
        !           298: fpusave_proc(struct proc *p, int save)
        !           299: {
        !           300:        struct cpu_info *ci = curcpu();
        !           301:        struct cpu_info *oci;
        !           302:
        !           303:        KDASSERT(p->p_addr != NULL);
        !           304:
        !           305:        oci = p->p_addr->u_pcb.pcb_fpcpu;
        !           306:        if (oci == NULL)
        !           307:                return;
        !           308:
        !           309: #if defined(MULTIPROCESSOR)
        !           310:        if (oci == ci) {
        !           311:                int s = splipi();
        !           312:                fpusave_cpu(ci, save);
        !           313:                splx(s);
        !           314:        } else {
        !           315: #ifdef DIAGNOSTIC
        !           316:                int spincount;
        !           317: #endif
        !           318:
        !           319:                x86_send_ipi(oci,
        !           320:                    save ? X86_IPI_SYNCH_FPU : X86_IPI_FLUSH_FPU);
        !           321:
        !           322: #ifdef DIAGNOSTIC
        !           323:                spincount = 0;
        !           324: #endif
        !           325:                while (p->p_addr->u_pcb.pcb_fpcpu != NULL)
        !           326: #ifdef DIAGNOSTIC
        !           327:                {
        !           328:                        spincount++;
        !           329:                        if (spincount > 10000000) {
        !           330:                                panic("fp_save ipi didn't");
        !           331:                        }
        !           332:                }
        !           333: #else
        !           334:                __splbarrier();         /* XXX replace by generic barrier */
        !           335:                ;
        !           336: #endif
        !           337:        }
        !           338: #else
        !           339:        KASSERT(ci->ci_fpcurproc == p);
        !           340:        fpusave_cpu(ci, save);
        !           341: #endif
        !           342: }

CVSweb