xref: /trueos/sys/i386/isa/npx.c (revision 17d83a70d11062ccf00ec19e142b61af05794ef2)
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  * 4. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *	from: @(#)npx.c	7.2 (Berkeley) 5/12/91
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include "opt_cpu.h"
37 #include "opt_isa.h"
38 #include "opt_npx.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
48 #include <sys/mutex.h>
49 #include <sys/proc.h>
50 #include <sys/smp.h>
51 #include <sys/sysctl.h>
52 #include <machine/bus.h>
53 #include <sys/rman.h>
54 #ifdef NPX_DEBUG
55 #include <sys/syslog.h>
56 #endif
57 #include <sys/signalvar.h>
58 #include <vm/uma.h>
59 
60 #include <machine/asmacros.h>
61 #include <machine/cputypes.h>
62 #include <machine/frame.h>
63 #include <machine/md_var.h>
64 #include <machine/pcb.h>
65 #include <machine/psl.h>
66 #include <machine/resource.h>
67 #include <machine/specialreg.h>
68 #include <machine/segments.h>
69 #include <machine/ucontext.h>
70 
71 #include <machine/intr_machdep.h>
72 #ifdef XEN
73 #include <xen/xen-os.h>
74 #include <xen/hypervisor.h>
75 #endif
76 
77 #ifdef DEV_ISA
78 #include <isa/isavar.h>
79 #endif
80 
81 #if !defined(CPU_DISABLE_SSE) && defined(I686_CPU)
82 #define CPU_ENABLE_SSE
83 #endif
84 
85 /*
86  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
87  */
88 
89 #if defined(__GNUCLIKE_ASM) && !defined(lint)
90 
91 #define	fldcw(cw)		__asm __volatile("fldcw %0" : : "m" (cw))
92 #define	fnclex()		__asm __volatile("fnclex")
93 #define	fninit()		__asm __volatile("fninit")
94 #define	fnsave(addr)		__asm __volatile("fnsave %0" : "=m" (*(addr)))
95 #define	fnstcw(addr)		__asm __volatile("fnstcw %0" : "=m" (*(addr)))
96 #define	fnstsw(addr)		__asm __volatile("fnstsw %0" : "=am" (*(addr)))
97 #define	fp_divide_by_0()	__asm __volatile( \
98 				    "fldz; fld1; fdiv %st,%st(1); fnop")
99 #define	frstor(addr)		__asm __volatile("frstor %0" : : "m" (*(addr)))
100 #ifdef CPU_ENABLE_SSE
101 #define	fxrstor(addr)		__asm __volatile("fxrstor %0" : : "m" (*(addr)))
102 #define	fxsave(addr)		__asm __volatile("fxsave %0" : "=m" (*(addr)))
103 #define	ldmxcsr(csr)		__asm __volatile("ldmxcsr %0" : : "m" (csr))
104 #define	stmxcsr(addr)		__asm __volatile("stmxcsr %0" : : "m" (*(addr)))
105 
106 static __inline void
xrstor(char * addr,uint64_t mask)107 xrstor(char *addr, uint64_t mask)
108 {
109 	uint32_t low, hi;
110 
111 	low = mask;
112 	hi = mask >> 32;
113 	__asm __volatile("xrstor %0" : : "m" (*addr), "a" (low), "d" (hi));
114 }
115 
116 static __inline void
xsave(char * addr,uint64_t mask)117 xsave(char *addr, uint64_t mask)
118 {
119 	uint32_t low, hi;
120 
121 	low = mask;
122 	hi = mask >> 32;
123 	__asm __volatile("xsave %0" : "=m" (*addr) : "a" (low), "d" (hi) :
124 	    "memory");
125 }
126 
127 static __inline void
xsaveopt(char * addr,uint64_t mask)128 xsaveopt(char *addr, uint64_t mask)
129 {
130 	uint32_t low, hi;
131 
132 	low = mask;
133 	hi = mask >> 32;
134 	__asm __volatile("xsaveopt %0" : "=m" (*addr) : "a" (low), "d" (hi) :
135 	    "memory");
136 }
137 #endif
138 #else	/* !(__GNUCLIKE_ASM && !lint) */
139 
140 void	fldcw(u_short cw);
141 void	fnclex(void);
142 void	fninit(void);
143 void	fnsave(caddr_t addr);
144 void	fnstcw(caddr_t addr);
145 void	fnstsw(caddr_t addr);
146 void	fp_divide_by_0(void);
147 void	frstor(caddr_t addr);
148 #ifdef CPU_ENABLE_SSE
149 void	fxsave(caddr_t addr);
150 void	fxrstor(caddr_t addr);
151 void	ldmxcsr(u_int csr);
152 void	stmxcsr(u_int *csr);
153 void	xrstor(char *addr, uint64_t mask);
154 void	xsave(char *addr, uint64_t mask);
155 void	xsaveopt(char *addr, uint64_t mask);
156 #endif
157 
158 #endif	/* __GNUCLIKE_ASM && !lint */
159 
160 #ifdef XEN
161 #define	start_emulating()	(HYPERVISOR_fpu_taskswitch(1))
162 #define	stop_emulating()	(HYPERVISOR_fpu_taskswitch(0))
163 #else
164 #define	start_emulating()	load_cr0(rcr0() | CR0_TS)
165 #define	stop_emulating()	clts()
166 #endif
167 
168 #ifdef CPU_ENABLE_SSE
169 #define GET_FPU_CW(thread) \
170 	(cpu_fxsr ? \
171 		(thread)->td_pcb->pcb_save->sv_xmm.sv_env.en_cw : \
172 		(thread)->td_pcb->pcb_save->sv_87.sv_env.en_cw)
173 #define GET_FPU_SW(thread) \
174 	(cpu_fxsr ? \
175 		(thread)->td_pcb->pcb_save->sv_xmm.sv_env.en_sw : \
176 		(thread)->td_pcb->pcb_save->sv_87.sv_env.en_sw)
177 #define SET_FPU_CW(savefpu, value) do { \
178 	if (cpu_fxsr) \
179 		(savefpu)->sv_xmm.sv_env.en_cw = (value); \
180 	else \
181 		(savefpu)->sv_87.sv_env.en_cw = (value); \
182 } while (0)
183 #else /* CPU_ENABLE_SSE */
184 #define GET_FPU_CW(thread) \
185 	(thread->td_pcb->pcb_save->sv_87.sv_env.en_cw)
186 #define GET_FPU_SW(thread) \
187 	(thread->td_pcb->pcb_save->sv_87.sv_env.en_sw)
188 #define SET_FPU_CW(savefpu, value) \
189 	(savefpu)->sv_87.sv_env.en_cw = (value)
190 #endif /* CPU_ENABLE_SSE */
191 
192 #ifdef CPU_ENABLE_SSE
193 CTASSERT(sizeof(union savefpu) == 512);
194 CTASSERT(sizeof(struct xstate_hdr) == 64);
195 CTASSERT(sizeof(struct savefpu_ymm) == 832);
196 
197 /*
198  * This requirement is to make it easier for asm code to calculate
199  * offset of the fpu save area from the pcb address. FPU save area
200  * must be 64-byte aligned.
201  */
202 CTASSERT(sizeof(struct pcb) % XSAVE_AREA_ALIGN == 0);
203 
204 /*
205  * Ensure the copy of XCR0 saved in a core is contained in the padding
206  * area.
207  */
208 CTASSERT(X86_XSTATE_XCR0_OFFSET >= offsetof(struct savexmm, sv_pad) &&
209     X86_XSTATE_XCR0_OFFSET + sizeof(uint64_t) <= sizeof(struct savexmm));
210 
211 static	void	fpu_clean_state(void);
212 #endif
213 
214 static	void	fpusave(union savefpu *);
215 static	void	fpurstor(union savefpu *);
216 
217 int	hw_float;
218 
219 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
220     &hw_float, 0, "Floating point instructions executed in hardware");
221 
222 #ifdef CPU_ENABLE_SSE
223 int use_xsave;
224 uint64_t xsave_mask;
225 #endif
226 static	uma_zone_t fpu_save_area_zone;
227 static	union savefpu *npx_initialstate;
228 
229 #ifdef CPU_ENABLE_SSE
230 struct xsave_area_elm_descr {
231 	u_int	offset;
232 	u_int	size;
233 } *xsave_area_desc;
234 
235 static int use_xsaveopt;
236 #endif
237 
238 static	volatile u_int		npx_traps_while_probing;
239 
240 alias_for_inthand_t probetrap;
241 __asm("								\n\
242 	.text							\n\
243 	.p2align 2,0x90						\n\
244 	.type	" __XSTRING(CNAME(probetrap)) ",@function	\n\
245 " __XSTRING(CNAME(probetrap)) ":				\n\
246 	ss							\n\
247 	incl	" __XSTRING(CNAME(npx_traps_while_probing)) "	\n\
248 	fnclex							\n\
249 	iret							\n\
250 ");
251 
252 /*
253  * Determine if an FPU is present and how to use it.
254  */
255 static int
npx_probe(void)256 npx_probe(void)
257 {
258 	struct gate_descriptor save_idt_npxtrap;
259 	u_short control, status;
260 
261 	/*
262 	 * Modern CPUs all have an FPU that uses the INT16 interface
263 	 * and provide a simple way to verify that, so handle the
264 	 * common case right away.
265 	 */
266 	if (cpu_feature & CPUID_FPU) {
267 		hw_float = 1;
268 		return (1);
269 	}
270 
271 	save_idt_npxtrap = idt[IDT_MF];
272 	setidt(IDT_MF, probetrap, SDT_SYS386TGT, SEL_KPL,
273 	    GSEL(GCODE_SEL, SEL_KPL));
274 
275 	/*
276 	 * Don't trap while we're probing.
277 	 */
278 	stop_emulating();
279 
280 	/*
281 	 * Finish resetting the coprocessor, if any.  If there is an error
282 	 * pending, then we may get a bogus IRQ13, but npx_intr() will handle
283 	 * it OK.  Bogus halts have never been observed, but we enabled
284 	 * IRQ13 and cleared the BUSY# latch early to handle them anyway.
285 	 */
286 	fninit();
287 
288 	/*
289 	 * Don't use fwait here because it might hang.
290 	 * Don't use fnop here because it usually hangs if there is no FPU.
291 	 */
292 	DELAY(1000);		/* wait for any IRQ13 */
293 #ifdef DIAGNOSTIC
294 	if (npx_traps_while_probing != 0)
295 		printf("fninit caused %u bogus npx trap(s)\n",
296 		       npx_traps_while_probing);
297 #endif
298 	/*
299 	 * Check for a status of mostly zero.
300 	 */
301 	status = 0x5a5a;
302 	fnstsw(&status);
303 	if ((status & 0xb8ff) == 0) {
304 		/*
305 		 * Good, now check for a proper control word.
306 		 */
307 		control = 0x5a5a;
308 		fnstcw(&control);
309 		if ((control & 0x1f3f) == 0x033f) {
310 			/*
311 			 * We have an npx, now divide by 0 to see if exception
312 			 * 16 works.
313 			 */
314 			control &= ~(1 << 2);	/* enable divide by 0 trap */
315 			fldcw(control);
316 #ifdef FPU_ERROR_BROKEN
317 			/*
318 			 * FPU error signal doesn't work on some CPU
319 			 * accelerator board.
320 			 */
321 			hw_float = 1;
322 			return (1);
323 #endif
324 			npx_traps_while_probing = 0;
325 			fp_divide_by_0();
326 			if (npx_traps_while_probing != 0) {
327 				/*
328 				 * Good, exception 16 works.
329 				 */
330 				hw_float = 1;
331 				goto cleanup;
332 			}
333 			printf(
334 	"FPU does not use exception 16 for error reporting\n");
335 			goto cleanup;
336 		}
337 	}
338 
339 	/*
340 	 * Probe failed.  Floating point simply won't work.
341 	 * Notify user and disable FPU/MMX/SSE instruction execution.
342 	 */
343 	printf("WARNING: no FPU!\n");
344 	__asm __volatile("smsw %%ax; orb %0,%%al; lmsw %%ax" : :
345 	    "n" (CR0_EM | CR0_MP) : "ax");
346 
347 cleanup:
348 	idt[IDT_MF] = save_idt_npxtrap;
349 	return (hw_float);
350 }
351 
352 #ifdef CPU_ENABLE_SSE
353 /*
354  * Enable XSAVE if supported and allowed by user.
355  * Calculate the xsave_mask.
356  */
357 static void
npxinit_bsp1(void)358 npxinit_bsp1(void)
359 {
360 	u_int cp[4];
361 	uint64_t xsave_mask_user;
362 
363 	if (cpu_fxsr && (cpu_feature2 & CPUID2_XSAVE) != 0) {
364 		use_xsave = 1;
365 		TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
366 	}
367 	if (!use_xsave)
368 		return;
369 
370 	cpuid_count(0xd, 0x0, cp);
371 	xsave_mask = XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
372 	if ((cp[0] & xsave_mask) != xsave_mask)
373 		panic("CPU0 does not support X87 or SSE: %x", cp[0]);
374 	xsave_mask = ((uint64_t)cp[3] << 32) | cp[0];
375 	xsave_mask_user = xsave_mask;
376 	TUNABLE_QUAD_FETCH("hw.xsave_mask", &xsave_mask_user);
377 	xsave_mask_user |= XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
378 	xsave_mask &= xsave_mask_user;
379 	if ((xsave_mask & XFEATURE_AVX512) != XFEATURE_AVX512)
380 		xsave_mask &= ~XFEATURE_AVX512;
381 	if ((xsave_mask & XFEATURE_MPX) != XFEATURE_MPX)
382 		xsave_mask &= ~XFEATURE_MPX;
383 
384 	cpuid_count(0xd, 0x1, cp);
385 	if ((cp[0] & CPUID_EXTSTATE_XSAVEOPT) != 0)
386 		use_xsaveopt = 1;
387 }
388 #endif
389 /*
390 
391  * Calculate the fpu save area size.
392  */
393 static void
npxinit_bsp2(void)394 npxinit_bsp2(void)
395 {
396 #ifdef CPU_ENABLE_SSE
397 	u_int cp[4];
398 
399 	if (use_xsave) {
400 		cpuid_count(0xd, 0x0, cp);
401 		cpu_max_ext_state_size = cp[1];
402 
403 		/*
404 		 * Reload the cpu_feature2, since we enabled OSXSAVE.
405 		 */
406 		do_cpuid(1, cp);
407 		cpu_feature2 = cp[2];
408 	} else
409 #endif
410 		cpu_max_ext_state_size = sizeof(union savefpu);
411 }
412 
413 /*
414  * Initialize floating point unit.
415  */
416 void
npxinit(bool bsp)417 npxinit(bool bsp)
418 {
419 	static union savefpu dummy;
420 	register_t saveintr;
421 #ifdef CPU_ENABLE_SSE
422 	u_int mxcsr;
423 #endif
424 	u_short control;
425 
426 	if (bsp) {
427 		if (!npx_probe())
428 			return;
429 #ifdef CPU_ENABLE_SSE
430 		npxinit_bsp1();
431 #endif
432 	}
433 
434 #ifdef CPU_ENABLE_SSE
435 	if (use_xsave) {
436 		load_cr4(rcr4() | CR4_XSAVE);
437 		load_xcr(XCR0, xsave_mask);
438 	}
439 #endif
440 
441 	/*
442 	 * XCR0 shall be set up before CPU can report the save area size.
443 	 */
444 	if (bsp)
445 		npxinit_bsp2();
446 
447 	/*
448 	 * fninit has the same h/w bugs as fnsave.  Use the detoxified
449 	 * fnsave to throw away any junk in the fpu.  fpusave() initializes
450 	 * the fpu.
451 	 *
452 	 * It is too early for critical_enter() to work on AP.
453 	 */
454 	saveintr = intr_disable();
455 	stop_emulating();
456 #ifdef CPU_ENABLE_SSE
457 	if (cpu_fxsr)
458 		fninit();
459 	else
460 #endif
461 		fnsave(&dummy);
462 	control = __INITIAL_NPXCW__;
463 	fldcw(control);
464 #ifdef CPU_ENABLE_SSE
465 	if (cpu_fxsr) {
466 		mxcsr = __INITIAL_MXCSR__;
467 		ldmxcsr(mxcsr);
468 	}
469 #endif
470 	start_emulating();
471 	intr_restore(saveintr);
472 }
473 
474 /*
475  * On the boot CPU we generate a clean state that is used to
476  * initialize the floating point unit when it is first used by a
477  * process.
478  */
479 static void
npxinitstate(void * arg __unused)480 npxinitstate(void *arg __unused)
481 {
482 	register_t saveintr;
483 #ifdef CPU_ENABLE_SSE
484 	int cp[4], i, max_ext_n;
485 #endif
486 
487 	if (!hw_float)
488 		return;
489 
490 	npx_initialstate = malloc(cpu_max_ext_state_size, M_DEVBUF,
491 	    M_WAITOK | M_ZERO);
492 	saveintr = intr_disable();
493 	stop_emulating();
494 
495 	fpusave(npx_initialstate);
496 #ifdef CPU_ENABLE_SSE
497 	if (cpu_fxsr) {
498 		if (npx_initialstate->sv_xmm.sv_env.en_mxcsr_mask)
499 			cpu_mxcsr_mask =
500 			    npx_initialstate->sv_xmm.sv_env.en_mxcsr_mask;
501 		else
502 			cpu_mxcsr_mask = 0xFFBF;
503 
504 		/*
505 		 * The fninit instruction does not modify XMM
506 		 * registers.  The fpusave call dumped the garbage
507 		 * contained in the registers after reset to the
508 		 * initial state saved.  Clear XMM registers file
509 		 * image to make the startup program state and signal
510 		 * handler XMM register content predictable.
511 		 */
512 		bzero(npx_initialstate->sv_xmm.sv_fp,
513 		    sizeof(npx_initialstate->sv_xmm.sv_fp));
514 		bzero(npx_initialstate->sv_xmm.sv_xmm,
515 		    sizeof(npx_initialstate->sv_xmm.sv_xmm));
516 	} else
517 #endif
518 		bzero(npx_initialstate->sv_87.sv_ac,
519 		    sizeof(npx_initialstate->sv_87.sv_ac));
520 
521 #ifdef CPU_ENABLE_SSE
522 	/*
523 	 * Create a table describing the layout of the CPU Extended
524 	 * Save Area.
525 	 */
526 	if (use_xsave) {
527 		if (xsave_mask >> 32 != 0)
528 			max_ext_n = fls(xsave_mask >> 32) + 32;
529 		else
530 			max_ext_n = fls(xsave_mask);
531 		xsave_area_desc = malloc(max_ext_n * sizeof(struct
532 		    xsave_area_elm_descr), M_DEVBUF, M_WAITOK | M_ZERO);
533 		/* x87 state */
534 		xsave_area_desc[0].offset = 0;
535 		xsave_area_desc[0].size = 160;
536 		/* XMM */
537 		xsave_area_desc[1].offset = 160;
538 		xsave_area_desc[1].size = 288 - 160;
539 
540 		for (i = 2; i < max_ext_n; i++) {
541 			cpuid_count(0xd, i, cp);
542 			xsave_area_desc[i].offset = cp[1];
543 			xsave_area_desc[i].size = cp[0];
544 		}
545 	}
546 #endif
547 
548 	fpu_save_area_zone = uma_zcreate("FPU_save_area",
549 	    cpu_max_ext_state_size, NULL, NULL, NULL, NULL,
550 	    XSAVE_AREA_ALIGN - 1, 0);
551 
552 	start_emulating();
553 	intr_restore(saveintr);
554 }
555 SYSINIT(npxinitstate, SI_SUB_DRIVERS, SI_ORDER_ANY, npxinitstate, NULL);
556 
557 /*
558  * Free coprocessor (if we have it).
559  */
560 void
npxexit(td)561 npxexit(td)
562 	struct thread *td;
563 {
564 
565 	critical_enter();
566 	if (curthread == PCPU_GET(fpcurthread)) {
567 		stop_emulating();
568 		fpusave(curpcb->pcb_save);
569 		start_emulating();
570 		PCPU_SET(fpcurthread, NULL);
571 	}
572 	critical_exit();
573 #ifdef NPX_DEBUG
574 	if (hw_float) {
575 		u_int	masked_exceptions;
576 
577 		masked_exceptions = GET_FPU_CW(td) & GET_FPU_SW(td) & 0x7f;
578 		/*
579 		 * Log exceptions that would have trapped with the old
580 		 * control word (overflow, divide by 0, and invalid operand).
581 		 */
582 		if (masked_exceptions & 0x0d)
583 			log(LOG_ERR,
584 	"pid %d (%s) exited with masked floating point exceptions 0x%02x\n",
585 			    td->td_proc->p_pid, td->td_proc->p_comm,
586 			    masked_exceptions);
587 	}
588 #endif
589 }
590 
591 int
npxformat()592 npxformat()
593 {
594 
595 	if (!hw_float)
596 		return (_MC_FPFMT_NODEV);
597 #ifdef	CPU_ENABLE_SSE
598 	if (cpu_fxsr)
599 		return (_MC_FPFMT_XMM);
600 #endif
601 	return (_MC_FPFMT_387);
602 }
603 
604 /*
605  * The following mechanism is used to ensure that the FPE_... value
606  * that is passed as a trapcode to the signal handler of the user
607  * process does not have more than one bit set.
608  *
609  * Multiple bits may be set if the user process modifies the control
610  * word while a status word bit is already set.  While this is a sign
611  * of bad coding, we have no choise than to narrow them down to one
612  * bit, since we must not send a trapcode that is not exactly one of
613  * the FPE_ macros.
614  *
615  * The mechanism has a static table with 127 entries.  Each combination
616  * of the 7 FPU status word exception bits directly translates to a
617  * position in this table, where a single FPE_... value is stored.
618  * This FPE_... value stored there is considered the "most important"
619  * of the exception bits and will be sent as the signal code.  The
620  * precedence of the bits is based upon Intel Document "Numerical
621  * Applications", Chapter "Special Computational Situations".
622  *
623  * The macro to choose one of these values does these steps: 1) Throw
624  * away status word bits that cannot be masked.  2) Throw away the bits
625  * currently masked in the control word, assuming the user isn't
626  * interested in them anymore.  3) Reinsert status word bit 7 (stack
627  * fault) if it is set, which cannot be masked but must be presered.
628  * 4) Use the remaining bits to point into the trapcode table.
629  *
630  * The 6 maskable bits in order of their preference, as stated in the
631  * above referenced Intel manual:
632  * 1  Invalid operation (FP_X_INV)
633  * 1a   Stack underflow
634  * 1b   Stack overflow
635  * 1c   Operand of unsupported format
636  * 1d   SNaN operand.
637  * 2  QNaN operand (not an exception, irrelavant here)
638  * 3  Any other invalid-operation not mentioned above or zero divide
639  *      (FP_X_INV, FP_X_DZ)
640  * 4  Denormal operand (FP_X_DNML)
641  * 5  Numeric over/underflow (FP_X_OFL, FP_X_UFL)
642  * 6  Inexact result (FP_X_IMP)
643  */
644 static char fpetable[128] = {
645 	0,
646 	FPE_FLTINV,	/*  1 - INV */
647 	FPE_FLTUND,	/*  2 - DNML */
648 	FPE_FLTINV,	/*  3 - INV | DNML */
649 	FPE_FLTDIV,	/*  4 - DZ */
650 	FPE_FLTINV,	/*  5 - INV | DZ */
651 	FPE_FLTDIV,	/*  6 - DNML | DZ */
652 	FPE_FLTINV,	/*  7 - INV | DNML | DZ */
653 	FPE_FLTOVF,	/*  8 - OFL */
654 	FPE_FLTINV,	/*  9 - INV | OFL */
655 	FPE_FLTUND,	/*  A - DNML | OFL */
656 	FPE_FLTINV,	/*  B - INV | DNML | OFL */
657 	FPE_FLTDIV,	/*  C - DZ | OFL */
658 	FPE_FLTINV,	/*  D - INV | DZ | OFL */
659 	FPE_FLTDIV,	/*  E - DNML | DZ | OFL */
660 	FPE_FLTINV,	/*  F - INV | DNML | DZ | OFL */
661 	FPE_FLTUND,	/* 10 - UFL */
662 	FPE_FLTINV,	/* 11 - INV | UFL */
663 	FPE_FLTUND,	/* 12 - DNML | UFL */
664 	FPE_FLTINV,	/* 13 - INV | DNML | UFL */
665 	FPE_FLTDIV,	/* 14 - DZ | UFL */
666 	FPE_FLTINV,	/* 15 - INV | DZ | UFL */
667 	FPE_FLTDIV,	/* 16 - DNML | DZ | UFL */
668 	FPE_FLTINV,	/* 17 - INV | DNML | DZ | UFL */
669 	FPE_FLTOVF,	/* 18 - OFL | UFL */
670 	FPE_FLTINV,	/* 19 - INV | OFL | UFL */
671 	FPE_FLTUND,	/* 1A - DNML | OFL | UFL */
672 	FPE_FLTINV,	/* 1B - INV | DNML | OFL | UFL */
673 	FPE_FLTDIV,	/* 1C - DZ | OFL | UFL */
674 	FPE_FLTINV,	/* 1D - INV | DZ | OFL | UFL */
675 	FPE_FLTDIV,	/* 1E - DNML | DZ | OFL | UFL */
676 	FPE_FLTINV,	/* 1F - INV | DNML | DZ | OFL | UFL */
677 	FPE_FLTRES,	/* 20 - IMP */
678 	FPE_FLTINV,	/* 21 - INV | IMP */
679 	FPE_FLTUND,	/* 22 - DNML | IMP */
680 	FPE_FLTINV,	/* 23 - INV | DNML | IMP */
681 	FPE_FLTDIV,	/* 24 - DZ | IMP */
682 	FPE_FLTINV,	/* 25 - INV | DZ | IMP */
683 	FPE_FLTDIV,	/* 26 - DNML | DZ | IMP */
684 	FPE_FLTINV,	/* 27 - INV | DNML | DZ | IMP */
685 	FPE_FLTOVF,	/* 28 - OFL | IMP */
686 	FPE_FLTINV,	/* 29 - INV | OFL | IMP */
687 	FPE_FLTUND,	/* 2A - DNML | OFL | IMP */
688 	FPE_FLTINV,	/* 2B - INV | DNML | OFL | IMP */
689 	FPE_FLTDIV,	/* 2C - DZ | OFL | IMP */
690 	FPE_FLTINV,	/* 2D - INV | DZ | OFL | IMP */
691 	FPE_FLTDIV,	/* 2E - DNML | DZ | OFL | IMP */
692 	FPE_FLTINV,	/* 2F - INV | DNML | DZ | OFL | IMP */
693 	FPE_FLTUND,	/* 30 - UFL | IMP */
694 	FPE_FLTINV,	/* 31 - INV | UFL | IMP */
695 	FPE_FLTUND,	/* 32 - DNML | UFL | IMP */
696 	FPE_FLTINV,	/* 33 - INV | DNML | UFL | IMP */
697 	FPE_FLTDIV,	/* 34 - DZ | UFL | IMP */
698 	FPE_FLTINV,	/* 35 - INV | DZ | UFL | IMP */
699 	FPE_FLTDIV,	/* 36 - DNML | DZ | UFL | IMP */
700 	FPE_FLTINV,	/* 37 - INV | DNML | DZ | UFL | IMP */
701 	FPE_FLTOVF,	/* 38 - OFL | UFL | IMP */
702 	FPE_FLTINV,	/* 39 - INV | OFL | UFL | IMP */
703 	FPE_FLTUND,	/* 3A - DNML | OFL | UFL | IMP */
704 	FPE_FLTINV,	/* 3B - INV | DNML | OFL | UFL | IMP */
705 	FPE_FLTDIV,	/* 3C - DZ | OFL | UFL | IMP */
706 	FPE_FLTINV,	/* 3D - INV | DZ | OFL | UFL | IMP */
707 	FPE_FLTDIV,	/* 3E - DNML | DZ | OFL | UFL | IMP */
708 	FPE_FLTINV,	/* 3F - INV | DNML | DZ | OFL | UFL | IMP */
709 	FPE_FLTSUB,	/* 40 - STK */
710 	FPE_FLTSUB,	/* 41 - INV | STK */
711 	FPE_FLTUND,	/* 42 - DNML | STK */
712 	FPE_FLTSUB,	/* 43 - INV | DNML | STK */
713 	FPE_FLTDIV,	/* 44 - DZ | STK */
714 	FPE_FLTSUB,	/* 45 - INV | DZ | STK */
715 	FPE_FLTDIV,	/* 46 - DNML | DZ | STK */
716 	FPE_FLTSUB,	/* 47 - INV | DNML | DZ | STK */
717 	FPE_FLTOVF,	/* 48 - OFL | STK */
718 	FPE_FLTSUB,	/* 49 - INV | OFL | STK */
719 	FPE_FLTUND,	/* 4A - DNML | OFL | STK */
720 	FPE_FLTSUB,	/* 4B - INV | DNML | OFL | STK */
721 	FPE_FLTDIV,	/* 4C - DZ | OFL | STK */
722 	FPE_FLTSUB,	/* 4D - INV | DZ | OFL | STK */
723 	FPE_FLTDIV,	/* 4E - DNML | DZ | OFL | STK */
724 	FPE_FLTSUB,	/* 4F - INV | DNML | DZ | OFL | STK */
725 	FPE_FLTUND,	/* 50 - UFL | STK */
726 	FPE_FLTSUB,	/* 51 - INV | UFL | STK */
727 	FPE_FLTUND,	/* 52 - DNML | UFL | STK */
728 	FPE_FLTSUB,	/* 53 - INV | DNML | UFL | STK */
729 	FPE_FLTDIV,	/* 54 - DZ | UFL | STK */
730 	FPE_FLTSUB,	/* 55 - INV | DZ | UFL | STK */
731 	FPE_FLTDIV,	/* 56 - DNML | DZ | UFL | STK */
732 	FPE_FLTSUB,	/* 57 - INV | DNML | DZ | UFL | STK */
733 	FPE_FLTOVF,	/* 58 - OFL | UFL | STK */
734 	FPE_FLTSUB,	/* 59 - INV | OFL | UFL | STK */
735 	FPE_FLTUND,	/* 5A - DNML | OFL | UFL | STK */
736 	FPE_FLTSUB,	/* 5B - INV | DNML | OFL | UFL | STK */
737 	FPE_FLTDIV,	/* 5C - DZ | OFL | UFL | STK */
738 	FPE_FLTSUB,	/* 5D - INV | DZ | OFL | UFL | STK */
739 	FPE_FLTDIV,	/* 5E - DNML | DZ | OFL | UFL | STK */
740 	FPE_FLTSUB,	/* 5F - INV | DNML | DZ | OFL | UFL | STK */
741 	FPE_FLTRES,	/* 60 - IMP | STK */
742 	FPE_FLTSUB,	/* 61 - INV | IMP | STK */
743 	FPE_FLTUND,	/* 62 - DNML | IMP | STK */
744 	FPE_FLTSUB,	/* 63 - INV | DNML | IMP | STK */
745 	FPE_FLTDIV,	/* 64 - DZ | IMP | STK */
746 	FPE_FLTSUB,	/* 65 - INV | DZ | IMP | STK */
747 	FPE_FLTDIV,	/* 66 - DNML | DZ | IMP | STK */
748 	FPE_FLTSUB,	/* 67 - INV | DNML | DZ | IMP | STK */
749 	FPE_FLTOVF,	/* 68 - OFL | IMP | STK */
750 	FPE_FLTSUB,	/* 69 - INV | OFL | IMP | STK */
751 	FPE_FLTUND,	/* 6A - DNML | OFL | IMP | STK */
752 	FPE_FLTSUB,	/* 6B - INV | DNML | OFL | IMP | STK */
753 	FPE_FLTDIV,	/* 6C - DZ | OFL | IMP | STK */
754 	FPE_FLTSUB,	/* 6D - INV | DZ | OFL | IMP | STK */
755 	FPE_FLTDIV,	/* 6E - DNML | DZ | OFL | IMP | STK */
756 	FPE_FLTSUB,	/* 6F - INV | DNML | DZ | OFL | IMP | STK */
757 	FPE_FLTUND,	/* 70 - UFL | IMP | STK */
758 	FPE_FLTSUB,	/* 71 - INV | UFL | IMP | STK */
759 	FPE_FLTUND,	/* 72 - DNML | UFL | IMP | STK */
760 	FPE_FLTSUB,	/* 73 - INV | DNML | UFL | IMP | STK */
761 	FPE_FLTDIV,	/* 74 - DZ | UFL | IMP | STK */
762 	FPE_FLTSUB,	/* 75 - INV | DZ | UFL | IMP | STK */
763 	FPE_FLTDIV,	/* 76 - DNML | DZ | UFL | IMP | STK */
764 	FPE_FLTSUB,	/* 77 - INV | DNML | DZ | UFL | IMP | STK */
765 	FPE_FLTOVF,	/* 78 - OFL | UFL | IMP | STK */
766 	FPE_FLTSUB,	/* 79 - INV | OFL | UFL | IMP | STK */
767 	FPE_FLTUND,	/* 7A - DNML | OFL | UFL | IMP | STK */
768 	FPE_FLTSUB,	/* 7B - INV | DNML | OFL | UFL | IMP | STK */
769 	FPE_FLTDIV,	/* 7C - DZ | OFL | UFL | IMP | STK */
770 	FPE_FLTSUB,	/* 7D - INV | DZ | OFL | UFL | IMP | STK */
771 	FPE_FLTDIV,	/* 7E - DNML | DZ | OFL | UFL | IMP | STK */
772 	FPE_FLTSUB,	/* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */
773 };
774 
775 /*
776  * Read the FP status and control words, then generate si_code value
777  * for SIGFPE.  The error code chosen will be one of the
778  * FPE_... macros.  It will be sent as the second argument to old
779  * BSD-style signal handlers and as "siginfo_t->si_code" (second
780  * argument) to SA_SIGINFO signal handlers.
781  *
782  * Some time ago, we cleared the x87 exceptions with FNCLEX there.
783  * Clearing exceptions was necessary mainly to avoid IRQ13 bugs.  The
784  * usermode code which understands the FPU hardware enough to enable
785  * the exceptions, can also handle clearing the exception state in the
786  * handler.  The only consequence of not clearing the exception is the
787  * rethrow of the SIGFPE on return from the signal handler and
788  * reexecution of the corresponding instruction.
789  *
790  * For XMM traps, the exceptions were never cleared.
791  */
792 int
npxtrap_x87(void)793 npxtrap_x87(void)
794 {
795 	u_short control, status;
796 
797 	if (!hw_float) {
798 		printf(
799 	"npxtrap_x87: fpcurthread = %p, curthread = %p, hw_float = %d\n",
800 		       PCPU_GET(fpcurthread), curthread, hw_float);
801 		panic("npxtrap from nowhere");
802 	}
803 	critical_enter();
804 
805 	/*
806 	 * Interrupt handling (for another interrupt) may have pushed the
807 	 * state to memory.  Fetch the relevant parts of the state from
808 	 * wherever they are.
809 	 */
810 	if (PCPU_GET(fpcurthread) != curthread) {
811 		control = GET_FPU_CW(curthread);
812 		status = GET_FPU_SW(curthread);
813 	} else {
814 		fnstcw(&control);
815 		fnstsw(&status);
816 	}
817 	critical_exit();
818 	return (fpetable[status & ((~control & 0x3f) | 0x40)]);
819 }
820 
821 #ifdef CPU_ENABLE_SSE
822 int
npxtrap_sse(void)823 npxtrap_sse(void)
824 {
825 	u_int mxcsr;
826 
827 	if (!hw_float) {
828 		printf(
829 	"npxtrap_sse: fpcurthread = %p, curthread = %p, hw_float = %d\n",
830 		       PCPU_GET(fpcurthread), curthread, hw_float);
831 		panic("npxtrap from nowhere");
832 	}
833 	critical_enter();
834 	if (PCPU_GET(fpcurthread) != curthread)
835 		mxcsr = curthread->td_pcb->pcb_save->sv_xmm.sv_env.en_mxcsr;
836 	else
837 		stmxcsr(&mxcsr);
838 	critical_exit();
839 	return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
840 }
841 #endif
842 
843 /*
844  * Implement device not available (DNA) exception
845  *
846  * It would be better to switch FP context here (if curthread != fpcurthread)
847  * and not necessarily for every context switch, but it is too hard to
848  * access foreign pcb's.
849  */
850 
851 static int err_count = 0;
852 
853 int
npxdna(void)854 npxdna(void)
855 {
856 
857 	if (!hw_float)
858 		return (0);
859 	critical_enter();
860 	if (PCPU_GET(fpcurthread) == curthread) {
861 		printf("npxdna: fpcurthread == curthread %d times\n",
862 		    ++err_count);
863 		stop_emulating();
864 		critical_exit();
865 		return (1);
866 	}
867 	if (PCPU_GET(fpcurthread) != NULL) {
868 		printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
869 		       PCPU_GET(fpcurthread),
870 		       PCPU_GET(fpcurthread)->td_proc->p_pid,
871 		       curthread, curthread->td_proc->p_pid);
872 		panic("npxdna");
873 	}
874 	stop_emulating();
875 	/*
876 	 * Record new context early in case frstor causes a trap.
877 	 */
878 	PCPU_SET(fpcurthread, curthread);
879 
880 #ifdef CPU_ENABLE_SSE
881 	if (cpu_fxsr)
882 		fpu_clean_state();
883 #endif
884 
885 	if ((curpcb->pcb_flags & PCB_NPXINITDONE) == 0) {
886 		/*
887 		 * This is the first time this thread has used the FPU or
888 		 * the PCB doesn't contain a clean FPU state.  Explicitly
889 		 * load an initial state.
890 		 *
891 		 * We prefer to restore the state from the actual save
892 		 * area in PCB instead of directly loading from
893 		 * npx_initialstate, to ignite the XSAVEOPT
894 		 * tracking engine.
895 		 */
896 		bcopy(npx_initialstate, curpcb->pcb_save, cpu_max_ext_state_size);
897 		fpurstor(curpcb->pcb_save);
898 		if (curpcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
899 			fldcw(curpcb->pcb_initial_npxcw);
900 		curpcb->pcb_flags |= PCB_NPXINITDONE;
901 		if (PCB_USER_FPU(curpcb))
902 			curpcb->pcb_flags |= PCB_NPXUSERINITDONE;
903 	} else {
904 		fpurstor(curpcb->pcb_save);
905 	}
906 	critical_exit();
907 
908 	return (1);
909 }
910 
911 /*
912  * Wrapper for fpusave() called from context switch routines.
913  *
914  * npxsave() must be called with interrupts disabled, so that it clears
915  * fpcurthread atomically with saving the state.  We require callers to do the
916  * disabling, since most callers need to disable interrupts anyway to call
917  * npxsave() atomically with checking fpcurthread.
918  */
919 void
npxsave(addr)920 npxsave(addr)
921 	union savefpu *addr;
922 {
923 
924 	stop_emulating();
925 #ifdef CPU_ENABLE_SSE
926 	if (use_xsaveopt)
927 		xsaveopt((char *)addr, xsave_mask);
928 	else
929 #endif
930 		fpusave(addr);
931 	start_emulating();
932 	PCPU_SET(fpcurthread, NULL);
933 }
934 
935 /*
936  * Unconditionally save the current co-processor state across suspend and
937  * resume.
938  */
939 void
npxsuspend(union savefpu * addr)940 npxsuspend(union savefpu *addr)
941 {
942 	register_t cr0;
943 
944 	if (!hw_float)
945 		return;
946 	if (PCPU_GET(fpcurthread) == NULL) {
947 		bcopy(npx_initialstate, addr, cpu_max_ext_state_size);
948 		return;
949 	}
950 	cr0 = rcr0();
951 	stop_emulating();
952 	fpusave(addr);
953 	load_cr0(cr0);
954 }
955 
956 void
npxresume(union savefpu * addr)957 npxresume(union savefpu *addr)
958 {
959 	register_t cr0;
960 
961 	if (!hw_float)
962 		return;
963 
964 	cr0 = rcr0();
965 	npxinit(false);
966 	stop_emulating();
967 	fpurstor(addr);
968 	load_cr0(cr0);
969 }
970 
971 void
npxdrop()972 npxdrop()
973 {
974 	struct thread *td;
975 
976 	/*
977 	 * Discard pending exceptions in the !cpu_fxsr case so that unmasked
978 	 * ones don't cause a panic on the next frstor.
979 	 */
980 #ifdef CPU_ENABLE_SSE
981 	if (!cpu_fxsr)
982 #endif
983 		fnclex();
984 
985 	td = PCPU_GET(fpcurthread);
986 	KASSERT(td == curthread, ("fpudrop: fpcurthread != curthread"));
987 	CRITICAL_ASSERT(td);
988 	PCPU_SET(fpcurthread, NULL);
989 	td->td_pcb->pcb_flags &= ~PCB_NPXINITDONE;
990 	start_emulating();
991 }
992 
993 /*
994  * Get the user state of the FPU into pcb->pcb_user_save without
995  * dropping ownership (if possible).  It returns the FPU ownership
996  * status.
997  */
998 int
npxgetregs(struct thread * td)999 npxgetregs(struct thread *td)
1000 {
1001 	struct pcb *pcb;
1002 #ifdef CPU_ENABLE_SSE
1003 	uint64_t *xstate_bv, bit;
1004 	char *sa;
1005 	int max_ext_n, i;
1006 #endif
1007 	int owned;
1008 
1009 	if (!hw_float)
1010 		return (_MC_FPOWNED_NONE);
1011 
1012 	pcb = td->td_pcb;
1013 	if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
1014 		bcopy(npx_initialstate, get_pcb_user_save_pcb(pcb),
1015 		    cpu_max_ext_state_size);
1016 		SET_FPU_CW(get_pcb_user_save_pcb(pcb), pcb->pcb_initial_npxcw);
1017 		npxuserinited(td);
1018 		return (_MC_FPOWNED_PCB);
1019 	}
1020 	critical_enter();
1021 	if (td == PCPU_GET(fpcurthread)) {
1022 		fpusave(get_pcb_user_save_pcb(pcb));
1023 #ifdef CPU_ENABLE_SSE
1024 		if (!cpu_fxsr)
1025 #endif
1026 			/*
1027 			 * fnsave initializes the FPU and destroys whatever
1028 			 * context it contains.  Make sure the FPU owner
1029 			 * starts with a clean state next time.
1030 			 */
1031 			npxdrop();
1032 		owned = _MC_FPOWNED_FPU;
1033 	} else {
1034 		owned = _MC_FPOWNED_PCB;
1035 	}
1036 	critical_exit();
1037 #ifdef CPU_ENABLE_SSE
1038 	if (use_xsave) {
1039 		/*
1040 		 * Handle partially saved state.
1041 		 */
1042 		sa = (char *)get_pcb_user_save_pcb(pcb);
1043 		xstate_bv = (uint64_t *)(sa + sizeof(union savefpu) +
1044 		    offsetof(struct xstate_hdr, xstate_bv));
1045 		if (xsave_mask >> 32 != 0)
1046 			max_ext_n = fls(xsave_mask >> 32) + 32;
1047 		else
1048 			max_ext_n = fls(xsave_mask);
1049 		for (i = 0; i < max_ext_n; i++) {
1050 			bit = 1ULL << i;
1051 			if ((xsave_mask & bit) == 0 || (*xstate_bv & bit) != 0)
1052 				continue;
1053 			bcopy((char *)npx_initialstate +
1054 			    xsave_area_desc[i].offset,
1055 			    sa + xsave_area_desc[i].offset,
1056 			    xsave_area_desc[i].size);
1057 			*xstate_bv |= bit;
1058 		}
1059 	}
1060 #endif
1061 	return (owned);
1062 }
1063 
1064 void
npxuserinited(struct thread * td)1065 npxuserinited(struct thread *td)
1066 {
1067 	struct pcb *pcb;
1068 
1069 	pcb = td->td_pcb;
1070 	if (PCB_USER_FPU(pcb))
1071 		pcb->pcb_flags |= PCB_NPXINITDONE;
1072 	pcb->pcb_flags |= PCB_NPXUSERINITDONE;
1073 }
1074 
1075 #ifdef CPU_ENABLE_SSE
1076 int
npxsetxstate(struct thread * td,char * xfpustate,size_t xfpustate_size)1077 npxsetxstate(struct thread *td, char *xfpustate, size_t xfpustate_size)
1078 {
1079 	struct xstate_hdr *hdr, *ehdr;
1080 	size_t len, max_len;
1081 	uint64_t bv;
1082 
1083 	/* XXXKIB should we clear all extended state in xstate_bv instead ? */
1084 	if (xfpustate == NULL)
1085 		return (0);
1086 	if (!use_xsave)
1087 		return (EOPNOTSUPP);
1088 
1089 	len = xfpustate_size;
1090 	if (len < sizeof(struct xstate_hdr))
1091 		return (EINVAL);
1092 	max_len = cpu_max_ext_state_size - sizeof(union savefpu);
1093 	if (len > max_len)
1094 		return (EINVAL);
1095 
1096 	ehdr = (struct xstate_hdr *)xfpustate;
1097 	bv = ehdr->xstate_bv;
1098 
1099 	/*
1100 	 * Avoid #gp.
1101 	 */
1102 	if (bv & ~xsave_mask)
1103 		return (EINVAL);
1104 
1105 	hdr = (struct xstate_hdr *)(get_pcb_user_save_td(td) + 1);
1106 
1107 	hdr->xstate_bv = bv;
1108 	bcopy(xfpustate + sizeof(struct xstate_hdr),
1109 	    (char *)(hdr + 1), len - sizeof(struct xstate_hdr));
1110 
1111 	return (0);
1112 }
1113 #endif
1114 
1115 int
npxsetregs(struct thread * td,union savefpu * addr,char * xfpustate,size_t xfpustate_size)1116 npxsetregs(struct thread *td, union savefpu *addr, char *xfpustate,
1117 	size_t xfpustate_size)
1118 {
1119 	struct pcb *pcb;
1120 #ifdef CPU_ENABLE_SSE
1121 	int error;
1122 #endif
1123 
1124 	if (!hw_float)
1125 		return (ENXIO);
1126 
1127 	pcb = td->td_pcb;
1128 	critical_enter();
1129 	if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
1130 #ifdef CPU_ENABLE_SSE
1131 		error = npxsetxstate(td, xfpustate, xfpustate_size);
1132 		if (error != 0) {
1133 			critical_exit();
1134 			return (error);
1135 		}
1136 		if (!cpu_fxsr)
1137 #endif
1138 			fnclex();	/* As in npxdrop(). */
1139 		bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
1140 		fpurstor(get_pcb_user_save_td(td));
1141 		critical_exit();
1142 		pcb->pcb_flags |= PCB_NPXUSERINITDONE | PCB_NPXINITDONE;
1143 	} else {
1144 		critical_exit();
1145 #ifdef CPU_ENABLE_SSE
1146 		error = npxsetxstate(td, xfpustate, xfpustate_size);
1147 		if (error != 0)
1148 			return (error);
1149 #endif
1150 		bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
1151 		npxuserinited(td);
1152 	}
1153 	return (0);
1154 }
1155 
1156 static void
fpusave(addr)1157 fpusave(addr)
1158 	union savefpu *addr;
1159 {
1160 
1161 #ifdef CPU_ENABLE_SSE
1162 	if (use_xsave)
1163 		xsave((char *)addr, xsave_mask);
1164 	else if (cpu_fxsr)
1165 		fxsave(addr);
1166 	else
1167 #endif
1168 		fnsave(addr);
1169 }
1170 
1171 #ifdef CPU_ENABLE_SSE
1172 /*
1173  * On AuthenticAMD processors, the fxrstor instruction does not restore
1174  * the x87's stored last instruction pointer, last data pointer, and last
1175  * opcode values, except in the rare case in which the exception summary
1176  * (ES) bit in the x87 status word is set to 1.
1177  *
1178  * In order to avoid leaking this information across processes, we clean
1179  * these values by performing a dummy load before executing fxrstor().
1180  */
1181 static void
fpu_clean_state(void)1182 fpu_clean_state(void)
1183 {
1184 	static float dummy_variable = 0.0;
1185 	u_short status;
1186 
1187 	/*
1188 	 * Clear the ES bit in the x87 status word if it is currently
1189 	 * set, in order to avoid causing a fault in the upcoming load.
1190 	 */
1191 	fnstsw(&status);
1192 	if (status & 0x80)
1193 		fnclex();
1194 
1195 	/*
1196 	 * Load the dummy variable into the x87 stack.  This mangles
1197 	 * the x87 stack, but we don't care since we're about to call
1198 	 * fxrstor() anyway.
1199 	 */
1200 	__asm __volatile("ffree %%st(7); flds %0" : : "m" (dummy_variable));
1201 }
1202 #endif /* CPU_ENABLE_SSE */
1203 
1204 static void
fpurstor(addr)1205 fpurstor(addr)
1206 	union savefpu *addr;
1207 {
1208 
1209 #ifdef CPU_ENABLE_SSE
1210 	if (use_xsave)
1211 		xrstor((char *)addr, xsave_mask);
1212 	else if (cpu_fxsr)
1213 		fxrstor(addr);
1214 	else
1215 #endif
1216 		frstor(addr);
1217 }
1218 
1219 #ifdef DEV_ISA
1220 /*
1221  * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
1222  */
1223 static struct isa_pnp_id npxisa_ids[] = {
1224 	{ 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
1225 	{ 0 }
1226 };
1227 
1228 static int
npxisa_probe(device_t dev)1229 npxisa_probe(device_t dev)
1230 {
1231 	int result;
1232 	if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, npxisa_ids)) <= 0) {
1233 		device_quiet(dev);
1234 	}
1235 	return(result);
1236 }
1237 
1238 static int
npxisa_attach(device_t dev)1239 npxisa_attach(device_t dev)
1240 {
1241 	return (0);
1242 }
1243 
1244 static device_method_t npxisa_methods[] = {
1245 	/* Device interface */
1246 	DEVMETHOD(device_probe,		npxisa_probe),
1247 	DEVMETHOD(device_attach,	npxisa_attach),
1248 	DEVMETHOD(device_detach,	bus_generic_detach),
1249 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
1250 	DEVMETHOD(device_suspend,	bus_generic_suspend),
1251 	DEVMETHOD(device_resume,	bus_generic_resume),
1252 
1253 	{ 0, 0 }
1254 };
1255 
1256 static driver_t npxisa_driver = {
1257 	"npxisa",
1258 	npxisa_methods,
1259 	1,			/* no softc */
1260 };
1261 
1262 static devclass_t npxisa_devclass;
1263 
1264 DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0);
1265 #ifndef PC98
1266 DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0);
1267 #endif
1268 #endif /* DEV_ISA */
1269 
1270 static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx",
1271     "Kernel contexts for FPU state");
1272 
1273 #define	FPU_KERN_CTX_NPXINITDONE 0x01
1274 #define	FPU_KERN_CTX_DUMMY	 0x02
1275 
1276 struct fpu_kern_ctx {
1277 	union savefpu *prev;
1278 	uint32_t flags;
1279 	char hwstate1[];
1280 };
1281 
1282 struct fpu_kern_ctx *
fpu_kern_alloc_ctx(u_int flags)1283 fpu_kern_alloc_ctx(u_int flags)
1284 {
1285 	struct fpu_kern_ctx *res;
1286 	size_t sz;
1287 
1288 	sz = sizeof(struct fpu_kern_ctx) + XSAVE_AREA_ALIGN +
1289 	    cpu_max_ext_state_size;
1290 	res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ?
1291 	    M_NOWAIT : M_WAITOK) | M_ZERO);
1292 	return (res);
1293 }
1294 
1295 void
fpu_kern_free_ctx(struct fpu_kern_ctx * ctx)1296 fpu_kern_free_ctx(struct fpu_kern_ctx *ctx)
1297 {
1298 
1299 	/* XXXKIB clear the memory ? */
1300 	free(ctx, M_FPUKERN_CTX);
1301 }
1302 
1303 static union savefpu *
fpu_kern_ctx_savefpu(struct fpu_kern_ctx * ctx)1304 fpu_kern_ctx_savefpu(struct fpu_kern_ctx *ctx)
1305 {
1306 	vm_offset_t p;
1307 
1308 	p = (vm_offset_t)&ctx->hwstate1;
1309 	p = roundup2(p, XSAVE_AREA_ALIGN);
1310 	return ((union savefpu *)p);
1311 }
1312 
1313 int
fpu_kern_enter(struct thread * td,struct fpu_kern_ctx * ctx,u_int flags)1314 fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
1315 {
1316 	struct pcb *pcb;
1317 
1318 	if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) {
1319 		ctx->flags = FPU_KERN_CTX_DUMMY;
1320 		return (0);
1321 	}
1322 	pcb = td->td_pcb;
1323 	KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
1324 	    get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
1325 	ctx->flags = 0;
1326 	if ((pcb->pcb_flags & PCB_NPXINITDONE) != 0)
1327 		ctx->flags |= FPU_KERN_CTX_NPXINITDONE;
1328 	npxexit(td);
1329 	ctx->prev = pcb->pcb_save;
1330 	pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
1331 	pcb->pcb_flags |= PCB_KERNNPX;
1332 	pcb->pcb_flags &= ~PCB_NPXINITDONE;
1333 	return (0);
1334 }
1335 
1336 int
fpu_kern_leave(struct thread * td,struct fpu_kern_ctx * ctx)1337 fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
1338 {
1339 	struct pcb *pcb;
1340 
1341 	if (is_fpu_kern_thread(0) && (ctx->flags & FPU_KERN_CTX_DUMMY) != 0)
1342 		return (0);
1343 	pcb = td->td_pcb;
1344 	critical_enter();
1345 	if (curthread == PCPU_GET(fpcurthread))
1346 		npxdrop();
1347 	critical_exit();
1348 	pcb->pcb_save = ctx->prev;
1349 	if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
1350 		if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0)
1351 			pcb->pcb_flags |= PCB_NPXINITDONE;
1352 		else
1353 			pcb->pcb_flags &= ~PCB_NPXINITDONE;
1354 		pcb->pcb_flags &= ~PCB_KERNNPX;
1355 	} else {
1356 		if ((ctx->flags & FPU_KERN_CTX_NPXINITDONE) != 0)
1357 			pcb->pcb_flags |= PCB_NPXINITDONE;
1358 		else
1359 			pcb->pcb_flags &= ~PCB_NPXINITDONE;
1360 		KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
1361 	}
1362 	return (0);
1363 }
1364 
1365 int
fpu_kern_thread(u_int flags)1366 fpu_kern_thread(u_int flags)
1367 {
1368 
1369 	KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0,
1370 	    ("Only kthread may use fpu_kern_thread"));
1371 	KASSERT(curpcb->pcb_save == get_pcb_user_save_pcb(curpcb),
1372 	    ("mangled pcb_save"));
1373 	KASSERT(PCB_USER_FPU(curpcb), ("recursive call"));
1374 
1375 	curpcb->pcb_flags |= PCB_KERNNPX;
1376 	return (0);
1377 }
1378 
1379 int
is_fpu_kern_thread(u_int flags)1380 is_fpu_kern_thread(u_int flags)
1381 {
1382 
1383 	if ((curthread->td_pflags & TDP_KTHREAD) == 0)
1384 		return (0);
1385 	return ((curpcb->pcb_flags & PCB_KERNNPX) != 0);
1386 }
1387 
1388 /*
1389  * FPU save area alloc/free/init utility routines
1390  */
1391 union savefpu *
fpu_save_area_alloc(void)1392 fpu_save_area_alloc(void)
1393 {
1394 
1395 	return (uma_zalloc(fpu_save_area_zone, 0));
1396 }
1397 
1398 void
fpu_save_area_free(union savefpu * fsa)1399 fpu_save_area_free(union savefpu *fsa)
1400 {
1401 
1402 	uma_zfree(fpu_save_area_zone, fsa);
1403 }
1404 
1405 void
fpu_save_area_reset(union savefpu * fsa)1406 fpu_save_area_reset(union savefpu *fsa)
1407 {
1408 
1409 	bcopy(npx_initialstate, fsa, cpu_max_ext_state_size);
1410 }
1411