The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/npx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  *
   34  *      from: @(#)npx.c 7.2 (Berkeley) 5/12/91
   35  * $FreeBSD: src/sys/i386/isa/npx.c,v 1.31.2.9 1999/09/05 08:13:15 peter Exp $
   36  */
   37 
   38 #include "npx.h"
   39 #if NNPX > 0
   40 
   41 #include "opt_cpu.h"
   42 #include "opt_math_emulate.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/conf.h>
   49 #include <sys/file.h>
   50 #include <sys/proc.h>
   51 #include <sys/ioctl.h>
   52 #ifdef NPX_DEBUG
   53 #include <sys/syslog.h>
   54 #endif
   55 #include <sys/signalvar.h>
   56 
   57 #include <machine/cpu.h>
   58 #include <machine/pcb.h>
   59 #include <machine/md_var.h>
   60 #include <machine/trap.h>
   61 #include <machine/clock.h>
   62 #include <machine/specialreg.h>
   63 
   64 #include <i386/isa/icu.h>
   65 #include <i386/isa/isa_device.h>
   66 #include <i386/isa/isa.h>
   67 
   68 /*
   69  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
   70  */
   71 
   72 /* Configuration flags. */
   73 #define NPX_DISABLE_I586_OPTIMIZED_BCOPY        (1 << 0)
   74 #define NPX_DISABLE_I586_OPTIMIZED_BZERO        (1 << 1)
   75 #define NPX_DISABLE_I586_OPTIMIZED_COPYIO       (1 << 2)
   76 
   77 /* XXX - should be in header file. */
   78 extern void (*bcopy_vector) __P((const void *from, void *to, size_t len));
   79 extern void (*ovbcopy_vector) __P((const void *from, void *to, size_t len));
   80 extern int (*copyin_vector) __P((const void *udaddr, void *kaddr, size_t len));
   81 extern int (*copyout_vector) __P((const void *kaddr, void *udaddr, size_t len));
   82 
   83 void    i586_bcopy __P((const void *from, void *to, size_t len));
   84 void    i586_bzero __P((void *buf, size_t len));
   85 int     i586_copyin __P((const void *udaddr, void *kaddr, size_t len));
   86 int     i586_copyout __P((const void *kaddr, void *udaddr, size_t len));
   87 
   88 #ifdef  __GNUC__
   89 
   90 #define fldcw(addr)             __asm("fldcw %0" : : "m" (*(addr)))
   91 #define fnclex()                __asm("fnclex")
   92 #define fninit()                __asm("fninit")
   93 #define fnop()                  __asm("fnop")
   94 #define fnsave(addr)            __asm("fnsave %0" : "=m" (*(addr)))
   95 #define fnstcw(addr)            __asm("fnstcw %0" : "=m" (*(addr)))
   96 #define fnstsw(addr)            __asm("fnstsw %0" : "=m" (*(addr)))
   97 #define fp_divide_by_0()        __asm("fldz; fld1; fdiv %st,%st(1); fnop")
   98 #define frstor(addr)            __asm("frstor %0" : : "m" (*(addr)))
   99 #define start_emulating()       __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
  100                                       : : "n" (CR0_TS) : "ax")
  101 #define stop_emulating()        __asm("clts")
  102 
  103 #else   /* not __GNUC__ */
  104 
  105 void    fldcw           __P((caddr_t addr));
  106 void    fnclex          __P((void));
  107 void    fninit          __P((void));
  108 void    fnop            __P((void));
  109 void    fnsave          __P((caddr_t addr));
  110 void    fnstcw          __P((caddr_t addr));
  111 void    fnstsw          __P((caddr_t addr));
  112 void    fp_divide_by_0  __P((void));
  113 void    frstor          __P((caddr_t addr));
  114 void    start_emulating __P((void));
  115 void    stop_emulating  __P((void));
  116 
  117 #endif  /* __GNUC__ */
  118 
  119 typedef u_char bool_t;
  120 
  121 static  int     npxattach       __P((struct isa_device *dvp));
  122 static  int     npxprobe        __P((struct isa_device *dvp));
  123 static  int     npxprobe1       __P((struct isa_device *dvp));
  124 
  125 struct  isa_driver npxdriver = {
  126         npxprobe, npxattach, "npx",
  127 };
  128 
  129 int     hw_float;               /* XXX currently just alias for npx_exists */
  130 
  131 SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
  132         CTLFLAG_RD, &hw_float, 0, 
  133         "Floatingpoint instructions executed in hardware");
  134 
  135 static u_int    npx0_imask = SWI_CLOCK_MASK;
  136 struct proc     *npxproc;
  137 
  138 static  bool_t                  npx_ex16;
  139 static  bool_t                  npx_exists;
  140 static  struct gate_descriptor  npx_idt_probeintr;
  141 static  int                     npx_intrno;
  142 static  volatile u_int          npx_intrs_while_probing;
  143 static  bool_t                  npx_irq13;
  144 static  volatile u_int          npx_traps_while_probing;
  145 
  146 /*
  147  * Special interrupt handlers.  Someday intr0-intr15 will be used to count
  148  * interrupts.  We'll still need a special exception 16 handler.  The busy
  149  * latch stuff in probeintr() can be moved to npxprobe().
  150  */
  151 inthand_t probeintr;
  152 __asm
  153 ("
  154         .text
  155 _probeintr:
  156         ss
  157         incl    _npx_intrs_while_probing
  158         pushl   %eax
  159         movb    $0x20,%al       # EOI (asm in strings loses cpp features)
  160         outb    %al,$0xa0       # IO_ICU2
  161         outb    %al,$0x20       # IO_ICU1
  162         movb    $0,%al
  163         outb    %al,$0xf0       # clear BUSY# latch
  164         popl    %eax
  165         iret
  166 ");
  167 
  168 inthand_t probetrap;
  169 __asm
  170 ("
  171         .text
  172 _probetrap:
  173         ss
  174         incl    _npx_traps_while_probing
  175         fnclex
  176         iret
  177 ");
  178 
  179 /*
  180  * Probe routine.  Initialize cr0 to give correct behaviour for [f]wait
  181  * whether the device exists or not (XXX should be elsewhere).  Set flags
  182  * to tell npxattach() what to do.  Modify device struct if npx doesn't
  183  * need to use interrupts.  Return 1 if device exists.
  184  */
  185 static int
  186 npxprobe(dvp)
  187         struct isa_device *dvp;
  188 {
  189         int     result;
  190         u_long  save_eflags;
  191         u_char  save_icu1_mask;
  192         u_char  save_icu2_mask;
  193         struct  gate_descriptor save_idt_npxintr;
  194         struct  gate_descriptor save_idt_npxtrap;
  195         /*
  196          * This routine is now just a wrapper for npxprobe1(), to install
  197          * special npx interrupt and trap handlers, to enable npx interrupts
  198          * and to disable other interrupts.  Someday isa_configure() will
  199          * install suitable handlers and run with interrupts enabled so we
  200          * won't need to do so much here.
  201          */
  202         npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
  203         save_eflags = read_eflags();
  204         disable_intr();
  205         save_icu1_mask = inb(IO_ICU1 + 1);
  206         save_icu2_mask = inb(IO_ICU2 + 1);
  207         save_idt_npxintr = idt[npx_intrno];
  208         save_idt_npxtrap = idt[16];
  209         outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
  210         outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
  211         setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
  212         setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
  213         npx_idt_probeintr = idt[npx_intrno];
  214         enable_intr();
  215         result = npxprobe1(dvp);
  216         disable_intr();
  217         outb(IO_ICU1 + 1, save_icu1_mask);
  218         outb(IO_ICU2 + 1, save_icu2_mask);
  219         idt[npx_intrno] = save_idt_npxintr;
  220         idt[16] = save_idt_npxtrap;
  221         write_eflags(save_eflags);
  222         return (result);
  223 }
  224 
  225 static int
  226 npxprobe1(dvp)
  227         struct isa_device *dvp;
  228 {
  229         u_short control;
  230         u_short status;
  231 
  232         /*
  233          * Partially reset the coprocessor, if any.  Some BIOS's don't reset
  234          * it after a warm boot.
  235          */
  236         outb(0xf1, 0);          /* full reset on some systems, NOP on others */
  237         outb(0xf0, 0);          /* clear BUSY# latch */
  238         /*
  239          * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
  240          * instructions.  We must set the CR0_MP bit and use the CR0_TS
  241          * bit to control the trap, because setting the CR0_EM bit does
  242          * not cause WAIT instructions to trap.  It's important to trap
  243          * WAIT instructions - otherwise the "wait" variants of no-wait
  244          * control instructions would degenerate to the "no-wait" variants
  245          * after FP context switches but work correctly otherwise.  It's
  246          * particularly important to trap WAITs when there is no NPX -
  247          * otherwise the "wait" variants would always degenerate.
  248          *
  249          * Try setting CR0_NE to get correct error reporting on 486DX's.
  250          * Setting it should fail or do nothing on lesser processors.
  251          */
  252         load_cr0(rcr0() | CR0_MP | CR0_NE);
  253         /*
  254          * But don't trap while we're probing.
  255          */
  256         stop_emulating();
  257         /*
  258          * Finish resetting the coprocessor, if any.  If there is an error
  259          * pending, then we may get a bogus IRQ13, but probeintr() will handle
  260          * it OK.  Bogus halts have never been observed, but we enabled
  261          * IRQ13 and cleared the BUSY# latch early to handle them anyway.
  262          */
  263         fninit();
  264         /*
  265          * Don't use fwait here because it might hang.
  266          * Don't use fnop here because it usually hangs if there is no FPU.
  267          */
  268         DELAY(1000);            /* wait for any IRQ13 */
  269 #ifdef DIAGNOSTIC
  270         if (npx_intrs_while_probing != 0)
  271                 printf("fninit caused %u bogus npx interrupt(s)\n",
  272                        npx_intrs_while_probing);
  273         if (npx_traps_while_probing != 0)
  274                 printf("fninit caused %u bogus npx trap(s)\n",
  275                        npx_traps_while_probing);
  276 #endif
  277         /*
  278          * Check for a status of mostly zero.
  279          */
  280         status = 0x5a5a;
  281         fnstsw(&status);
  282         if ((status & 0xb8ff) == 0) {
  283                 /*
  284                  * Good, now check for a proper control word.
  285                  */
  286                 control = 0x5a5a;
  287                 fnstcw(&control);
  288                 if ((control & 0x1f3f) == 0x033f) {
  289                         hw_float = npx_exists = 1;
  290                         /*
  291                          * We have an npx, now divide by 0 to see if exception
  292                          * 16 works.
  293                          */
  294                         control &= ~(1 << 2);   /* enable divide by 0 trap */
  295                         fldcw(&control);
  296                         npx_traps_while_probing = npx_intrs_while_probing = 0;
  297                         fp_divide_by_0();
  298                         if (npx_traps_while_probing != 0) {
  299                                 /*
  300                                  * Good, exception 16 works.
  301                                  */
  302                                 npx_ex16 = 1;
  303                                 dvp->id_irq = 0;        /* zap the interrupt */
  304                                 /*
  305                                  * special return value to flag that we do not
  306                                  * actually use any I/O registers
  307                                  */
  308                                 return (-1);
  309                         }
  310                         if (npx_intrs_while_probing != 0) {
  311                                 /*
  312                                  * Bad, we are stuck with IRQ13.
  313                                  */
  314                                 npx_irq13 = 1;
  315                                 /*
  316                                  * npxattach would be too late to set npx0_imask.
  317                                  */
  318                                 npx0_imask |= dvp->id_irq;
  319                                 return (IO_NPXSIZE);
  320                         }
  321                         /*
  322                          * Worse, even IRQ13 is broken.  Use emulator.
  323                          */
  324                 }
  325         }
  326         /*
  327          * Probe failed, but we want to get to npxattach to initialize the
  328          * emulator and say that it has been installed.  XXX handle devices
  329          * that aren't really devices better.
  330          */
  331         dvp->id_irq = 0;
  332         /*
  333          * special return value to flag that we do not
  334          * actually use any I/O registers
  335          */
  336         return (-1);
  337 }
  338 
  339 /*
  340  * Attach routine - announce which it is, and wire into system
  341  */
  342 int
  343 npxattach(dvp)
  344         struct isa_device *dvp;
  345 {
  346         /* The caller has printed "irq 13" for the npx_irq13 case. */
  347         if (!npx_irq13) {
  348                 printf("npx%d: ", dvp->id_unit);
  349                 if (npx_ex16)
  350                         printf("INT 16 interface\n");
  351 #if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
  352                 else if (npx_exists) {
  353                         printf("error reporting broken; using 387 emulator\n");
  354                         hw_float = npx_exists = 0;
  355                 } else
  356                         printf("387 emulator\n");
  357 #else
  358                 else
  359                         printf("no 387 emulator in kernel!\n");
  360 #endif
  361         }
  362         npxinit(__INITIAL_NPXCW__);
  363 
  364 #ifdef I586_CPU
  365         if (cpu_class == CPUCLASS_586 && npx_ex16) {
  366                 if (!(dvp->id_flags & NPX_DISABLE_I586_OPTIMIZED_BCOPY)) {
  367                         bcopy_vector = i586_bcopy;
  368                         ovbcopy_vector = i586_bcopy;
  369                 }
  370                 if (!(dvp->id_flags & NPX_DISABLE_I586_OPTIMIZED_BZERO))
  371                         bzero = i586_bzero;
  372                 if (!(dvp->id_flags & NPX_DISABLE_I586_OPTIMIZED_COPYIO)) {
  373                         copyin_vector = i586_copyin;
  374                         copyout_vector = i586_copyout;
  375                 }
  376         }
  377 #endif
  378 
  379         return (1);             /* XXX unused */
  380 }
  381 
  382 /*
  383  * Initialize floating point unit.
  384  */
  385 void
  386 npxinit(control)
  387         u_short control;
  388 {
  389         struct save87 dummy;
  390 
  391         if (!npx_exists)
  392                 return;
  393         /*
  394          * fninit has the same h/w bugs as fnsave.  Use the detoxified
  395          * fnsave to throw away any junk in the fpu.  npxsave() initializes
  396          * the fpu and sets npxproc = NULL as important side effects.
  397          */
  398         npxsave(&dummy);
  399         stop_emulating();
  400         fldcw(&control);
  401         if (curpcb != NULL)
  402                 fnsave(&curpcb->pcb_savefpu);
  403         start_emulating();
  404 }
  405 
  406 /*
  407  * Free coprocessor (if we have it).
  408  */
  409 void
  410 npxexit(p)
  411         struct proc *p;
  412 {
  413 
  414         if (p == npxproc)
  415                 npxsave(&curpcb->pcb_savefpu);
  416 #ifdef NPX_DEBUG
  417         if (npx_exists) {
  418                 u_int   masked_exceptions;
  419 
  420                 masked_exceptions = curpcb->pcb_savefpu.sv_env.en_cw
  421                                     & curpcb->pcb_savefpu.sv_env.en_sw & 0x7f;
  422                 /*
  423                  * Log exceptions that would have trapped with the old
  424                  * control word (overflow, divide by 0, and invalid operand).
  425                  */
  426                 if (masked_exceptions & 0x0d)
  427                         log(LOG_ERR,
  428         "pid %d (%s) exited with masked floating point exceptions 0x%02x\n",
  429                             p->p_pid, p->p_comm, masked_exceptions);
  430         }
  431 #endif
  432 }
  433 
  434 /*
  435  * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
  436  *
  437  * Clearing exceptions is necessary mainly to avoid IRQ13 bugs.  We now
  438  * depend on longjmp() restoring a usable state.  Restoring the state
  439  * or examining it might fail if we didn't clear exceptions.
  440  *
  441  * XXX there is no standard way to tell SIGFPE handlers about the error
  442  * state.  The old interface:
  443  *
  444  *      void handler(int sig, int code, struct sigcontext *scp);
  445  *
  446  * is broken because it is non-ANSI and because the FP state is not in
  447  * struct sigcontext.
  448  *
  449  * XXX the FP state is not preserved across signal handlers.  So signal
  450  * handlers cannot afford to do FP unless they preserve the state or
  451  * longjmp() out.  Both preserving the state and longjmp()ing may be
  452  * destroyed by IRQ13 bugs.  Clearing FP exceptions is not an acceptable
  453  * solution for signals other than SIGFPE.
  454  */
  455 void
  456 npxintr(unit)
  457         int unit;
  458 {
  459         int code;
  460         struct intrframe *frame;
  461 
  462         if (npxproc == NULL || !npx_exists) {
  463                 printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
  464                        npxproc, curproc, npx_exists);
  465                 panic("npxintr from nowhere");
  466         }
  467         if (npxproc != curproc) {
  468                 printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
  469                        npxproc, curproc, npx_exists);
  470                 panic("npxintr from non-current process");
  471         }
  472 
  473         outb(0xf0, 0);
  474         fnstsw(&curpcb->pcb_savefpu.sv_ex_sw);
  475         fnclex();
  476 
  477         /*
  478          * Pass exception to process.
  479          */
  480         frame = (struct intrframe *)&unit;      /* XXX */
  481         if (ISPL(frame->if_cs) == SEL_UPL) {
  482                 /*
  483                  * Interrupt is essentially a trap, so we can afford to call
  484                  * the SIGFPE handler (if any) as soon as the interrupt
  485                  * returns.
  486                  *
  487                  * XXX little or nothing is gained from this, and plenty is
  488                  * lost - the interrupt frame has to contain the trap frame
  489                  * (this is otherwise only necessary for the rescheduling trap
  490                  * in doreti, and the frame for that could easily be set up
  491                  * just before it is used).
  492                  */
  493                 curproc->p_md.md_regs = &frame->if_es;
  494 #ifdef notyet
  495                 /*
  496                  * Encode the appropriate code for detailed information on
  497                  * this exception.
  498                  */
  499                 code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
  500 #else
  501                 code = 0;       /* XXX */
  502 #endif
  503                 trapsignal(curproc, SIGFPE, code);
  504         } else {
  505                 /*
  506                  * Nested interrupt.  These losers occur when:
  507                  *      o an IRQ13 is bogusly generated at a bogus time, e.g.:
  508                  *              o immediately after an fnsave or frstor of an
  509                  *                error state.
  510                  *              o a couple of 386 instructions after
  511                  *                "fstpl _memvar" causes a stack overflow.
  512                  *        These are especially nasty when combined with a
  513                  *        trace trap.
  514                  *      o an IRQ13 occurs at the same time as another higher-
  515                  *        priority interrupt.
  516                  *
  517                  * Treat them like a true async interrupt.
  518                  */
  519                 psignal(curproc, SIGFPE);
  520         }
  521 }
  522 
  523 /*
  524  * Implement device not available (DNA) exception
  525  *
  526  * It would be better to switch FP context here (if curproc != npxproc)
  527  * and not necessarily for every context switch, but it is too hard to
  528  * access foreign pcb's.
  529  */
  530 int
  531 npxdna()
  532 {
  533         if (!npx_exists)
  534                 return (0);
  535         if (npxproc != NULL) {
  536                 printf("npxdna: npxproc = %p, curproc = %p\n",
  537                        npxproc, curproc);
  538                 panic("npxdna");
  539         }
  540         stop_emulating();
  541         /*
  542          * Record new context early in case frstor causes an IRQ13.
  543          */
  544         npxproc = curproc;
  545         curpcb->pcb_savefpu.sv_ex_sw = 0;
  546         /*
  547          * The following frstor may cause an IRQ13 when the state being
  548          * restored has a pending error.  The error will appear to have been
  549          * triggered by the current (npx) user instruction even when that
  550          * instruction is a no-wait instruction that should not trigger an
  551          * error (e.g., fnclex).  On at least one 486 system all of the
  552          * no-wait instructions are broken the same as frstor, so our
  553          * treatment does not amplify the breakage.  On at least one
  554          * 386/Cyrix 387 system, fnclex works correctly while frstor and
  555          * fnsave are broken, so our treatment breaks fnclex if it is the
  556          * first FPU instruction after a context switch.
  557          */
  558         frstor(&curpcb->pcb_savefpu);
  559 
  560         return (1);
  561 }
  562 
  563 /*
  564  * Wrapper for fnsave instruction to handle h/w bugs.  If there is an error
  565  * pending, then fnsave generates a bogus IRQ13 on some systems.  Force
  566  * any IRQ13 to be handled immediately, and then ignore it.  This routine is
  567  * often called at splhigh so it must not use many system services.  In
  568  * particular, it's much easier to install a special handler than to
  569  * guarantee that it's safe to use npxintr() and its supporting code.
  570  */
  571 void
  572 npxsave(addr)
  573         struct save87 *addr;
  574 {
  575         u_char  icu1_mask;
  576         u_char  icu2_mask;
  577         u_char  old_icu1_mask;
  578         u_char  old_icu2_mask;
  579         struct gate_descriptor  save_idt_npxintr;
  580 
  581         disable_intr();
  582         old_icu1_mask = inb(IO_ICU1 + 1);
  583         old_icu2_mask = inb(IO_ICU2 + 1);
  584         save_idt_npxintr = idt[npx_intrno];
  585         outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
  586         outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
  587         idt[npx_intrno] = npx_idt_probeintr;
  588         enable_intr();
  589         stop_emulating();
  590         fnsave(addr);
  591         fnop();
  592         start_emulating();
  593         npxproc = NULL;
  594         disable_intr();
  595         icu1_mask = inb(IO_ICU1 + 1);   /* masks may have changed */
  596         icu2_mask = inb(IO_ICU2 + 1);
  597         outb(IO_ICU1 + 1,
  598              (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
  599         outb(IO_ICU2 + 1,
  600              (icu2_mask & ~(npx0_imask >> 8))
  601              | (old_icu2_mask & (npx0_imask >> 8)));
  602         idt[npx_intrno] = save_idt_npxintr;
  603         enable_intr();          /* back to usual state */
  604 }
  605 
  606 #endif /* NNPX > 0 */

Cache object: d06d677d56ddb5a351d06861866681ec


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.