Annotation of Net2/arch/i386/isa/npx.c, revision 1.1.1.5

1.1       root        1: /*-
                      2:  * Copyright (c) 1990 William Jolitz.
                      3:  * Copyright (c) 1991 The Regents of the University of California.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. All advertising materials mentioning features or use of this software
                     15:  *    must display the following acknowledgement:
                     16:  *     This product includes software developed by the University of
                     17:  *     California, Berkeley and its contributors.
                     18:  * 4. 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:  *
1.1.1.5 ! root       34:  *     from: @(#)npx.c 7.2 (Berkeley) 5/12/91
        !            35:  *     npx.c,v 1.7 1993/06/14 07:06:49 cgd Exp
1.1       root       36:  */
                     37: #include "npx.h"
                     38: #if NNPX > 0
                     39: 
                     40: #include "param.h"
                     41: #include "systm.h"
                     42: #include "conf.h"
                     43: #include "file.h"
                     44: #include "proc.h"
                     45: #include "machine/cpu.h"
                     46: #include "machine/pcb.h"
                     47: #include "machine/trap.h"
                     48: #include "ioctl.h"
1.1.1.5 ! root       49: #include "i386/isa/icu.h"
1.1       root       50: #include "machine/specialreg.h"
                     51: #include "i386/isa/isa_device.h"
1.1.1.5 ! root       52: #include "i386/isa/isa.h"
        !            53: 
1.1       root       54: /*
                     55:  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
                     56:  */
                     57: 
1.1.1.5 ! root       58: #ifdef __GNUC__
        !            59: 
        !            60: #define        disable_intr()          __asm("cli")
        !            61: #define        enable_intr()           __asm("sti")
        !            62: #define        fldcw(addr)             __asm("fldcw %0" : : "m" (*addr))
        !            63: #define        fnclex()                __asm("fnclex")
        !            64: #define        fninit()                __asm("fninit")
        !            65: #define        fnsave(addr)            __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
        !            66: #define        fnstcw(addr)            __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
        !            67: #define        fnstsw(addr)            __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
        !            68: #define        fp_divide_by_0()        __asm("fldz; fld1; fdiv %st,%st(1); fwait")
        !            69: #define        frstor(addr)            __asm("frstor %0" : : "m" (*addr))
        !            70: #define        fwait()                 __asm("fwait")
        !            71: #define        read_eflags()           ({u_long ef; \
        !            72:                                  __asm("pushf; popl %0" : "=a" (ef)); \
        !            73:                                  ef; })
        !            74: #define        start_emulating()       __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
        !            75:                                      : : "n" (CR0_TS) : "ax")
        !            76: #define        stop_emulating()        __asm("clts")
        !            77: #define        write_eflags(ef)        __asm("pushl %0; popf" : : "a" ((u_long) ef))
        !            78: 
        !            79: #else  /* not __GNUC__ */
        !            80: 
        !            81: void   disable_intr    __P((void));
        !            82: void   enable_intr     __P((void));
        !            83: void   fldcw           __P((caddr_t addr));
        !            84: void   fnclex          __P((void));
        !            85: void   fninit          __P((void));
        !            86: void   fnsave          __P((caddr_t addr));
        !            87: void   fnstcw          __P((caddr_t addr));
        !            88: void   fnstsw          __P((caddr_t addr));
        !            89: void   fp_divide_by_0  __P((void));
        !            90: void   frstor          __P((caddr_t addr));
        !            91: void   fwait           __P((void));
        !            92: u_long read_eflags     __P((void));
        !            93: void   start_emulating __P((void));
        !            94: void   stop_emulating  __P((void));
        !            95: void   write_eflags    __P((u_long ef));
        !            96: 
        !            97: #endif /* __GNUC__ */
        !            98: 
        !            99: typedef u_char bool_t;
        !           100: 
        !           101: extern struct gate_descriptor idt[];
        !           102: 
        !           103: int    npxdna          __P((void));
        !           104: void   npxexit         __P((struct proc *p));
        !           105: void   npxinit         __P((u_int control));
        !           106: void   npxintr         __P((struct intrframe frame));
        !           107: void   npxsave         __P((struct save87 *addr));
        !           108: static int     npxattach       __P((struct isa_device *dvp));
        !           109: static int     npxprobe        __P((struct isa_device *dvp));
        !           110: static int     npxprobe1       __P((struct isa_device *dvp));
        !           111: 
1.1       root      112: struct isa_driver npxdriver = {
                    113:        npxprobe, npxattach, "npx",
                    114: };
                    115: 
1.1.1.5 ! root      116: u_int  npx0mask;
        !           117: struct proc    *npxproc;
        !           118: 
        !           119: static bool_t                  npx_ex16;
        !           120: static bool_t                  npx_exists;
        !           121: static struct gate_descriptor  npx_idt_probeintr;
        !           122: static int                     npx_intrno;
        !           123: static volatile u_int          npx_intrs_while_probing;
        !           124: static bool_t                  npx_irq13;
        !           125: static volatile u_int          npx_traps_while_probing;
1.1       root      126: 
                    127: /*
1.1.1.5 ! root      128:  * Special interrupt handlers.  Someday intr0-intr15 will be used to count
        !           129:  * interrupts.  We'll still need a special exception 16 handler.  The busy
        !           130:  * latch stuff in probintr() can be moved to npxprobe().
1.1       root      131:  */
1.1.1.5 ! root      132: void probeintr(void);
        !           133: asm ( \
        !           134:        ".text;" \
        !           135:        "_probeintr:;" \
        !           136:        "ss;" \
        !           137:        "incl   _npx_intrs_while_probing;" \
        !           138:        "pushl  %eax;" \
        !           139:        "movb   $0x20,%al;"     /* EOI (asm in strings loses cpp features) */ \
        !           140:        "outb   %al,$0xa0;"     /* IO_ICU2 */ \
        !           141:        "outb   %al,$0x20;"     /* IO_ICU1 */ \
        !           142:        "movb   $0,%al;" \
        !           143:        "outb   %al,$0xf0;"     /* clear BUSY# latch */ \
        !           144:        "popl   %eax;" \
        !           145:        "iret" \
        !           146: );
        !           147: 
        !           148: void probetrap(void);
        !           149: asm
        !           150: ("
        !           151:        .text
        !           152: _probetrap:
        !           153:        ss
        !           154:        incl    _npx_traps_while_probing
        !           155:        fnclex
        !           156:        iret
        !           157: ");
        !           158: 
        !           159: /*
        !           160:  * Probe routine.  Initialize cr0 to give correct behaviour for [f]wait
        !           161:  * whether the device exists or not (XXX should be elsewhere).  Set flags
        !           162:  * to tell npxattach() what to do.  Modify device struct if npx doesn't
        !           163:  * need to use interrupts.  Return 1 if device exists.
        !           164:  */
        !           165: static int
1.1       root      166: npxprobe(dvp)
                    167:        struct isa_device *dvp;
1.1.1.5 ! root      168: {
        !           169:        int     result;
        !           170:        u_long  save_eflags;
        !           171:        u_char  save_icu1_mask;
        !           172:        u_char  save_icu2_mask;
        !           173:        struct  gate_descriptor save_idt_npxintr;
        !           174:        struct  gate_descriptor save_idt_npxtrap;
        !           175:        /*
        !           176:         * This routine is now just a wrapper for npxprobe1(), to install
        !           177:         * special npx interrupt and trap handlers, to enable npx interrupts
        !           178:         * and to disable other interrupts.  Someday isa_configure() will
        !           179:         * install suitable handlers and run with interrupts enabled so we
        !           180:         * won't need to do so much here.
        !           181:         */
        !           182:        npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
        !           183:        save_eflags = read_eflags();
        !           184:        disable_intr();
        !           185:        save_icu1_mask = inb(IO_ICU1 + 1);
        !           186:        save_icu2_mask = inb(IO_ICU2 + 1);
        !           187:        save_idt_npxintr = idt[npx_intrno];
        !           188:        save_idt_npxtrap = idt[16];
        !           189:        outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
        !           190:        outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
        !           191:        setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
        !           192:        setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
        !           193:        npx_idt_probeintr = idt[npx_intrno];
        !           194:        enable_intr();
        !           195:        result = npxprobe1(dvp);
        !           196:        disable_intr();
        !           197:        outb(IO_ICU1 + 1, save_icu1_mask);
        !           198:        outb(IO_ICU2 + 1, save_icu2_mask);
        !           199:        idt[npx_intrno] = save_idt_npxintr;
        !           200:        idt[16] = save_idt_npxtrap;
        !           201:        write_eflags(save_eflags);
        !           202:        return (result);
        !           203: }
1.1       root      204: 
1.1.1.5 ! root      205: static int
        !           206: npxprobe1(dvp)
        !           207:        struct isa_device *dvp;
        !           208: {
        !           209:        int control;
        !           210:        int status;
1.1       root      211: #ifdef lint
                    212:        npxintr();
                    213: #endif
1.1.1.5 ! root      214:        /*
        !           215:         * Partially reset the coprocessor, if any.  Some BIOS's don't reset
        !           216:         * it after a warm boot.
        !           217:         */
        !           218:        outb(0xf1, 0);          /* full reset on some systems, NOP on others */
        !           219:        outb(0xf0, 0);          /* clear BUSY# latch */
        !           220:        /*
        !           221:         * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
        !           222:         * instructions.  We must set the CR0_MP bit and use the CR0_TS
        !           223:         * bit to control the trap, because setting the CR0_EM bit does
        !           224:         * not cause WAIT instructions to trap.  It's important to trap
        !           225:         * WAIT instructions - otherwise the "wait" variants of no-wait
        !           226:         * control instructions would degenerate to the "no-wait" variants
        !           227:         * after FP context switches but work correctly otherwise.  It's
        !           228:         * particularly important to trap WAITs when there is no NPX -
        !           229:         * otherwise the "wait" variants would always degenerate.
        !           230:         *
        !           231:         * Try setting CR0_NE to get correct error reporting on 486DX's.
        !           232:         * Setting it should fail or do nothing on lesser processors.
        !           233:         */
        !           234:        load_cr0(rcr0() | CR0_MP | CR0_NE);
        !           235:        /*
        !           236:         * But don't trap while we're probing.
        !           237:         */
        !           238:        stop_emulating();
        !           239:        /*
        !           240:         * Finish resetting the coprocessor, if any.  If there is an error
        !           241:         * pending, then we may get a bogus IRQ13, but probeintr() will handle
        !           242:         * it OK.  Bogus halts have never been observed, but we enabled
        !           243:         * IRQ13 and cleared the BUSY# latch early to handle them anyway.
        !           244:         */
        !           245:        fninit();
        !           246:        DELAY(1000);            /* wait for any IRQ13 (fwait might hang) */
        !           247: #ifdef DIAGNOSTIC
        !           248:        if (npx_intrs_while_probing != 0)
        !           249:                printf("fninit caused %u bogus npx interrupt(s)\n",
        !           250:                       npx_intrs_while_probing);
        !           251:        if (npx_traps_while_probing != 0)
        !           252:                printf("fninit caused %u bogus npx trap(s)\n",
        !           253:                       npx_traps_while_probing);
        !           254: #endif
        !           255:        /*
        !           256:         * Check for a status of mostly zero.
        !           257:         */
        !           258:        status = 0x5a5a;
        !           259:        fnstsw(&status);
        !           260:        if ((status & 0xb8ff) == 0) {
        !           261:                /*
        !           262:                 * Good, now check for a proper control word.
        !           263:                 */
        !           264:                control = 0x5a5a;       
        !           265:                fnstcw(&control);
        !           266:                if ((control & 0x1f3f) == 0x033f) {
        !           267:                        npx_exists = 1;
        !           268:                        /*
        !           269:                         * We have an npx, now divide by 0 to see if exception
        !           270:                         * 16 works.
        !           271:                         */
        !           272:                        control &= ~(1 << 2);   /* enable divide by 0 trap */
        !           273:                        fldcw(&control);
        !           274:                        npx_traps_while_probing = npx_intrs_while_probing = 0;
        !           275:                        fp_divide_by_0();
        !           276:                        if (npx_traps_while_probing != 0) {
        !           277:                                /*
        !           278:                                 * Good, exception 16 works.
        !           279:                                 */
        !           280:                                npx_ex16 = 1;
        !           281:                                dvp->id_irq = 0;        /* zap the interrupt */
        !           282:                                return 16;
        !           283:                        }
        !           284:                        if (npx_intrs_while_probing != 0) {
        !           285:                                /*
        !           286:                                 * Bad, we are stuck with IRQ13.
        !           287:                                 */
        !           288:                                npx_irq13 = 1;
        !           289:                                npx0mask = dvp->id_irq; /* npxattach too late */
        !           290:                                return 16;
        !           291:                        }
        !           292:                        /*
        !           293:                         * Worse, even IRQ13 is broken.  Use emulator.
        !           294:                         */
1.1       root      295:                }
                    296:        }
1.1.1.5 ! root      297:        /*
        !           298:         * Probe failed, but we want to get to npxattach to initialize the
        !           299:         * emulator and say that it has been installed.  XXX handle devices
        !           300:         * that aren't really devices better.
        !           301:         */
        !           302:        dvp->id_irq = 0;
        !           303:        return 16;
1.1       root      304: }
                    305: 
                    306: /*
                    307:  * Attach routine - announce which it is, and wire into system
                    308:  */
1.1.1.5 ! root      309: int
1.1       root      310: npxattach(dvp)
                    311:        struct isa_device *dvp;
                    312: {
1.1.1.5 ! root      313:        if (npx_ex16)
        !           314:                printf("npx%d: using exception 16\n", dvp->id_unit);
        !           315:        else if (npx_irq13)
        !           316:                ;
        !           317:        else {
        !           318: #ifdef MATH_EMULATE
        !           319:                if (npx_exists)
        !           320:                        printf("npx%d: error reporting broken, using emulator\n",
        !           321:                                dvp->id_unit);
        !           322:                else
        !           323:                        printf("npx%d: emulator\n", dvp->id_unit);
1.1.1.4   root      324: #else
1.1.1.5 ! root      325:                panic("npxattach: no math emulator in kernel!");
1.1.1.4   root      326: #endif
1.1.1.3   root      327:        }
1.1.1.5 ! root      328:        npxinit(__INITIAL_NPXCW__);
        !           329:        return (1);
1.1       root      330: }
                    331: 
                    332: /*
1.1.1.5 ! root      333:  * Initialize floating point unit.
1.1       root      334:  */
1.1.1.5 ! root      335: void
        !           336: npxinit(control)
        !           337:        u_int control;
        !           338: {
        !           339:        struct save87 dummy;
1.1       root      340: 
1.1.1.5 ! root      341:        if (!npx_exists)
        !           342:                return;
        !           343:        /*
        !           344:         * fninit has the same h/w bugs as fnsave.  Use the detoxified
        !           345:         * fnsave to throw away any junk in the fpu.  fnsave initializes
        !           346:         * the fpu and sets npxproc = NULL as important side effects.
        !           347:         */
        !           348:        npxsave(&dummy);
        !           349:        stop_emulating();
        !           350:        fldcw(&control);
        !           351:        if (curpcb != NULL)
        !           352:                fnsave(&curpcb->pcb_savefpu);
        !           353:        start_emulating();
1.1       root      354: }
                    355: 
                    356: /*
1.1.1.5 ! root      357:  * Free coprocessor (if we have it).
1.1       root      358:  */
1.1.1.5 ! root      359: void
        !           360: npxexit(p)
        !           361:        struct proc *p;
        !           362: {
        !           363:        if (p == npxproc) {
        !           364:                start_emulating();
        !           365:                npxproc = NULL;
        !           366:        }
1.1       root      367: }
                    368: 
                    369: /*
1.1.1.5 ! root      370:  * Record the FPU state and reinitialize it all except for the control word.
        !           371:  * Then generate a SIGFPE.
        !           372:  *
        !           373:  * Reinitializing the state allows naive SIGFPE handlers to longjmp without
        !           374:  * doing any fixups.
        !           375:  *
        !           376:  * XXX there is currently no way to pass the full error state to signal
        !           377:  * handlers, and if this is a nested interrupt there is no way to pass even
        !           378:  * a status code!  So there is no way to have a non-naive SIGFPE handler.  At
        !           379:  * best a handler could do an fninit followed by an fldcw of a static value.
        !           380:  * fnclex would be of little use because it would leave junk on the FPU stack.
        !           381:  * Returning from the handler would be even less safe than usual because
        !           382:  * IRQ13 exception handling makes exceptions even less precise than usual.
1.1       root      383:  */
1.1.1.5 ! root      384: void
        !           385: npxintr(frame)
        !           386:        struct intrframe frame;
        !           387: {
1.1.1.3   root      388:        int code;
1.1       root      389: 
1.1.1.5 ! root      390:        if (npxproc == NULL || !npx_exists) {
        !           391:                /* XXX no %p in stand/printf.c.  Cast to quiet gcc -Wall. */
        !           392:                printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
        !           393:                       (u_long) npxproc, (u_long) curproc, npx_exists);
        !           394:                panic("npxintr from nowhere");
        !           395:        }
        !           396:        if (npxproc != curproc) {
        !           397:                printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
        !           398:                       (u_long) npxproc, (u_long) curproc, npx_exists);
        !           399:                panic("npxintr from non-current process");
        !           400:        }
        !           401:        /*
        !           402:         * Save state.  This does an implied fninit.  It had better not halt
        !           403:         * the cpu or we'll hang.
        !           404:         */
        !           405:        outb(0xf0, 0);
        !           406:        fnsave(&curpcb->pcb_savefpu);
        !           407:        fwait();
        !           408:        /*
        !           409:         * Restore control word (was clobbered by fnsave).
        !           410:         */
        !           411:        fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
        !           412:        fwait();
        !           413:        /*
        !           414:         * Remember the exception status word and tag word.  The current
        !           415:         * (almost fninit'ed) fpu state is in the fpu and the exception
        !           416:         * state just saved will soon be junk.  However, the implied fninit
        !           417:         * doesn't change the error pointers or register contents, and we
        !           418:         * preserved the control word and will copy the status and tag
        !           419:         * words, so the complete exception state can be recovered.
        !           420:         */
        !           421:        curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
        !           422:        curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
        !           423: 
        !           424:        /*
        !           425:         * Pass exception to process.
        !           426:         */
        !           427:        if (ISPL(frame.if_cs) == SEL_UPL) {
        !           428:                /*
        !           429:                 * Interrupt is essentially a trap, so we can afford to call
        !           430:                 * the SIGFPE handler (if any) as soon as the interrupt
        !           431:                 * returns.
        !           432:                 *
        !           433:                 * XXX little or nothing is gained from this, and plenty is
        !           434:                 * lost - the interrupt frame has to contain the trap frame
        !           435:                 * (this is otherwise only necessary for the rescheduling trap
        !           436:                 * in doreti, and the frame for that could easily be set up
        !           437:                 * just before it is used).
        !           438:                 */
        !           439:                curproc->p_regs = (int *)&frame.if_es;
        !           440:                curpcb->pcb_flags |= FM_TRAP;   /* used by sendsig */
1.1       root      441: #ifdef notyet
1.1.1.5 ! root      442:                /*
        !           443:                 * Encode the appropriate code for detailed information on
        !           444:                 * this exception.
        !           445:                 */
        !           446:                code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
1.1.1.3   root      447: #else
1.1.1.5 ! root      448:                code = 0;       /* XXX */
1.1       root      449: #endif
1.1.1.3   root      450:                trapsignal(curproc, SIGFPE, code);
1.1.1.5 ! root      451:                curpcb->pcb_flags &= ~FM_TRAP;
1.1.1.3   root      452:        } else {
1.1.1.5 ! root      453:                /*
        !           454:                 * Nested interrupt.  These losers occur when:
        !           455:                 *      o an IRQ13 is bogusly generated at a bogus time, e.g.:
        !           456:                 *              o immediately after an fnsave or frstor of an
        !           457:                 *                error state.
        !           458:                 *              o a couple of 386 instructions after
        !           459:                 *                "fstpl _memvar" causes a stack overflow.
        !           460:                 *        These are especially nasty when combined with a
        !           461:                 *        trace trap.
        !           462:                 *      o an IRQ13 occurs at the same time as another higher-
        !           463:                 *        priority interrupt.
        !           464:                 *
        !           465:                 * Treat them like a true async interrupt.
        !           466:                 */
1.1.1.3   root      467:                psignal(npxproc, SIGFPE);
                    468:        }
1.1       root      469: }
                    470: 
                    471: /*
                    472:  * Implement device not available (DNA) exception
1.1.1.5 ! root      473:  *
        !           474:  * It would be better to switch FP context here (only).  This would require
        !           475:  * saving the state in the proc table instead of in the pcb.
1.1       root      476:  */
1.1.1.5 ! root      477: int
        !           478: npxdna()
        !           479: {
        !           480:        if (!npx_exists)
        !           481:                return (0);
        !           482:        if (npxproc != NULL) {
        !           483:                printf("npxdna: npxproc = %lx, curproc = %lx\n",
        !           484:                       (u_long) npxproc, (u_long) curproc);
        !           485:                panic("npxdna");
        !           486:        }
        !           487:        stop_emulating();
        !           488:        /*
        !           489:         * Record new context early in case frstor causes an IRQ13.
        !           490:         */
1.1.1.2   root      491:        npxproc = curproc;
1.1.1.5 ! root      492:        /*
        !           493:         * The following frstor may cause an IRQ13 when the state being
        !           494:         * restored has a pending error.  The error will appear to have been
        !           495:         * triggered by the current (npx) user instruction even when that
        !           496:         * instruction is a no-wait instruction that should not trigger an
        !           497:         * error (e.g., fnclex).  On at least one 486 system all of the
        !           498:         * no-wait instructions are broken the same as frstor, so our
        !           499:         * treatment does not amplify the breakage.  On at least one
        !           500:         * 386/Cyrix 387 system, fnclex works correctly while frstor and
        !           501:         * fnsave are broken, so our treatment breaks fnclex if it is the
        !           502:         * first FPU instruction after a context switch.
        !           503:         */
        !           504:        frstor(&curpcb->pcb_savefpu);
        !           505: 
1.1.1.2   root      506:        return (1);
1.1       root      507: }
1.1.1.5 ! root      508: 
        !           509: /*
        !           510:  * Wrapper for fnsave instruction to handle h/w bugs.  If there is an error
        !           511:  * pending, then fnsave generates a bogus IRQ13 on some systems.  Force
        !           512:  * any IRQ13 to be handled immediately, and then ignore it.  This routine is
        !           513:  * often called at splhigh so it must not use many system services.  In
        !           514:  * particular, it's much easier to install a special handler than to
        !           515:  * guarantee that it's safe to use npxintr() and its supporting code.
        !           516:  */
        !           517: void
        !           518: npxsave(addr)
        !           519:        struct save87 *addr;
        !           520: {
        !           521:        u_char  icu1_mask;
        !           522:        u_char  icu2_mask;
        !           523:        u_char  old_icu1_mask;
        !           524:        u_char  old_icu2_mask;
        !           525:        struct gate_descriptor  save_idt_npxintr;
        !           526: 
        !           527:        disable_intr();
        !           528:        old_icu1_mask = inb(IO_ICU1 + 1);
        !           529:        old_icu2_mask = inb(IO_ICU2 + 1);
        !           530:        save_idt_npxintr = idt[npx_intrno];
        !           531:        outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask));
        !           532:        outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8));
        !           533:        idt[npx_intrno] = npx_idt_probeintr;
        !           534:        enable_intr();
        !           535:        stop_emulating();
        !           536:        fnsave(addr);
        !           537:        fwait();
        !           538:        start_emulating();
        !           539:        npxproc = NULL;
        !           540:        disable_intr();
        !           541:        icu1_mask = inb(IO_ICU1 + 1);   /* masks may have changed */
        !           542:        icu2_mask = inb(IO_ICU2 + 1);
        !           543:        outb(IO_ICU1 + 1,
        !           544:             (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask));
        !           545:        outb(IO_ICU2 + 1,
        !           546:             (icu2_mask & ~(npx0mask >> 8))
        !           547:             | (old_icu2_mask & (npx0mask >> 8)));
        !           548:        idt[npx_intrno] = save_idt_npxintr;
        !           549:        enable_intr();          /* back to usual state */
        !           550: }
        !           551: 
        !           552: #endif /* NNPX > 0 */

unix.superglobalmegacorp.com

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