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

Cache object: 57e65cb2ed0d55794015c827c0875240


[ 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.