1 /* $NetBSD: npx.c,v 1.134 2008/11/25 21:53:50 bouyer Exp $ */
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software developed for The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1991 The Regents of the University of California.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * @(#)npx.c 7.2 (Berkeley) 5/12/91
64 * Copyright (c) 1994, 1995, 1998 Charles M. Hannum. All rights reserved.
65 * Copyright (c) 1990 William Jolitz.
67 * Redistribution and use in source and binary forms, with or without
68 * modification, are permitted provided that the following conditions
70 * 1. Redistributions of source code must retain the above copyright
71 * notice, this list of conditions and the following disclaimer.
72 * 2. Redistributions in binary form must reproduce the above copyright
73 * notice, this list of conditions and the following disclaimer in the
74 * documentation and/or other materials provided with the distribution.
75 * 3. All advertising materials mentioning features or use of this software
76 * must display the following acknowledgement:
77 * This product includes software developed by the University of
78 * California, Berkeley and its contributors.
79 * 4. Neither the name of the University nor the names of its contributors
80 * may be used to endorse or promote products derived from this software
81 * without specific prior written permission.
83 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
84 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
85 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
86 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
87 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
88 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
89 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
90 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
91 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
92 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95 * @(#)npx.c 7.2 (Berkeley) 5/12/91
98 #include <sys/cdefs.h>
99 __KERNEL_RCSID(0, "$NetBSD: npx.c,v 1.134 2008/11/25 21:53:50 bouyer Exp $");
102 #define IPRINTF(x) printf x
107 #include "opt_multiprocessor.h"
110 #include <sys/param.h>
111 #include <sys/systm.h>
112 #include <sys/conf.h>
113 #include <sys/file.h>
114 #include <sys/proc.h>
115 #include <sys/ioctl.h>
116 #include <sys/device.h>
117 #include <sys/vmmeter.h>
118 #include <sys/kernel.h>
121 #include <sys/intr.h>
123 #include <uvm/uvm_extern.h>
125 #include <machine/cpufunc.h>
126 #include <machine/pcb.h>
127 #include <machine/trap.h>
128 #include <machine/specialreg.h>
129 #include <machine/pio.h>
130 #include <machine/i8259.h>
132 #include <dev/isa/isareg.h>
133 #include <dev/isa/isavar.h>
135 #include <i386/isa/npxvar.h>
138 * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
140 * We do lazy initialization and switching using the TS bit in cr0 and the
141 * MDL_USEDFPU bit in mdlwp.
143 * DNA exceptions are handled like this:
145 * 1) If there is no NPX, return and go to the emulator.
146 * 2) If someone else has used the NPX, save its state into that process's PCB.
147 * 3a) If MDL_USEDFPU is not set, set it and initialize the NPX.
148 * 3b) Otherwise, reload the process's previous NPX state.
150 * When a process is created or exec()s, its saved cr0 image has the TS bit
151 * set and the MDL_USEDFPU bit clear. The MDL_USEDFPU bit is set when the
152 * process first gets a DNA and the NPX is initialized. The TS bit is turned
153 * off when the NPX is used, and turned on again later when the process's NPX
157 static int x86fpflags_to_ksiginfo(uint32_t flags
);
158 static int npxdna(struct cpu_info
*);
165 static enum npx_type npx_type
;
166 volatile u_int npx_intrs_while_probing
;
167 volatile u_int npx_traps_while_probing
;
169 extern int i386_fpu_present
;
170 extern int i386_fpu_exception
;
171 extern int i386_fpu_fdivbug
;
173 struct npx_softc
*npx_softc
;
176 fpu_save(union savefpu
*addr
)
180 fxsave(&addr
->sv_xmm
);
182 /* FXSAVE doesn't FNINIT like FNSAVE does -- so do it here. */
185 fnsave(&addr
->sv_87
);
189 npxdna_empty(struct cpu_info
*ci
)
193 panic("npxdna vector not initialized");
199 int (*npxdna_func
)(struct cpu_info
*) = npxdna_empty
;
203 * This calls i8259_* directly, but currently we can count on systems
204 * having a i8259 compatible setup all the time. Maybe have to change
205 * that in the future.
208 npxprobe1(bus_space_tag_t iot
, bus_space_handle_t ioh
, int irq
)
210 struct gate_descriptor save_idt_npxintr
;
211 struct gate_descriptor save_idt_npxtrap
;
212 enum npx_type rv
= NPX_NONE
;
218 if (cpu_feature
& CPUID_FPU
) {
219 i386_fpu_exception
= 1;
222 save_eflags
= x86_read_psl();
224 save_idt_npxintr
= idt
[NRSVIDT
+ irq
];
225 save_idt_npxtrap
= idt
[16];
226 setgate(&idt
[NRSVIDT
+ irq
], probeintr
, 0, SDT_SYS386IGT
, SEL_KPL
,
227 GSEL(GCODE_SEL
, SEL_KPL
));
228 setgate(&idt
[16], probetrap
, 0, SDT_SYS386TGT
, SEL_KPL
,
229 GSEL(GCODE_SEL
, SEL_KPL
));
231 irqmask
= i8259_setmask(~((1 << IRQ_SLAVE
) | (1 << irq
)));
234 * Partially reset the coprocessor, if any. Some BIOS's don't reset
235 * it after a warm boot.
237 /* full reset on some systems, NOP on others */
238 bus_space_write_1(iot
, ioh
, 1, 0);
240 /* clear BUSY# latch */
241 bus_space_write_1(iot
, ioh
, 0, 0);
244 * We set CR0 in locore to trap all ESC and WAIT instructions.
245 * We have to turn off the CR0_EM bit temporarily while probing.
247 lcr0(rcr0() & ~(CR0_EM
|CR0_TS
));
251 * Finish resetting the coprocessor, if any. If there is an error
252 * pending, then we may get a bogus IRQ13, but probeintr() will handle
253 * it OK. Bogus halts have never been observed, but we enabled
254 * IRQ13 and cleared the BUSY# latch early to handle them anyway.
257 delay(1000); /* wait for any IRQ13 (fwait might hang) */
260 * Check for a status of mostly zero.
264 if ((status
& 0xb8ff) == 0) {
266 * Good, now check for a proper control word.
270 if ((control
& 0x1f3f) == 0x033f) {
272 * We have an npx, now divide by 0 to see if exception
275 control
&= ~(1 << 2); /* enable divide by 0 trap */
277 npx_traps_while_probing
= npx_intrs_while_probing
= 0;
279 if (npx_traps_while_probing
!= 0) {
281 * Good, exception 16 works.
284 i386_fpu_exception
= 1;
285 } else if (npx_intrs_while_probing
!= 0) {
287 * Bad, we are stuck with IRQ13.
292 * Worse, even IRQ13 is broken. Use emulator.
300 lcr0(rcr0() | (CR0_EM
|CR0_TS
));
302 irqmask
= i8259_setmask(irqmask
);
304 idt
[NRSVIDT
+ irq
] = save_idt_npxintr
;
306 idt
[16] = save_idt_npxtrap
;
307 x86_write_psl(save_eflags
);
312 void npxinit(struct cpu_info
*ci
)
314 lcr0(rcr0() & ~(CR0_EM
|CR0_TS
));
316 if (npx586bug1(4195835, 3145727) != 0) {
317 i386_fpu_fdivbug
= 1;
318 aprint_normal_dev(ci
->ci_dev
,
319 "WARNING: Pentium FDIV bug detected!\n");
321 lcr0(rcr0() | (CR0_TS
));
326 * Common attach routine.
329 npxattach(struct npx_softc
*sc
)
333 npx_type
= sc
->sc_type
;
336 npxinit(&cpu_info_primary
);
338 i386_fpu_present
= 1;
339 npxdna_func
= npxdna
;
341 if (!pmf_device_register(sc
->sc_dev
, NULL
, NULL
))
342 aprint_error_dev(sc
->sc_dev
, "couldn't establish power handler\n");
346 npxdetach(device_t self
, int flags
)
348 struct npx_softc
*sc
= device_private(self
);
350 if (sc
->sc_type
== NPX_INTERRUPT
)
353 pmf_device_deregister(self
);
359 * Record the FPU state and reinitialize it all except for the control word.
360 * Then generate a SIGFPE.
362 * Reinitializing the state allows naive SIGFPE handlers to longjmp without
365 * XXX there is currently no way to pass the full error state to signal
366 * handlers, and if this is a nested interrupt there is no way to pass even
367 * a status code! So there is no way to have a non-naive SIGFPE handler. At
368 * best a handler could do an fninit followed by an fldcw of a static value.
369 * fnclex would be of little use because it would leave junk on the FPU stack.
370 * Returning from the handler would be even less safe than usual because
371 * IRQ13 exception handling makes exceptions even less precise than usual.
374 npxintr(void *arg
, struct intrframe
*frame
)
376 struct cpu_info
*ci
= curcpu();
377 struct lwp
*l
= ci
->ci_fpcurlwp
;
379 struct npx_softc
*sc
;
387 KASSERT((x86_read_psl() & PSL_I
) == 0);
392 IPRINTF(("%s: fp intr\n", device_xname(ci
->ci_dev
)));
396 * Clear the interrupt latch.
398 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, 0, 0);
402 * If we're saving, ignore the interrupt. The FPU will generate
403 * another one when we restore the state later.
405 if (ci
->ci_fpsaving
) {
410 if (l
== NULL
|| npx_type
== NPX_NONE
) {
411 printf("npxintr: l = %p, curproc = %p, npx_type = %d\n",
412 l
, curproc
, npx_type
);
413 printf("npxintr: came from nowhere");
419 * At this point, fpcurlwp should be curlwp. If it wasn't, the TS
420 * bit should be set, and we should have gotten a DNA exception.
422 KASSERT(l
== curlwp
);
426 * Find the address of fpcurproc's saved FPU state. (Given the
427 * invariant above, this is always the one in curpcb.)
429 addr
= &pcb
->pcb_savefpu
;
432 * Save state. This does an implied fninit. It had better not halt
433 * the CPU or we'll hang.
437 if (i386_use_fxsave
) {
438 fldcw(&addr
->sv_xmm
.sv_env
.en_cw
);
440 * FNINIT doesn't affect MXCSR or the XMM registers;
441 * no need to re-load MXCSR here.
444 fldcw(&addr
->sv_87
.sv_env
.en_cw
);
447 * Remember the exception status word and tag word. The current
448 * (almost fninit'ed) fpu state is in the fpu and the exception
449 * state just saved will soon be junk. However, the implied fninit
450 * doesn't change the error pointers or register contents, and we
451 * preserved the control word and will copy the status and tag
452 * words, so the complete exception state can be recovered.
454 if (i386_use_fxsave
) {
455 addr
->sv_xmm
.sv_ex_sw
= addr
->sv_xmm
.sv_env
.en_sw
;
456 addr
->sv_xmm
.sv_ex_tw
= addr
->sv_xmm
.sv_env
.en_tw
;
458 addr
->sv_87
.sv_ex_sw
= addr
->sv_87
.sv_env
.en_sw
;
459 addr
->sv_87
.sv_ex_tw
= addr
->sv_87
.sv_env
.en_tw
;
462 * Pass exception to process.
464 if (USERMODE(frame
->if_cs
, frame
->if_eflags
)) {
466 * Interrupt is essentially a trap, so we can afford to call
467 * the SIGFPE handler (if any) as soon as the interrupt
470 * XXX little or nothing is gained from this, and plenty is
471 * lost - the interrupt frame has to contain the trap frame
472 * (this is otherwise only necessary for the rescheduling trap
473 * in doreti, and the frame for that could easily be set up
474 * just before it is used).
476 l
->l_md
.md_regs
= (struct trapframe
*)&frame
->if_gs
;
479 ksi
.ksi_signo
= SIGFPE
;
480 ksi
.ksi_addr
= (void *)frame
->if_eip
;
483 * Encode the appropriate code for detailed information on
487 if (i386_use_fxsave
) {
489 x86fpflags_to_ksiginfo(addr
->sv_xmm
.sv_ex_sw
);
490 ksi
.ksi_trap
= (int)addr
->sv_xmm
.sv_ex_sw
;
493 x86fpflags_to_ksiginfo(addr
->sv_87
.sv_ex_sw
);
494 ksi
.ksi_trap
= (int)addr
->sv_87
.sv_ex_sw
;
500 * This is a nested interrupt. This should only happen when
501 * an IRQ13 occurs at the same time as a higher-priority
505 * Currently, we treat this like an asynchronous interrupt, but
506 * this has disadvantages.
508 psignal(l
->l_proc
, SIGFPE
);
515 /* map x86 fp flags to ksiginfo fp codes */
516 /* see table 8-4 of the IA-32 Intel Architecture */
517 /* Software Developer's Manual, Volume 1 */
518 /* XXX punting on the stack fault with FLTINV */
520 x86fpflags_to_ksiginfo(uint32_t flags
)
523 static int x86fp_ksiginfo_table
[] = {
524 FPE_FLTINV
, /* bit 0 - invalid operation */
525 FPE_FLTRES
, /* bit 1 - denormal operand */
526 FPE_FLTDIV
, /* bit 2 - divide by zero */
527 FPE_FLTOVF
, /* bit 3 - fp overflow */
528 FPE_FLTUND
, /* bit 4 - fp underflow */
529 FPE_FLTRES
, /* bit 5 - fp precision */
530 FPE_FLTINV
, /* bit 6 - stack fault */
533 for(i
=0;i
< sizeof(x86fp_ksiginfo_table
)/sizeof(int); i
++) {
534 if (flags
& (1 << i
))
535 return(x86fp_ksiginfo_table
[i
]);
537 /* punt if flags not set */
542 * Implement device not available (DNA) exception
544 * If we were the last lwp to use the FPU, we can simply return.
545 * Otherwise, we save the previous state, if necessary, and restore
546 * our last saved state.
549 npxdna(struct cpu_info
*ci
)
555 if (ci
->ci_fpsaving
) {
556 /* Recursive trap. */
560 /* Lock out IPIs and disable preemption. */
565 /* Save state on current CPU. */
569 fl
= ci
->ci_fpcurlwp
;
572 * It seems we can get here on Xen even if we didn't
573 * switch lwp. In this case do nothing
576 KASSERT(pcb
->pcb_fpcpu
== ci
);
584 KASSERT(ci
->ci_fpcurlwp
== NULL
);
587 /* Save our state if on a remote CPU. */
588 if (pcb
->pcb_fpcpu
!= NULL
) {
589 /* Explicitly disable preemption before dropping spl. */
592 npxsave_lwp(l
, true);
593 KASSERT(pcb
->pcb_fpcpu
== NULL
);
599 * Restore state on this CPU, or initialize. Ensure that
600 * the entire update is atomic with respect to FPU-sync IPIs.
607 if ((l
->l_md
.md_flags
& MDL_USEDFPU
) == 0) {
609 if (i386_use_fxsave
) {
610 fldcw(&pcb
->pcb_savefpu
.
611 sv_xmm
.sv_env
.en_cw
);
613 fldcw(&pcb
->pcb_savefpu
.
616 l
->l_md
.md_flags
|= MDL_USEDFPU
;
617 } else if (i386_use_fxsave
) {
619 * AMD FPU's do not restore FIP, FDP, and FOP on fxrstor,
620 * leaking other process's execution history. Clear them
623 static const double zero
= 0.0;
626 * Clear the ES bit in the x87 status word if it is currently
627 * set, in order to avoid causing a fault in the upcoming load.
633 * Load the dummy variable into the x87 stack. This mangles
634 * the x87 stack, but we don't care since we're about to call
638 fxrstor(&pcb
->pcb_savefpu
.sv_xmm
);
640 frstor(&pcb
->pcb_savefpu
.sv_87
);
643 KASSERT(ci
== curcpu());
649 * Save current CPU's FPU state. Must be called at IPL_HIGH.
652 npxsave_cpu(bool save
)
658 KASSERT(curcpu()->ci_ilevel
== IPL_HIGH
);
669 * Set ci->ci_fpsaving, so that any pending exception will
670 * be thrown away. It will be caught again if/when the
671 * FPU state is restored.
673 KASSERT(ci
->ci_fpsaving
== 0);
676 if (i386_use_fxsave
) {
677 fxsave(&pcb
->pcb_savefpu
.sv_xmm
);
679 fnsave(&pcb
->pcb_savefpu
.sv_87
);
685 pcb
->pcb_fpcpu
= NULL
;
686 ci
->ci_fpcurlwp
= NULL
;
691 * Save l's FPU state, which may be on this processor or another processor.
692 * It may take some time, so we avoid disabling preemption where possible.
693 * Caller must know that the target LWP is stopped, otherwise this routine
694 * may race against it.
697 npxsave_lwp(struct lwp
*l
, bool save
)
699 struct cpu_info
*oci
;
704 ticks
= hardclock_ticks
;
708 oci
= pcb
->pcb_fpcpu
;
713 if (oci
== curcpu()) {
714 KASSERT(oci
->ci_fpcurlwp
== l
);
720 x86_send_ipi(oci
, X86_IPI_SYNCH_FPU
);
721 while (pcb
->pcb_fpcpu
== oci
&&
722 ticks
== hardclock_ticks
) {
726 if (spins
> 100000000) {
727 panic("npxsave_lwp: did not");
732 /* Ensure we restart with a clean slate. */
733 l
->l_md
.md_flags
&= ~MDL_USEDFPU
;