fpu.c revision 122292
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 *	@(#)npx.c	7.2 (Berkeley) 5/12/91
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/amd64/amd64/fpu.c 122292 2003-11-08 03:33:38Z peter $");
39
40#include "opt_isa.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/bus.h>
45#include <sys/kernel.h>
46#include <sys/lock.h>
47#include <sys/malloc.h>
48#include <sys/module.h>
49#include <sys/mutex.h>
50#include <sys/mutex.h>
51#include <sys/proc.h>
52#include <sys/sysctl.h>
53#include <machine/bus.h>
54#include <sys/rman.h>
55#include <sys/signalvar.h>
56#include <sys/user.h>
57
58#include <machine/cputypes.h>
59#include <machine/frame.h>
60#include <machine/md_var.h>
61#include <machine/pcb.h>
62#include <machine/psl.h>
63#include <machine/resource.h>
64#include <machine/specialreg.h>
65#include <machine/segments.h>
66#include <machine/ucontext.h>
67
68#include <amd64/isa/intr_machdep.h>
69#ifdef DEV_ISA
70#include <isa/isavar.h>
71#endif
72
73/*
74 * Floating point support.
75 */
76
77#if defined(__GNUC__) && !defined(lint)
78
79#define	fldcw(addr)		__asm("fldcw %0" : : "m" (*(addr)))
80#define	fnclex()		__asm("fnclex")
81#define	fninit()		__asm("fninit")
82#define	fnstcw(addr)		__asm __volatile("fnstcw %0" : "=m" (*(addr)))
83#define	fnstsw(addr)		__asm __volatile("fnstsw %0" : "=m" (*(addr)))
84#define	fxrstor(addr)		__asm("fxrstor %0" : : "m" (*(addr)))
85#define	fxsave(addr)		__asm __volatile("fxsave %0" : "=m" (*(addr)))
86#define	start_emulating()	__asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
87				      : : "n" (CR0_TS) : "ax")
88#define	stop_emulating()	__asm("clts")
89
90#else	/* not __GNUC__ */
91
92void	fldcw(caddr_t addr);
93void	fnclex(void);
94void	fninit(void);
95void	fnstcw(caddr_t addr);
96void	fnstsw(caddr_t addr);
97void	fxsave(caddr_t addr);
98void	fxrstor(caddr_t addr);
99void	start_emulating(void);
100void	stop_emulating(void);
101
102#endif	/* __GNUC__ */
103
104#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_cw)
105#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_sw)
106
107typedef u_char bool_t;
108
109static	int	fpu_attach(device_t dev);
110static	void	fpu_identify(driver_t *driver, device_t parent);
111static	int	fpu_probe(device_t dev);
112
113int	hw_float = 1;
114SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
115	CTLFLAG_RD, &hw_float, 0,
116	"Floatingpoint instructions executed in hardware");
117
118static	struct savefpu		fpu_cleanstate;
119static	bool_t			fpu_cleanstate_ready;
120
121/*
122 * Identify routine.  Create a connection point on our parent for probing.
123 */
124static void
125fpu_identify(driver_t *driver, device_t parent)
126{
127	device_t child;
128
129	child = BUS_ADD_CHILD(parent, 0, "fpu", 0);
130	if (child == NULL)
131		panic("fpu_identify");
132}
133
134/*
135 * Probe routine.  Initialize cr0 to give correct behaviour for [f]wait
136 * whether the device exists or not (XXX should be elsewhere).
137 * Modify device struct if fpu doesn't need to use interrupts.
138 * Return 0 if device exists.
139 */
140static int
141fpu_probe(device_t dev)
142{
143
144	/*
145	 * Prepare to trap all ESC (i.e., FPU) instructions and all WAIT
146	 * instructions.  We must set the CR0_MP bit and use the CR0_TS
147	 * bit to control the trap, because setting the CR0_EM bit does
148	 * not cause WAIT instructions to trap.  It's important to trap
149	 * WAIT instructions - otherwise the "wait" variants of no-wait
150	 * control instructions would degenerate to the "no-wait" variants
151	 * after FP context switches but work correctly otherwise.  It's
152	 * particularly important to trap WAITs when there is no FPU -
153	 * otherwise the "wait" variants would always degenerate.
154	 *
155	 * Try setting CR0_NE to get correct error reporting on 486DX's.
156	 * Setting it should fail or do nothing on lesser processors.
157	 */
158	load_cr0(rcr0() | CR0_MP | CR0_NE);
159	/*
160	 * But don't trap while we're probing.
161	 */
162	stop_emulating();
163	/*
164	 * Finish resetting the coprocessor.
165	 */
166	fninit();
167
168	device_set_desc(dev, "math processor");
169	device_quiet(dev);
170
171	return (0);
172}
173
174/*
175 * Attach routine - announce which it is, and wire into system
176 */
177static int
178fpu_attach(device_t dev)
179{
180	register_t s;
181
182	fpuinit(__INITIAL_FPUCW__);
183
184	if (fpu_cleanstate_ready == 0) {
185		s = intr_disable();
186		stop_emulating();
187		fxsave(&fpu_cleanstate);
188		start_emulating();
189		fpu_cleanstate_ready = 1;
190		intr_restore(s);
191	}
192	return (0);		/* XXX unused */
193}
194
195/*
196 * Initialize floating point unit.
197 */
198void
199fpuinit(u_short control)
200{
201	static struct savefpu dummy;
202	register_t savecrit;
203
204	/*
205	 * fninit has the same h/w bugs as fnsave.  Use the detoxified
206	 * fnsave to throw away any junk in the fpu.  fpusave() initializes
207	 * the fpu and sets fpcurthread = NULL as important side effects.
208	 */
209	savecrit = intr_disable();
210	fpusave(&dummy);
211	stop_emulating();
212	/* XXX fpusave() doesn't actually initialize the fpu in the SSE case. */
213	fninit();
214	fldcw(&control);
215	start_emulating();
216	intr_restore(savecrit);
217}
218
219/*
220 * Free coprocessor (if we have it).
221 */
222void
223fpuexit(struct thread *td)
224{
225	register_t savecrit;
226
227	savecrit = intr_disable();
228	if (curthread == PCPU_GET(fpcurthread))
229		fpusave(&PCPU_GET(curpcb)->pcb_save);
230	intr_restore(savecrit);
231}
232
233int
234fpuformat()
235{
236
237	return (_MC_FPFMT_XMM);
238}
239
240/*
241 * The following mechanism is used to ensure that the FPE_... value
242 * that is passed as a trapcode to the signal handler of the user
243 * process does not have more than one bit set.
244 *
245 * Multiple bits may be set if the user process modifies the control
246 * word while a status word bit is already set.  While this is a sign
247 * of bad coding, we have no choise than to narrow them down to one
248 * bit, since we must not send a trapcode that is not exactly one of
249 * the FPE_ macros.
250 *
251 * The mechanism has a static table with 127 entries.  Each combination
252 * of the 7 FPU status word exception bits directly translates to a
253 * position in this table, where a single FPE_... value is stored.
254 * This FPE_... value stored there is considered the "most important"
255 * of the exception bits and will be sent as the signal code.  The
256 * precedence of the bits is based upon Intel Document "Numerical
257 * Applications", Chapter "Special Computational Situations".
258 *
259 * The macro to choose one of these values does these steps: 1) Throw
260 * away status word bits that cannot be masked.  2) Throw away the bits
261 * currently masked in the control word, assuming the user isn't
262 * interested in them anymore.  3) Reinsert status word bit 7 (stack
263 * fault) if it is set, which cannot be masked but must be presered.
264 * 4) Use the remaining bits to point into the trapcode table.
265 *
266 * The 6 maskable bits in order of their preference, as stated in the
267 * above referenced Intel manual:
268 * 1  Invalid operation (FP_X_INV)
269 * 1a   Stack underflow
270 * 1b   Stack overflow
271 * 1c   Operand of unsupported format
272 * 1d   SNaN operand.
273 * 2  QNaN operand (not an exception, irrelavant here)
274 * 3  Any other invalid-operation not mentioned above or zero divide
275 *      (FP_X_INV, FP_X_DZ)
276 * 4  Denormal operand (FP_X_DNML)
277 * 5  Numeric over/underflow (FP_X_OFL, FP_X_UFL)
278 * 6  Inexact result (FP_X_IMP)
279 */
280static char fpetable[128] = {
281	0,
282	FPE_FLTINV,	/*  1 - INV */
283	FPE_FLTUND,	/*  2 - DNML */
284	FPE_FLTINV,	/*  3 - INV | DNML */
285	FPE_FLTDIV,	/*  4 - DZ */
286	FPE_FLTINV,	/*  5 - INV | DZ */
287	FPE_FLTDIV,	/*  6 - DNML | DZ */
288	FPE_FLTINV,	/*  7 - INV | DNML | DZ */
289	FPE_FLTOVF,	/*  8 - OFL */
290	FPE_FLTINV,	/*  9 - INV | OFL */
291	FPE_FLTUND,	/*  A - DNML | OFL */
292	FPE_FLTINV,	/*  B - INV | DNML | OFL */
293	FPE_FLTDIV,	/*  C - DZ | OFL */
294	FPE_FLTINV,	/*  D - INV | DZ | OFL */
295	FPE_FLTDIV,	/*  E - DNML | DZ | OFL */
296	FPE_FLTINV,	/*  F - INV | DNML | DZ | OFL */
297	FPE_FLTUND,	/* 10 - UFL */
298	FPE_FLTINV,	/* 11 - INV | UFL */
299	FPE_FLTUND,	/* 12 - DNML | UFL */
300	FPE_FLTINV,	/* 13 - INV | DNML | UFL */
301	FPE_FLTDIV,	/* 14 - DZ | UFL */
302	FPE_FLTINV,	/* 15 - INV | DZ | UFL */
303	FPE_FLTDIV,	/* 16 - DNML | DZ | UFL */
304	FPE_FLTINV,	/* 17 - INV | DNML | DZ | UFL */
305	FPE_FLTOVF,	/* 18 - OFL | UFL */
306	FPE_FLTINV,	/* 19 - INV | OFL | UFL */
307	FPE_FLTUND,	/* 1A - DNML | OFL | UFL */
308	FPE_FLTINV,	/* 1B - INV | DNML | OFL | UFL */
309	FPE_FLTDIV,	/* 1C - DZ | OFL | UFL */
310	FPE_FLTINV,	/* 1D - INV | DZ | OFL | UFL */
311	FPE_FLTDIV,	/* 1E - DNML | DZ | OFL | UFL */
312	FPE_FLTINV,	/* 1F - INV | DNML | DZ | OFL | UFL */
313	FPE_FLTRES,	/* 20 - IMP */
314	FPE_FLTINV,	/* 21 - INV | IMP */
315	FPE_FLTUND,	/* 22 - DNML | IMP */
316	FPE_FLTINV,	/* 23 - INV | DNML | IMP */
317	FPE_FLTDIV,	/* 24 - DZ | IMP */
318	FPE_FLTINV,	/* 25 - INV | DZ | IMP */
319	FPE_FLTDIV,	/* 26 - DNML | DZ | IMP */
320	FPE_FLTINV,	/* 27 - INV | DNML | DZ | IMP */
321	FPE_FLTOVF,	/* 28 - OFL | IMP */
322	FPE_FLTINV,	/* 29 - INV | OFL | IMP */
323	FPE_FLTUND,	/* 2A - DNML | OFL | IMP */
324	FPE_FLTINV,	/* 2B - INV | DNML | OFL | IMP */
325	FPE_FLTDIV,	/* 2C - DZ | OFL | IMP */
326	FPE_FLTINV,	/* 2D - INV | DZ | OFL | IMP */
327	FPE_FLTDIV,	/* 2E - DNML | DZ | OFL | IMP */
328	FPE_FLTINV,	/* 2F - INV | DNML | DZ | OFL | IMP */
329	FPE_FLTUND,	/* 30 - UFL | IMP */
330	FPE_FLTINV,	/* 31 - INV | UFL | IMP */
331	FPE_FLTUND,	/* 32 - DNML | UFL | IMP */
332	FPE_FLTINV,	/* 33 - INV | DNML | UFL | IMP */
333	FPE_FLTDIV,	/* 34 - DZ | UFL | IMP */
334	FPE_FLTINV,	/* 35 - INV | DZ | UFL | IMP */
335	FPE_FLTDIV,	/* 36 - DNML | DZ | UFL | IMP */
336	FPE_FLTINV,	/* 37 - INV | DNML | DZ | UFL | IMP */
337	FPE_FLTOVF,	/* 38 - OFL | UFL | IMP */
338	FPE_FLTINV,	/* 39 - INV | OFL | UFL | IMP */
339	FPE_FLTUND,	/* 3A - DNML | OFL | UFL | IMP */
340	FPE_FLTINV,	/* 3B - INV | DNML | OFL | UFL | IMP */
341	FPE_FLTDIV,	/* 3C - DZ | OFL | UFL | IMP */
342	FPE_FLTINV,	/* 3D - INV | DZ | OFL | UFL | IMP */
343	FPE_FLTDIV,	/* 3E - DNML | DZ | OFL | UFL | IMP */
344	FPE_FLTINV,	/* 3F - INV | DNML | DZ | OFL | UFL | IMP */
345	FPE_FLTSUB,	/* 40 - STK */
346	FPE_FLTSUB,	/* 41 - INV | STK */
347	FPE_FLTUND,	/* 42 - DNML | STK */
348	FPE_FLTSUB,	/* 43 - INV | DNML | STK */
349	FPE_FLTDIV,	/* 44 - DZ | STK */
350	FPE_FLTSUB,	/* 45 - INV | DZ | STK */
351	FPE_FLTDIV,	/* 46 - DNML | DZ | STK */
352	FPE_FLTSUB,	/* 47 - INV | DNML | DZ | STK */
353	FPE_FLTOVF,	/* 48 - OFL | STK */
354	FPE_FLTSUB,	/* 49 - INV | OFL | STK */
355	FPE_FLTUND,	/* 4A - DNML | OFL | STK */
356	FPE_FLTSUB,	/* 4B - INV | DNML | OFL | STK */
357	FPE_FLTDIV,	/* 4C - DZ | OFL | STK */
358	FPE_FLTSUB,	/* 4D - INV | DZ | OFL | STK */
359	FPE_FLTDIV,	/* 4E - DNML | DZ | OFL | STK */
360	FPE_FLTSUB,	/* 4F - INV | DNML | DZ | OFL | STK */
361	FPE_FLTUND,	/* 50 - UFL | STK */
362	FPE_FLTSUB,	/* 51 - INV | UFL | STK */
363	FPE_FLTUND,	/* 52 - DNML | UFL | STK */
364	FPE_FLTSUB,	/* 53 - INV | DNML | UFL | STK */
365	FPE_FLTDIV,	/* 54 - DZ | UFL | STK */
366	FPE_FLTSUB,	/* 55 - INV | DZ | UFL | STK */
367	FPE_FLTDIV,	/* 56 - DNML | DZ | UFL | STK */
368	FPE_FLTSUB,	/* 57 - INV | DNML | DZ | UFL | STK */
369	FPE_FLTOVF,	/* 58 - OFL | UFL | STK */
370	FPE_FLTSUB,	/* 59 - INV | OFL | UFL | STK */
371	FPE_FLTUND,	/* 5A - DNML | OFL | UFL | STK */
372	FPE_FLTSUB,	/* 5B - INV | DNML | OFL | UFL | STK */
373	FPE_FLTDIV,	/* 5C - DZ | OFL | UFL | STK */
374	FPE_FLTSUB,	/* 5D - INV | DZ | OFL | UFL | STK */
375	FPE_FLTDIV,	/* 5E - DNML | DZ | OFL | UFL | STK */
376	FPE_FLTSUB,	/* 5F - INV | DNML | DZ | OFL | UFL | STK */
377	FPE_FLTRES,	/* 60 - IMP | STK */
378	FPE_FLTSUB,	/* 61 - INV | IMP | STK */
379	FPE_FLTUND,	/* 62 - DNML | IMP | STK */
380	FPE_FLTSUB,	/* 63 - INV | DNML | IMP | STK */
381	FPE_FLTDIV,	/* 64 - DZ | IMP | STK */
382	FPE_FLTSUB,	/* 65 - INV | DZ | IMP | STK */
383	FPE_FLTDIV,	/* 66 - DNML | DZ | IMP | STK */
384	FPE_FLTSUB,	/* 67 - INV | DNML | DZ | IMP | STK */
385	FPE_FLTOVF,	/* 68 - OFL | IMP | STK */
386	FPE_FLTSUB,	/* 69 - INV | OFL | IMP | STK */
387	FPE_FLTUND,	/* 6A - DNML | OFL | IMP | STK */
388	FPE_FLTSUB,	/* 6B - INV | DNML | OFL | IMP | STK */
389	FPE_FLTDIV,	/* 6C - DZ | OFL | IMP | STK */
390	FPE_FLTSUB,	/* 6D - INV | DZ | OFL | IMP | STK */
391	FPE_FLTDIV,	/* 6E - DNML | DZ | OFL | IMP | STK */
392	FPE_FLTSUB,	/* 6F - INV | DNML | DZ | OFL | IMP | STK */
393	FPE_FLTUND,	/* 70 - UFL | IMP | STK */
394	FPE_FLTSUB,	/* 71 - INV | UFL | IMP | STK */
395	FPE_FLTUND,	/* 72 - DNML | UFL | IMP | STK */
396	FPE_FLTSUB,	/* 73 - INV | DNML | UFL | IMP | STK */
397	FPE_FLTDIV,	/* 74 - DZ | UFL | IMP | STK */
398	FPE_FLTSUB,	/* 75 - INV | DZ | UFL | IMP | STK */
399	FPE_FLTDIV,	/* 76 - DNML | DZ | UFL | IMP | STK */
400	FPE_FLTSUB,	/* 77 - INV | DNML | DZ | UFL | IMP | STK */
401	FPE_FLTOVF,	/* 78 - OFL | UFL | IMP | STK */
402	FPE_FLTSUB,	/* 79 - INV | OFL | UFL | IMP | STK */
403	FPE_FLTUND,	/* 7A - DNML | OFL | UFL | IMP | STK */
404	FPE_FLTSUB,	/* 7B - INV | DNML | OFL | UFL | IMP | STK */
405	FPE_FLTDIV,	/* 7C - DZ | OFL | UFL | IMP | STK */
406	FPE_FLTSUB,	/* 7D - INV | DZ | OFL | UFL | IMP | STK */
407	FPE_FLTDIV,	/* 7E - DNML | DZ | OFL | UFL | IMP | STK */
408	FPE_FLTSUB,	/* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */
409};
410
411/*
412 * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
413 *
414 * Clearing exceptions is necessary mainly to avoid IRQ13 bugs.  We now
415 * depend on longjmp() restoring a usable state.  Restoring the state
416 * or examining it might fail if we didn't clear exceptions.
417 *
418 * The error code chosen will be one of the FPE_... macros. It will be
419 * sent as the second argument to old BSD-style signal handlers and as
420 * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers.
421 *
422 * XXX the FP state is not preserved across signal handlers.  So signal
423 * handlers cannot afford to do FP unless they preserve the state or
424 * longjmp() out.  Both preserving the state and longjmp()ing may be
425 * destroyed by IRQ13 bugs.  Clearing FP exceptions is not an acceptable
426 * solution for signals other than SIGFPE.
427 */
428int
429fputrap()
430{
431	register_t savecrit;
432	u_short control, status;
433
434	savecrit = intr_disable();
435
436	/*
437	 * Interrupt handling (for another interrupt) may have pushed the
438	 * state to memory.  Fetch the relevant parts of the state from
439	 * wherever they are.
440	 */
441	if (PCPU_GET(fpcurthread) != curthread) {
442		control = GET_FPU_CW(curthread);
443		status = GET_FPU_SW(curthread);
444	} else {
445		fnstcw(&control);
446		fnstsw(&status);
447	}
448
449	if (PCPU_GET(fpcurthread) == curthread)
450		fnclex();
451	intr_restore(savecrit);
452	return (fpetable[status & ((~control & 0x3f) | 0x40)]);
453}
454
455/*
456 * Implement device not available (DNA) exception
457 *
458 * It would be better to switch FP context here (if curthread != fpcurthread)
459 * and not necessarily for every context switch, but it is too hard to
460 * access foreign pcb's.
461 */
462
463static int err_count = 0;
464
465int
466fpudna()
467{
468	struct pcb *pcb;
469	register_t s;
470	u_short control;
471
472	if (PCPU_GET(fpcurthread) == curthread) {
473		printf("fpudna: fpcurthread == curthread %d times\n",
474		    ++err_count);
475		stop_emulating();
476		return (1);
477	}
478	if (PCPU_GET(fpcurthread) != NULL) {
479		printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
480		       PCPU_GET(fpcurthread),
481		       PCPU_GET(fpcurthread)->td_proc->p_pid,
482		       curthread, curthread->td_proc->p_pid);
483		panic("fpudna");
484	}
485	s = intr_disable();
486	stop_emulating();
487	/*
488	 * Record new context early in case frstor causes a trap.
489	 */
490	PCPU_SET(fpcurthread, curthread);
491	pcb = PCPU_GET(curpcb);
492
493	if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
494		/*
495		 * This is the first time this thread has used the FPU or
496		 * the PCB doesn't contain a clean FPU state.  Explicitly
497		 * initialize the FPU and load the default control word.
498		 */
499		fninit();
500		control = __INITIAL_FPUCW__;
501		fldcw(&control);
502		pcb->pcb_flags |= PCB_FPUINITDONE;
503	} else {
504		/*
505		 * The following frstor may cause a trap when the state
506		 * being restored has a pending error.  The error will
507		 * appear to have been triggered by the current (fpu) user
508		 * instruction even when that instruction is a no-wait
509		 * instruction that should not trigger an error (e.g.,
510		 * instructions are broken the same as frstor, so our
511		 * treatment does not amplify the breakage.
512		 */
513		fxrstor(&pcb->pcb_save);
514	}
515	intr_restore(s);
516
517	return (1);
518}
519
520/*
521 * Wrapper for fnsave instruction.
522 *
523 * fpusave() must be called with interrupts disabled, so that it clears
524 * fpcurthread atomically with saving the state.  We require callers to do the
525 * disabling, since most callers need to disable interrupts anyway to call
526 * fpusave() atomically with checking fpcurthread.
527 */
528void
529fpusave(struct savefpu *addr)
530{
531
532	stop_emulating();
533	fxsave(addr);
534	start_emulating();
535	PCPU_SET(fpcurthread, NULL);
536}
537
538/*
539 * This should be called with interrupts disabled and only when the owning
540 * FPU thread is non-null.
541 */
542void
543fpudrop()
544{
545	struct thread *td;
546
547	td = PCPU_GET(fpcurthread);
548	PCPU_SET(fpcurthread, NULL);
549	td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
550	start_emulating();
551}
552
553/*
554 * Get the state of the FPU without dropping ownership (if possible).
555 * It returns the FPU ownership status.
556 */
557int
558fpugetregs(struct thread *td, struct savefpu *addr)
559{
560	register_t s;
561
562	if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
563		if (fpu_cleanstate_ready)
564			bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate));
565		else
566			bzero(addr, sizeof(*addr));
567		return (_MC_FPOWNED_NONE);
568	}
569	s = intr_disable();
570	if (td == PCPU_GET(fpcurthread)) {
571		fxsave(addr);
572		intr_restore(s);
573		return (_MC_FPOWNED_FPU);
574	} else {
575		intr_restore(s);
576		bcopy(&td->td_pcb->pcb_save, addr, sizeof(*addr));
577		return (_MC_FPOWNED_PCB);
578	}
579}
580
581/*
582 * Set the state of the FPU.
583 */
584void
585fpusetregs(struct thread *td, struct savefpu *addr)
586{
587	register_t s;
588
589	s = intr_disable();
590	if (td == PCPU_GET(fpcurthread)) {
591		fxrstor(addr);
592		intr_restore(s);
593	} else {
594		intr_restore(s);
595		bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr));
596	}
597	curthread->td_pcb->pcb_flags |= PCB_FPUINITDONE;
598}
599
600static device_method_t fpu_methods[] = {
601	/* Device interface */
602	DEVMETHOD(device_identify,	fpu_identify),
603	DEVMETHOD(device_probe,		fpu_probe),
604	DEVMETHOD(device_attach,	fpu_attach),
605	DEVMETHOD(device_detach,	bus_generic_detach),
606	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
607	DEVMETHOD(device_suspend,	bus_generic_suspend),
608	DEVMETHOD(device_resume,	bus_generic_resume),
609
610	{ 0, 0 }
611};
612
613static driver_t fpu_driver = {
614	"fpu",
615	fpu_methods,
616	1,			/* no softc */
617};
618
619static devclass_t fpu_devclass;
620
621/*
622 * We prefer to attach to the root nexus so that the usual case (exception 16)
623 * doesn't describe the processor as being `on isa'.
624 */
625DRIVER_MODULE(fpu, nexus, fpu_driver, fpu_devclass, 0, 0);
626
627#ifdef DEV_ISA
628/*
629 * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
630 */
631static struct isa_pnp_id fpuisa_ids[] = {
632	{ 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
633	{ 0 }
634};
635
636static int
637fpuisa_probe(device_t dev)
638{
639	int result;
640
641	result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpuisa_ids);
642	if (result <= 0)
643		device_quiet(dev);
644	return (result);
645}
646
647static int
648fpuisa_attach(device_t dev)
649{
650
651	return (0);
652}
653
654static device_method_t fpuisa_methods[] = {
655	/* Device interface */
656	DEVMETHOD(device_probe,		fpuisa_probe),
657	DEVMETHOD(device_attach,	fpuisa_attach),
658	DEVMETHOD(device_detach,	bus_generic_detach),
659	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
660	DEVMETHOD(device_suspend,	bus_generic_suspend),
661	DEVMETHOD(device_resume,	bus_generic_resume),
662
663	{ 0, 0 }
664};
665
666static driver_t fpuisa_driver = {
667	"fpuisa",
668	fpuisa_methods,
669	1,			/* no softc */
670};
671
672static devclass_t fpuisa_devclass;
673
674DRIVER_MODULE(fpuisa, isa, fpuisa_driver, fpuisa_devclass, 0, 0);
675DRIVER_MODULE(fpuisa, acpi, fpuisa_driver, fpuisa_devclass, 0, 0);
676#endif /* DEV_ISA */
677