xref: /freebsd/sys/amd64/amd64/fpu.c (revision 0e33efe4e4b5d24e2d416938af8bc6e6e4160ec8)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1990 William Jolitz.
5  * Copyright (c) 1991 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	from: @(#)npx.c	7.2 (Berkeley) 5/12/91
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 #include <sys/mutex.h>
47 #include <sys/proc.h>
48 #include <sys/sysctl.h>
49 #include <machine/bus.h>
50 #include <sys/rman.h>
51 #include <sys/signalvar.h>
52 #include <vm/uma.h>
53 
54 #include <machine/cputypes.h>
55 #include <machine/frame.h>
56 #include <machine/intr_machdep.h>
57 #include <machine/md_var.h>
58 #include <machine/pcb.h>
59 #include <machine/psl.h>
60 #include <machine/resource.h>
61 #include <machine/specialreg.h>
62 #include <machine/segments.h>
63 #include <machine/ucontext.h>
64 
65 /*
66  * Floating point support.
67  */
68 
69 #if defined(__GNUCLIKE_ASM) && !defined(lint)
70 
71 #define	fldcw(cw)		__asm __volatile("fldcw %0" : : "m" (cw))
72 #define	fnclex()		__asm __volatile("fnclex")
73 #define	fninit()		__asm __volatile("fninit")
74 #define	fnstcw(addr)		__asm __volatile("fnstcw %0" : "=m" (*(addr)))
75 #define	fnstsw(addr)		__asm __volatile("fnstsw %0" : "=am" (*(addr)))
76 #define	fxrstor(addr)		__asm __volatile("fxrstor %0" : : "m" (*(addr)))
77 #define	fxsave(addr)		__asm __volatile("fxsave %0" : "=m" (*(addr)))
78 #define	ldmxcsr(csr)		__asm __volatile("ldmxcsr %0" : : "m" (csr))
79 #define	stmxcsr(addr)		__asm __volatile("stmxcsr %0" : : "m" (*(addr)))
80 
81 static __inline void
82 xrstor(char *addr, uint64_t mask)
83 {
84 	uint32_t low, hi;
85 
86 	low = mask;
87 	hi = mask >> 32;
88 	__asm __volatile("xrstor %0" : : "m" (*addr), "a" (low), "d" (hi));
89 }
90 
91 static __inline void
92 xsave(char *addr, uint64_t mask)
93 {
94 	uint32_t low, hi;
95 
96 	low = mask;
97 	hi = mask >> 32;
98 	__asm __volatile("xsave %0" : "=m" (*addr) : "a" (low), "d" (hi) :
99 	    "memory");
100 }
101 
102 #else	/* !(__GNUCLIKE_ASM && !lint) */
103 
104 void	fldcw(u_short cw);
105 void	fnclex(void);
106 void	fninit(void);
107 void	fnstcw(caddr_t addr);
108 void	fnstsw(caddr_t addr);
109 void	fxsave(caddr_t addr);
110 void	fxrstor(caddr_t addr);
111 void	ldmxcsr(u_int csr);
112 void	stmxcsr(u_int *csr);
113 void	xrstor(char *addr, uint64_t mask);
114 void	xsave(char *addr, uint64_t mask);
115 
116 #endif	/* __GNUCLIKE_ASM && !lint */
117 
118 #define	start_emulating()	load_cr0(rcr0() | CR0_TS)
119 #define	stop_emulating()	clts()
120 
121 CTASSERT(sizeof(struct savefpu) == 512);
122 CTASSERT(sizeof(struct xstate_hdr) == 64);
123 CTASSERT(sizeof(struct savefpu_ymm) == 832);
124 
125 /*
126  * This requirement is to make it easier for asm code to calculate
127  * offset of the fpu save area from the pcb address. FPU save area
128  * must be 64-byte aligned.
129  */
130 CTASSERT(sizeof(struct pcb) % XSAVE_AREA_ALIGN == 0);
131 
132 /*
133  * Ensure the copy of XCR0 saved in a core is contained in the padding
134  * area.
135  */
136 CTASSERT(X86_XSTATE_XCR0_OFFSET >= offsetof(struct savefpu, sv_pad) &&
137     X86_XSTATE_XCR0_OFFSET + sizeof(uint64_t) <= sizeof(struct savefpu));
138 
139 static	void	fpu_clean_state(void);
140 
141 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
142     SYSCTL_NULL_INT_PTR, 1, "Floating point instructions executed in hardware");
143 
144 int use_xsave;			/* non-static for cpu_switch.S */
145 uint64_t xsave_mask;		/* the same */
146 static	uma_zone_t fpu_save_area_zone;
147 static	struct savefpu *fpu_initialstate;
148 
149 struct xsave_area_elm_descr {
150 	u_int	offset;
151 	u_int	size;
152 } *xsave_area_desc;
153 
154 void
155 fpusave(void *addr)
156 {
157 
158 	if (use_xsave)
159 		xsave((char *)addr, xsave_mask);
160 	else
161 		fxsave((char *)addr);
162 }
163 
164 void
165 fpurestore(void *addr)
166 {
167 
168 	if (use_xsave)
169 		xrstor((char *)addr, xsave_mask);
170 	else
171 		fxrstor((char *)addr);
172 }
173 
174 void
175 fpususpend(void *addr)
176 {
177 	u_long cr0;
178 
179 	cr0 = rcr0();
180 	stop_emulating();
181 	fpusave(addr);
182 	load_cr0(cr0);
183 }
184 
185 void
186 fpuresume(void *addr)
187 {
188 	u_long cr0;
189 
190 	cr0 = rcr0();
191 	stop_emulating();
192 	fninit();
193 	if (use_xsave)
194 		load_xcr(XCR0, xsave_mask);
195 	fpurestore(addr);
196 	load_cr0(cr0);
197 }
198 
199 /*
200  * Enable XSAVE if supported and allowed by user.
201  * Calculate the xsave_mask.
202  */
203 static void
204 fpuinit_bsp1(void)
205 {
206 	u_int cp[4];
207 	uint64_t xsave_mask_user;
208 	bool old_wp;
209 
210 	if ((cpu_feature2 & CPUID2_XSAVE) != 0) {
211 		use_xsave = 1;
212 		TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
213 	}
214 	if (!use_xsave)
215 		return;
216 
217 	cpuid_count(0xd, 0x0, cp);
218 	xsave_mask = XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
219 	if ((cp[0] & xsave_mask) != xsave_mask)
220 		panic("CPU0 does not support X87 or SSE: %x", cp[0]);
221 	xsave_mask = ((uint64_t)cp[3] << 32) | cp[0];
222 	xsave_mask_user = xsave_mask;
223 	TUNABLE_ULONG_FETCH("hw.xsave_mask", &xsave_mask_user);
224 	xsave_mask_user |= XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
225 	xsave_mask &= xsave_mask_user;
226 	if ((xsave_mask & XFEATURE_AVX512) != XFEATURE_AVX512)
227 		xsave_mask &= ~XFEATURE_AVX512;
228 	if ((xsave_mask & XFEATURE_MPX) != XFEATURE_MPX)
229 		xsave_mask &= ~XFEATURE_MPX;
230 
231 	cpuid_count(0xd, 0x1, cp);
232 	if ((cp[0] & CPUID_EXTSTATE_XSAVEOPT) != 0) {
233 		/*
234 		 * Patch the XSAVE instruction in the cpu_switch code
235 		 * to XSAVEOPT.  We assume that XSAVE encoding used
236 		 * REX byte, and set the bit 4 of the r/m byte.
237 		 *
238 		 * It seems that some BIOSes give control to the OS
239 		 * with CR0.WP already set, making the kernel text
240 		 * read-only before cpu_startup().
241 		 */
242 		old_wp = disable_wp();
243 		ctx_switch_xsave[3] |= 0x10;
244 		restore_wp(old_wp);
245 	}
246 }
247 
248 /*
249  * Calculate the fpu save area size.
250  */
251 static void
252 fpuinit_bsp2(void)
253 {
254 	u_int cp[4];
255 
256 	if (use_xsave) {
257 		cpuid_count(0xd, 0x0, cp);
258 		cpu_max_ext_state_size = cp[1];
259 
260 		/*
261 		 * Reload the cpu_feature2, since we enabled OSXSAVE.
262 		 */
263 		do_cpuid(1, cp);
264 		cpu_feature2 = cp[2];
265 	} else
266 		cpu_max_ext_state_size = sizeof(struct savefpu);
267 }
268 
269 /*
270  * Initialize the floating point unit.
271  */
272 void
273 fpuinit(void)
274 {
275 	register_t saveintr;
276 	u_int mxcsr;
277 	u_short control;
278 
279 	if (IS_BSP())
280 		fpuinit_bsp1();
281 
282 	if (use_xsave) {
283 		load_cr4(rcr4() | CR4_XSAVE);
284 		load_xcr(XCR0, xsave_mask);
285 	}
286 
287 	/*
288 	 * XCR0 shall be set up before CPU can report the save area size.
289 	 */
290 	if (IS_BSP())
291 		fpuinit_bsp2();
292 
293 	/*
294 	 * It is too early for critical_enter() to work on AP.
295 	 */
296 	saveintr = intr_disable();
297 	stop_emulating();
298 	fninit();
299 	control = __INITIAL_FPUCW__;
300 	fldcw(control);
301 	mxcsr = __INITIAL_MXCSR__;
302 	ldmxcsr(mxcsr);
303 	start_emulating();
304 	intr_restore(saveintr);
305 }
306 
307 /*
308  * On the boot CPU we generate a clean state that is used to
309  * initialize the floating point unit when it is first used by a
310  * process.
311  */
312 static void
313 fpuinitstate(void *arg __unused)
314 {
315 	register_t saveintr;
316 	int cp[4], i, max_ext_n;
317 
318 	fpu_initialstate = malloc(cpu_max_ext_state_size, M_DEVBUF,
319 	    M_WAITOK | M_ZERO);
320 	saveintr = intr_disable();
321 	stop_emulating();
322 
323 	fpusave(fpu_initialstate);
324 	if (fpu_initialstate->sv_env.en_mxcsr_mask)
325 		cpu_mxcsr_mask = fpu_initialstate->sv_env.en_mxcsr_mask;
326 	else
327 		cpu_mxcsr_mask = 0xFFBF;
328 
329 	/*
330 	 * The fninit instruction does not modify XMM registers or x87
331 	 * registers (MM/ST).  The fpusave call dumped the garbage
332 	 * contained in the registers after reset to the initial state
333 	 * saved.  Clear XMM and x87 registers file image to make the
334 	 * startup program state and signal handler XMM/x87 register
335 	 * content predictable.
336 	 */
337 	bzero(fpu_initialstate->sv_fp, sizeof(fpu_initialstate->sv_fp));
338 	bzero(fpu_initialstate->sv_xmm, sizeof(fpu_initialstate->sv_xmm));
339 
340 	/*
341 	 * Create a table describing the layout of the CPU Extended
342 	 * Save Area.
343 	 */
344 	if (use_xsave) {
345 		max_ext_n = flsl(xsave_mask);
346 		xsave_area_desc = malloc(max_ext_n * sizeof(struct
347 		    xsave_area_elm_descr), M_DEVBUF, M_WAITOK | M_ZERO);
348 		/* x87 state */
349 		xsave_area_desc[0].offset = 0;
350 		xsave_area_desc[0].size = 160;
351 		/* XMM */
352 		xsave_area_desc[1].offset = 160;
353 		xsave_area_desc[1].size = 288 - 160;
354 
355 		for (i = 2; i < max_ext_n; i++) {
356 			cpuid_count(0xd, i, cp);
357 			xsave_area_desc[i].offset = cp[1];
358 			xsave_area_desc[i].size = cp[0];
359 		}
360 	}
361 
362 	fpu_save_area_zone = uma_zcreate("FPU_save_area",
363 	    cpu_max_ext_state_size, NULL, NULL, NULL, NULL,
364 	    XSAVE_AREA_ALIGN - 1, 0);
365 
366 	start_emulating();
367 	intr_restore(saveintr);
368 }
369 SYSINIT(fpuinitstate, SI_SUB_DRIVERS, SI_ORDER_ANY, fpuinitstate, NULL);
370 
371 /*
372  * Free coprocessor (if we have it).
373  */
374 void
375 fpuexit(struct thread *td)
376 {
377 
378 	critical_enter();
379 	if (curthread == PCPU_GET(fpcurthread)) {
380 		stop_emulating();
381 		fpusave(curpcb->pcb_save);
382 		start_emulating();
383 		PCPU_SET(fpcurthread, NULL);
384 	}
385 	critical_exit();
386 }
387 
388 int
389 fpuformat(void)
390 {
391 
392 	return (_MC_FPFMT_XMM);
393 }
394 
395 /*
396  * The following mechanism is used to ensure that the FPE_... value
397  * that is passed as a trapcode to the signal handler of the user
398  * process does not have more than one bit set.
399  *
400  * Multiple bits may be set if the user process modifies the control
401  * word while a status word bit is already set.  While this is a sign
402  * of bad coding, we have no choise than to narrow them down to one
403  * bit, since we must not send a trapcode that is not exactly one of
404  * the FPE_ macros.
405  *
406  * The mechanism has a static table with 127 entries.  Each combination
407  * of the 7 FPU status word exception bits directly translates to a
408  * position in this table, where a single FPE_... value is stored.
409  * This FPE_... value stored there is considered the "most important"
410  * of the exception bits and will be sent as the signal code.  The
411  * precedence of the bits is based upon Intel Document "Numerical
412  * Applications", Chapter "Special Computational Situations".
413  *
414  * The macro to choose one of these values does these steps: 1) Throw
415  * away status word bits that cannot be masked.  2) Throw away the bits
416  * currently masked in the control word, assuming the user isn't
417  * interested in them anymore.  3) Reinsert status word bit 7 (stack
418  * fault) if it is set, which cannot be masked but must be presered.
419  * 4) Use the remaining bits to point into the trapcode table.
420  *
421  * The 6 maskable bits in order of their preference, as stated in the
422  * above referenced Intel manual:
423  * 1  Invalid operation (FP_X_INV)
424  * 1a   Stack underflow
425  * 1b   Stack overflow
426  * 1c   Operand of unsupported format
427  * 1d   SNaN operand.
428  * 2  QNaN operand (not an exception, irrelavant here)
429  * 3  Any other invalid-operation not mentioned above or zero divide
430  *      (FP_X_INV, FP_X_DZ)
431  * 4  Denormal operand (FP_X_DNML)
432  * 5  Numeric over/underflow (FP_X_OFL, FP_X_UFL)
433  * 6  Inexact result (FP_X_IMP)
434  */
435 static char fpetable[128] = {
436 	0,
437 	FPE_FLTINV,	/*  1 - INV */
438 	FPE_FLTUND,	/*  2 - DNML */
439 	FPE_FLTINV,	/*  3 - INV | DNML */
440 	FPE_FLTDIV,	/*  4 - DZ */
441 	FPE_FLTINV,	/*  5 - INV | DZ */
442 	FPE_FLTDIV,	/*  6 - DNML | DZ */
443 	FPE_FLTINV,	/*  7 - INV | DNML | DZ */
444 	FPE_FLTOVF,	/*  8 - OFL */
445 	FPE_FLTINV,	/*  9 - INV | OFL */
446 	FPE_FLTUND,	/*  A - DNML | OFL */
447 	FPE_FLTINV,	/*  B - INV | DNML | OFL */
448 	FPE_FLTDIV,	/*  C - DZ | OFL */
449 	FPE_FLTINV,	/*  D - INV | DZ | OFL */
450 	FPE_FLTDIV,	/*  E - DNML | DZ | OFL */
451 	FPE_FLTINV,	/*  F - INV | DNML | DZ | OFL */
452 	FPE_FLTUND,	/* 10 - UFL */
453 	FPE_FLTINV,	/* 11 - INV | UFL */
454 	FPE_FLTUND,	/* 12 - DNML | UFL */
455 	FPE_FLTINV,	/* 13 - INV | DNML | UFL */
456 	FPE_FLTDIV,	/* 14 - DZ | UFL */
457 	FPE_FLTINV,	/* 15 - INV | DZ | UFL */
458 	FPE_FLTDIV,	/* 16 - DNML | DZ | UFL */
459 	FPE_FLTINV,	/* 17 - INV | DNML | DZ | UFL */
460 	FPE_FLTOVF,	/* 18 - OFL | UFL */
461 	FPE_FLTINV,	/* 19 - INV | OFL | UFL */
462 	FPE_FLTUND,	/* 1A - DNML | OFL | UFL */
463 	FPE_FLTINV,	/* 1B - INV | DNML | OFL | UFL */
464 	FPE_FLTDIV,	/* 1C - DZ | OFL | UFL */
465 	FPE_FLTINV,	/* 1D - INV | DZ | OFL | UFL */
466 	FPE_FLTDIV,	/* 1E - DNML | DZ | OFL | UFL */
467 	FPE_FLTINV,	/* 1F - INV | DNML | DZ | OFL | UFL */
468 	FPE_FLTRES,	/* 20 - IMP */
469 	FPE_FLTINV,	/* 21 - INV | IMP */
470 	FPE_FLTUND,	/* 22 - DNML | IMP */
471 	FPE_FLTINV,	/* 23 - INV | DNML | IMP */
472 	FPE_FLTDIV,	/* 24 - DZ | IMP */
473 	FPE_FLTINV,	/* 25 - INV | DZ | IMP */
474 	FPE_FLTDIV,	/* 26 - DNML | DZ | IMP */
475 	FPE_FLTINV,	/* 27 - INV | DNML | DZ | IMP */
476 	FPE_FLTOVF,	/* 28 - OFL | IMP */
477 	FPE_FLTINV,	/* 29 - INV | OFL | IMP */
478 	FPE_FLTUND,	/* 2A - DNML | OFL | IMP */
479 	FPE_FLTINV,	/* 2B - INV | DNML | OFL | IMP */
480 	FPE_FLTDIV,	/* 2C - DZ | OFL | IMP */
481 	FPE_FLTINV,	/* 2D - INV | DZ | OFL | IMP */
482 	FPE_FLTDIV,	/* 2E - DNML | DZ | OFL | IMP */
483 	FPE_FLTINV,	/* 2F - INV | DNML | DZ | OFL | IMP */
484 	FPE_FLTUND,	/* 30 - UFL | IMP */
485 	FPE_FLTINV,	/* 31 - INV | UFL | IMP */
486 	FPE_FLTUND,	/* 32 - DNML | UFL | IMP */
487 	FPE_FLTINV,	/* 33 - INV | DNML | UFL | IMP */
488 	FPE_FLTDIV,	/* 34 - DZ | UFL | IMP */
489 	FPE_FLTINV,	/* 35 - INV | DZ | UFL | IMP */
490 	FPE_FLTDIV,	/* 36 - DNML | DZ | UFL | IMP */
491 	FPE_FLTINV,	/* 37 - INV | DNML | DZ | UFL | IMP */
492 	FPE_FLTOVF,	/* 38 - OFL | UFL | IMP */
493 	FPE_FLTINV,	/* 39 - INV | OFL | UFL | IMP */
494 	FPE_FLTUND,	/* 3A - DNML | OFL | UFL | IMP */
495 	FPE_FLTINV,	/* 3B - INV | DNML | OFL | UFL | IMP */
496 	FPE_FLTDIV,	/* 3C - DZ | OFL | UFL | IMP */
497 	FPE_FLTINV,	/* 3D - INV | DZ | OFL | UFL | IMP */
498 	FPE_FLTDIV,	/* 3E - DNML | DZ | OFL | UFL | IMP */
499 	FPE_FLTINV,	/* 3F - INV | DNML | DZ | OFL | UFL | IMP */
500 	FPE_FLTSUB,	/* 40 - STK */
501 	FPE_FLTSUB,	/* 41 - INV | STK */
502 	FPE_FLTUND,	/* 42 - DNML | STK */
503 	FPE_FLTSUB,	/* 43 - INV | DNML | STK */
504 	FPE_FLTDIV,	/* 44 - DZ | STK */
505 	FPE_FLTSUB,	/* 45 - INV | DZ | STK */
506 	FPE_FLTDIV,	/* 46 - DNML | DZ | STK */
507 	FPE_FLTSUB,	/* 47 - INV | DNML | DZ | STK */
508 	FPE_FLTOVF,	/* 48 - OFL | STK */
509 	FPE_FLTSUB,	/* 49 - INV | OFL | STK */
510 	FPE_FLTUND,	/* 4A - DNML | OFL | STK */
511 	FPE_FLTSUB,	/* 4B - INV | DNML | OFL | STK */
512 	FPE_FLTDIV,	/* 4C - DZ | OFL | STK */
513 	FPE_FLTSUB,	/* 4D - INV | DZ | OFL | STK */
514 	FPE_FLTDIV,	/* 4E - DNML | DZ | OFL | STK */
515 	FPE_FLTSUB,	/* 4F - INV | DNML | DZ | OFL | STK */
516 	FPE_FLTUND,	/* 50 - UFL | STK */
517 	FPE_FLTSUB,	/* 51 - INV | UFL | STK */
518 	FPE_FLTUND,	/* 52 - DNML | UFL | STK */
519 	FPE_FLTSUB,	/* 53 - INV | DNML | UFL | STK */
520 	FPE_FLTDIV,	/* 54 - DZ | UFL | STK */
521 	FPE_FLTSUB,	/* 55 - INV | DZ | UFL | STK */
522 	FPE_FLTDIV,	/* 56 - DNML | DZ | UFL | STK */
523 	FPE_FLTSUB,	/* 57 - INV | DNML | DZ | UFL | STK */
524 	FPE_FLTOVF,	/* 58 - OFL | UFL | STK */
525 	FPE_FLTSUB,	/* 59 - INV | OFL | UFL | STK */
526 	FPE_FLTUND,	/* 5A - DNML | OFL | UFL | STK */
527 	FPE_FLTSUB,	/* 5B - INV | DNML | OFL | UFL | STK */
528 	FPE_FLTDIV,	/* 5C - DZ | OFL | UFL | STK */
529 	FPE_FLTSUB,	/* 5D - INV | DZ | OFL | UFL | STK */
530 	FPE_FLTDIV,	/* 5E - DNML | DZ | OFL | UFL | STK */
531 	FPE_FLTSUB,	/* 5F - INV | DNML | DZ | OFL | UFL | STK */
532 	FPE_FLTRES,	/* 60 - IMP | STK */
533 	FPE_FLTSUB,	/* 61 - INV | IMP | STK */
534 	FPE_FLTUND,	/* 62 - DNML | IMP | STK */
535 	FPE_FLTSUB,	/* 63 - INV | DNML | IMP | STK */
536 	FPE_FLTDIV,	/* 64 - DZ | IMP | STK */
537 	FPE_FLTSUB,	/* 65 - INV | DZ | IMP | STK */
538 	FPE_FLTDIV,	/* 66 - DNML | DZ | IMP | STK */
539 	FPE_FLTSUB,	/* 67 - INV | DNML | DZ | IMP | STK */
540 	FPE_FLTOVF,	/* 68 - OFL | IMP | STK */
541 	FPE_FLTSUB,	/* 69 - INV | OFL | IMP | STK */
542 	FPE_FLTUND,	/* 6A - DNML | OFL | IMP | STK */
543 	FPE_FLTSUB,	/* 6B - INV | DNML | OFL | IMP | STK */
544 	FPE_FLTDIV,	/* 6C - DZ | OFL | IMP | STK */
545 	FPE_FLTSUB,	/* 6D - INV | DZ | OFL | IMP | STK */
546 	FPE_FLTDIV,	/* 6E - DNML | DZ | OFL | IMP | STK */
547 	FPE_FLTSUB,	/* 6F - INV | DNML | DZ | OFL | IMP | STK */
548 	FPE_FLTUND,	/* 70 - UFL | IMP | STK */
549 	FPE_FLTSUB,	/* 71 - INV | UFL | IMP | STK */
550 	FPE_FLTUND,	/* 72 - DNML | UFL | IMP | STK */
551 	FPE_FLTSUB,	/* 73 - INV | DNML | UFL | IMP | STK */
552 	FPE_FLTDIV,	/* 74 - DZ | UFL | IMP | STK */
553 	FPE_FLTSUB,	/* 75 - INV | DZ | UFL | IMP | STK */
554 	FPE_FLTDIV,	/* 76 - DNML | DZ | UFL | IMP | STK */
555 	FPE_FLTSUB,	/* 77 - INV | DNML | DZ | UFL | IMP | STK */
556 	FPE_FLTOVF,	/* 78 - OFL | UFL | IMP | STK */
557 	FPE_FLTSUB,	/* 79 - INV | OFL | UFL | IMP | STK */
558 	FPE_FLTUND,	/* 7A - DNML | OFL | UFL | IMP | STK */
559 	FPE_FLTSUB,	/* 7B - INV | DNML | OFL | UFL | IMP | STK */
560 	FPE_FLTDIV,	/* 7C - DZ | OFL | UFL | IMP | STK */
561 	FPE_FLTSUB,	/* 7D - INV | DZ | OFL | UFL | IMP | STK */
562 	FPE_FLTDIV,	/* 7E - DNML | DZ | OFL | UFL | IMP | STK */
563 	FPE_FLTSUB,	/* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */
564 };
565 
566 /*
567  * Read the FP status and control words, then generate si_code value
568  * for SIGFPE.  The error code chosen will be one of the
569  * FPE_... macros.  It will be sent as the second argument to old
570  * BSD-style signal handlers and as "siginfo_t->si_code" (second
571  * argument) to SA_SIGINFO signal handlers.
572  *
573  * Some time ago, we cleared the x87 exceptions with FNCLEX there.
574  * Clearing exceptions was necessary mainly to avoid IRQ13 bugs.  The
575  * usermode code which understands the FPU hardware enough to enable
576  * the exceptions, can also handle clearing the exception state in the
577  * handler.  The only consequence of not clearing the exception is the
578  * rethrow of the SIGFPE on return from the signal handler and
579  * reexecution of the corresponding instruction.
580  *
581  * For XMM traps, the exceptions were never cleared.
582  */
583 int
584 fputrap_x87(void)
585 {
586 	struct savefpu *pcb_save;
587 	u_short control, status;
588 
589 	critical_enter();
590 
591 	/*
592 	 * Interrupt handling (for another interrupt) may have pushed the
593 	 * state to memory.  Fetch the relevant parts of the state from
594 	 * wherever they are.
595 	 */
596 	if (PCPU_GET(fpcurthread) != curthread) {
597 		pcb_save = curpcb->pcb_save;
598 		control = pcb_save->sv_env.en_cw;
599 		status = pcb_save->sv_env.en_sw;
600 	} else {
601 		fnstcw(&control);
602 		fnstsw(&status);
603 	}
604 
605 	critical_exit();
606 	return (fpetable[status & ((~control & 0x3f) | 0x40)]);
607 }
608 
609 int
610 fputrap_sse(void)
611 {
612 	u_int mxcsr;
613 
614 	critical_enter();
615 	if (PCPU_GET(fpcurthread) != curthread)
616 		mxcsr = curpcb->pcb_save->sv_env.en_mxcsr;
617 	else
618 		stmxcsr(&mxcsr);
619 	critical_exit();
620 	return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
621 }
622 
623 /*
624  * Device Not Available (DNA, #NM) exception handler.
625  *
626  * It would be better to switch FP context here (if curthread !=
627  * fpcurthread) and not necessarily for every context switch, but it
628  * is too hard to access foreign pcb's.
629  */
630 void
631 fpudna(void)
632 {
633 
634 	/*
635 	 * This handler is entered with interrupts enabled, so context
636 	 * switches may occur before critical_enter() is executed.  If
637 	 * a context switch occurs, then when we regain control, our
638 	 * state will have been completely restored.  The CPU may
639 	 * change underneath us, but the only part of our context that
640 	 * lives in the CPU is CR0.TS and that will be "restored" by
641 	 * setting it on the new CPU.
642 	 */
643 	critical_enter();
644 
645 	KASSERT((curpcb->pcb_flags & PCB_FPUNOSAVE) == 0,
646 	    ("fpudna while in fpu_kern_enter(FPU_KERN_NOCTX)"));
647 	if (PCPU_GET(fpcurthread) == curthread) {
648 		printf("fpudna: fpcurthread == curthread\n");
649 		stop_emulating();
650 		critical_exit();
651 		return;
652 	}
653 	if (PCPU_GET(fpcurthread) != NULL) {
654 		panic("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
655 		    PCPU_GET(fpcurthread), PCPU_GET(fpcurthread)->td_tid,
656 		    curthread, curthread->td_tid);
657 	}
658 	stop_emulating();
659 	/*
660 	 * Record new context early in case frstor causes a trap.
661 	 */
662 	PCPU_SET(fpcurthread, curthread);
663 
664 	fpu_clean_state();
665 
666 	if ((curpcb->pcb_flags & PCB_FPUINITDONE) == 0) {
667 		/*
668 		 * This is the first time this thread has used the FPU or
669 		 * the PCB doesn't contain a clean FPU state.  Explicitly
670 		 * load an initial state.
671 		 *
672 		 * We prefer to restore the state from the actual save
673 		 * area in PCB instead of directly loading from
674 		 * fpu_initialstate, to ignite the XSAVEOPT
675 		 * tracking engine.
676 		 */
677 		bcopy(fpu_initialstate, curpcb->pcb_save,
678 		    cpu_max_ext_state_size);
679 		fpurestore(curpcb->pcb_save);
680 		if (curpcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
681 			fldcw(curpcb->pcb_initial_fpucw);
682 		if (PCB_USER_FPU(curpcb))
683 			set_pcb_flags(curpcb,
684 			    PCB_FPUINITDONE | PCB_USERFPUINITDONE);
685 		else
686 			set_pcb_flags(curpcb, PCB_FPUINITDONE);
687 	} else
688 		fpurestore(curpcb->pcb_save);
689 	critical_exit();
690 }
691 
692 void
693 fpudrop(void)
694 {
695 	struct thread *td;
696 
697 	td = PCPU_GET(fpcurthread);
698 	KASSERT(td == curthread, ("fpudrop: fpcurthread != curthread"));
699 	CRITICAL_ASSERT(td);
700 	PCPU_SET(fpcurthread, NULL);
701 	clear_pcb_flags(td->td_pcb, PCB_FPUINITDONE);
702 	start_emulating();
703 }
704 
705 /*
706  * Get the user state of the FPU into pcb->pcb_user_save without
707  * dropping ownership (if possible).  It returns the FPU ownership
708  * status.
709  */
710 int
711 fpugetregs(struct thread *td)
712 {
713 	struct pcb *pcb;
714 	uint64_t *xstate_bv, bit;
715 	char *sa;
716 	int max_ext_n, i, owned;
717 
718 	pcb = td->td_pcb;
719 	if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) {
720 		bcopy(fpu_initialstate, get_pcb_user_save_pcb(pcb),
721 		    cpu_max_ext_state_size);
722 		get_pcb_user_save_pcb(pcb)->sv_env.en_cw =
723 		    pcb->pcb_initial_fpucw;
724 		fpuuserinited(td);
725 		return (_MC_FPOWNED_PCB);
726 	}
727 	critical_enter();
728 	if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
729 		fpusave(get_pcb_user_save_pcb(pcb));
730 		owned = _MC_FPOWNED_FPU;
731 	} else {
732 		owned = _MC_FPOWNED_PCB;
733 	}
734 	critical_exit();
735 	if (use_xsave) {
736 		/*
737 		 * Handle partially saved state.
738 		 */
739 		sa = (char *)get_pcb_user_save_pcb(pcb);
740 		xstate_bv = (uint64_t *)(sa + sizeof(struct savefpu) +
741 		    offsetof(struct xstate_hdr, xstate_bv));
742 		max_ext_n = flsl(xsave_mask);
743 		for (i = 0; i < max_ext_n; i++) {
744 			bit = 1ULL << i;
745 			if ((xsave_mask & bit) == 0 || (*xstate_bv & bit) != 0)
746 				continue;
747 			bcopy((char *)fpu_initialstate +
748 			    xsave_area_desc[i].offset,
749 			    sa + xsave_area_desc[i].offset,
750 			    xsave_area_desc[i].size);
751 			*xstate_bv |= bit;
752 		}
753 	}
754 	return (owned);
755 }
756 
757 void
758 fpuuserinited(struct thread *td)
759 {
760 	struct pcb *pcb;
761 
762 	pcb = td->td_pcb;
763 	if (PCB_USER_FPU(pcb))
764 		set_pcb_flags(pcb,
765 		    PCB_FPUINITDONE | PCB_USERFPUINITDONE);
766 	else
767 		set_pcb_flags(pcb, PCB_FPUINITDONE);
768 }
769 
770 int
771 fpusetxstate(struct thread *td, char *xfpustate, size_t xfpustate_size)
772 {
773 	struct xstate_hdr *hdr, *ehdr;
774 	size_t len, max_len;
775 	uint64_t bv;
776 
777 	/* XXXKIB should we clear all extended state in xstate_bv instead ? */
778 	if (xfpustate == NULL)
779 		return (0);
780 	if (!use_xsave)
781 		return (EOPNOTSUPP);
782 
783 	len = xfpustate_size;
784 	if (len < sizeof(struct xstate_hdr))
785 		return (EINVAL);
786 	max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
787 	if (len > max_len)
788 		return (EINVAL);
789 
790 	ehdr = (struct xstate_hdr *)xfpustate;
791 	bv = ehdr->xstate_bv;
792 
793 	/*
794 	 * Avoid #gp.
795 	 */
796 	if (bv & ~xsave_mask)
797 		return (EINVAL);
798 
799 	hdr = (struct xstate_hdr *)(get_pcb_user_save_td(td) + 1);
800 
801 	hdr->xstate_bv = bv;
802 	bcopy(xfpustate + sizeof(struct xstate_hdr),
803 	    (char *)(hdr + 1), len - sizeof(struct xstate_hdr));
804 
805 	return (0);
806 }
807 
808 /*
809  * Set the state of the FPU.
810  */
811 int
812 fpusetregs(struct thread *td, struct savefpu *addr, char *xfpustate,
813     size_t xfpustate_size)
814 {
815 	struct pcb *pcb;
816 	int error;
817 
818 	addr->sv_env.en_mxcsr &= cpu_mxcsr_mask;
819 	pcb = td->td_pcb;
820 	critical_enter();
821 	if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
822 		error = fpusetxstate(td, xfpustate, xfpustate_size);
823 		if (error != 0) {
824 			critical_exit();
825 			return (error);
826 		}
827 		bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
828 		fpurestore(get_pcb_user_save_td(td));
829 		critical_exit();
830 		set_pcb_flags(pcb, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
831 	} else {
832 		critical_exit();
833 		error = fpusetxstate(td, xfpustate, xfpustate_size);
834 		if (error != 0)
835 			return (error);
836 		bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
837 		fpuuserinited(td);
838 	}
839 	return (0);
840 }
841 
842 /*
843  * On AuthenticAMD processors, the fxrstor instruction does not restore
844  * the x87's stored last instruction pointer, last data pointer, and last
845  * opcode values, except in the rare case in which the exception summary
846  * (ES) bit in the x87 status word is set to 1.
847  *
848  * In order to avoid leaking this information across processes, we clean
849  * these values by performing a dummy load before executing fxrstor().
850  */
851 static void
852 fpu_clean_state(void)
853 {
854 	static float dummy_variable = 0.0;
855 	u_short status;
856 
857 	/*
858 	 * Clear the ES bit in the x87 status word if it is currently
859 	 * set, in order to avoid causing a fault in the upcoming load.
860 	 */
861 	fnstsw(&status);
862 	if (status & 0x80)
863 		fnclex();
864 
865 	/*
866 	 * Load the dummy variable into the x87 stack.  This mangles
867 	 * the x87 stack, but we don't care since we're about to call
868 	 * fxrstor() anyway.
869 	 */
870 	__asm __volatile("ffree %%st(7); flds %0" : : "m" (dummy_variable));
871 }
872 
873 /*
874  * This really sucks.  We want the acpi version only, but it requires
875  * the isa_if.h file in order to get the definitions.
876  */
877 #include "opt_isa.h"
878 #ifdef DEV_ISA
879 #include <isa/isavar.h>
880 /*
881  * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
882  */
883 static struct isa_pnp_id fpupnp_ids[] = {
884 	{ 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
885 	{ 0 }
886 };
887 
888 static int
889 fpupnp_probe(device_t dev)
890 {
891 	int result;
892 
893 	result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpupnp_ids);
894 	if (result <= 0)
895 		device_quiet(dev);
896 	return (result);
897 }
898 
899 static int
900 fpupnp_attach(device_t dev)
901 {
902 
903 	return (0);
904 }
905 
906 static device_method_t fpupnp_methods[] = {
907 	/* Device interface */
908 	DEVMETHOD(device_probe,		fpupnp_probe),
909 	DEVMETHOD(device_attach,	fpupnp_attach),
910 	DEVMETHOD(device_detach,	bus_generic_detach),
911 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
912 	DEVMETHOD(device_suspend,	bus_generic_suspend),
913 	DEVMETHOD(device_resume,	bus_generic_resume),
914 
915 	{ 0, 0 }
916 };
917 
918 static driver_t fpupnp_driver = {
919 	"fpupnp",
920 	fpupnp_methods,
921 	1,			/* no softc */
922 };
923 
924 static devclass_t fpupnp_devclass;
925 
926 DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0);
927 ISA_PNP_INFO(fpupnp_ids);
928 #endif	/* DEV_ISA */
929 
930 static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx",
931     "Kernel contexts for FPU state");
932 
933 #define	FPU_KERN_CTX_FPUINITDONE 0x01
934 #define	FPU_KERN_CTX_DUMMY	 0x02	/* avoided save for the kern thread */
935 #define	FPU_KERN_CTX_INUSE	 0x04
936 
937 struct fpu_kern_ctx {
938 	struct savefpu *prev;
939 	uint32_t flags;
940 	char hwstate1[];
941 };
942 
943 struct fpu_kern_ctx *
944 fpu_kern_alloc_ctx(u_int flags)
945 {
946 	struct fpu_kern_ctx *res;
947 	size_t sz;
948 
949 	sz = sizeof(struct fpu_kern_ctx) + XSAVE_AREA_ALIGN +
950 	    cpu_max_ext_state_size;
951 	res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ?
952 	    M_NOWAIT : M_WAITOK) | M_ZERO);
953 	return (res);
954 }
955 
956 void
957 fpu_kern_free_ctx(struct fpu_kern_ctx *ctx)
958 {
959 
960 	KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) == 0, ("free'ing inuse ctx"));
961 	/* XXXKIB clear the memory ? */
962 	free(ctx, M_FPUKERN_CTX);
963 }
964 
965 static struct savefpu *
966 fpu_kern_ctx_savefpu(struct fpu_kern_ctx *ctx)
967 {
968 	vm_offset_t p;
969 
970 	p = (vm_offset_t)&ctx->hwstate1;
971 	p = roundup2(p, XSAVE_AREA_ALIGN);
972 	return ((struct savefpu *)p);
973 }
974 
975 void
976 fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
977 {
978 	struct pcb *pcb;
979 
980 	pcb = td->td_pcb;
981 	KASSERT((flags & FPU_KERN_NOCTX) != 0 || ctx != NULL,
982 	    ("ctx is required when !FPU_KERN_NOCTX"));
983 	KASSERT(ctx == NULL || (ctx->flags & FPU_KERN_CTX_INUSE) == 0,
984 	    ("using inuse ctx"));
985 	KASSERT((pcb->pcb_flags & PCB_FPUNOSAVE) == 0,
986 	    ("recursive fpu_kern_enter while in PCB_FPUNOSAVE state"));
987 
988 	if ((flags & FPU_KERN_NOCTX) != 0) {
989 		critical_enter();
990 		stop_emulating();
991 		if (curthread == PCPU_GET(fpcurthread)) {
992 			fpusave(curpcb->pcb_save);
993 			PCPU_SET(fpcurthread, NULL);
994 		} else {
995 			KASSERT(PCPU_GET(fpcurthread) == NULL,
996 			    ("invalid fpcurthread"));
997 		}
998 
999 		/*
1000 		 * This breaks XSAVEOPT tracker, but
1001 		 * PCB_FPUNOSAVE state is supposed to never need to
1002 		 * save FPU context at all.
1003 		 */
1004 		fpurestore(fpu_initialstate);
1005 		set_pcb_flags(pcb, PCB_KERNFPU | PCB_FPUNOSAVE |
1006 		    PCB_FPUINITDONE);
1007 		return;
1008 	}
1009 	if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) {
1010 		ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE;
1011 		return;
1012 	}
1013 	KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
1014 	    get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
1015 	ctx->flags = FPU_KERN_CTX_INUSE;
1016 	if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0)
1017 		ctx->flags |= FPU_KERN_CTX_FPUINITDONE;
1018 	fpuexit(td);
1019 	ctx->prev = pcb->pcb_save;
1020 	pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
1021 	set_pcb_flags(pcb, PCB_KERNFPU);
1022 	clear_pcb_flags(pcb, PCB_FPUINITDONE);
1023 	return;
1024 }
1025 
1026 int
1027 fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
1028 {
1029 	struct pcb *pcb;
1030 
1031 	pcb = td->td_pcb;
1032 
1033 	if ((pcb->pcb_flags & PCB_FPUNOSAVE) != 0) {
1034 		KASSERT(ctx == NULL, ("non-null ctx after FPU_KERN_NOCTX"));
1035 		KASSERT(PCPU_GET(fpcurthread) == NULL,
1036 		    ("non-NULL fpcurthread for PCB_FPUNOSAVE"));
1037 		CRITICAL_ASSERT(td);
1038 
1039 		clear_pcb_flags(pcb,  PCB_FPUNOSAVE | PCB_FPUINITDONE);
1040 		start_emulating();
1041 		critical_exit();
1042 	} else {
1043 		KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0,
1044 		    ("leaving not inuse ctx"));
1045 		ctx->flags &= ~FPU_KERN_CTX_INUSE;
1046 
1047 		if (is_fpu_kern_thread(0) &&
1048 		    (ctx->flags & FPU_KERN_CTX_DUMMY) != 0)
1049 			return (0);
1050 		KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0,
1051 		    ("dummy ctx"));
1052 		critical_enter();
1053 		if (curthread == PCPU_GET(fpcurthread))
1054 			fpudrop();
1055 		critical_exit();
1056 		pcb->pcb_save = ctx->prev;
1057 	}
1058 
1059 	if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
1060 		if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) {
1061 			set_pcb_flags(pcb, PCB_FPUINITDONE);
1062 			clear_pcb_flags(pcb, PCB_KERNFPU);
1063 		} else
1064 			clear_pcb_flags(pcb, PCB_FPUINITDONE | PCB_KERNFPU);
1065 	} else {
1066 		if ((ctx->flags & FPU_KERN_CTX_FPUINITDONE) != 0)
1067 			set_pcb_flags(pcb, PCB_FPUINITDONE);
1068 		else
1069 			clear_pcb_flags(pcb, PCB_FPUINITDONE);
1070 		KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
1071 	}
1072 	return (0);
1073 }
1074 
1075 int
1076 fpu_kern_thread(u_int flags)
1077 {
1078 
1079 	KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0,
1080 	    ("Only kthread may use fpu_kern_thread"));
1081 	KASSERT(curpcb->pcb_save == get_pcb_user_save_pcb(curpcb),
1082 	    ("mangled pcb_save"));
1083 	KASSERT(PCB_USER_FPU(curpcb), ("recursive call"));
1084 
1085 	set_pcb_flags(curpcb, PCB_KERNFPU);
1086 	return (0);
1087 }
1088 
1089 int
1090 is_fpu_kern_thread(u_int flags)
1091 {
1092 
1093 	if ((curthread->td_pflags & TDP_KTHREAD) == 0)
1094 		return (0);
1095 	return ((curpcb->pcb_flags & PCB_KERNFPU) != 0);
1096 }
1097 
1098 /*
1099  * FPU save area alloc/free/init utility routines
1100  */
1101 struct savefpu *
1102 fpu_save_area_alloc(void)
1103 {
1104 
1105 	return (uma_zalloc(fpu_save_area_zone, 0));
1106 }
1107 
1108 void
1109 fpu_save_area_free(struct savefpu *fsa)
1110 {
1111 
1112 	uma_zfree(fpu_save_area_zone, fsa);
1113 }
1114 
1115 void
1116 fpu_save_area_reset(struct savefpu *fsa)
1117 {
1118 
1119 	bcopy(fpu_initialstate, fsa, cpu_max_ext_state_size);
1120 }
1121