1 /*	$OpenBSD: npx.c,v 1.40.2.1 2006/11/15 03:06:15 brad Exp $	*/
2 /*	$NetBSD: npx.c,v 1.57 1996/05/12 23:12:24 mycroft Exp $	*/
3 
4 #if 0
5 #define iprintf(x)	printf x
6 #else
7 #define	iprintf(x)
8 #endif
9 
10 /*-
11  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
12  * Copyright (c) 1990 William Jolitz.
13  * Copyright (c) 1991 The Regents of the University of California.
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)npx.c	7.2 (Berkeley) 5/12/91
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #include <sys/proc.h>
48 #include <sys/signalvar.h>
49 #include <sys/user.h>
50 #include <sys/ioctl.h>
51 #include <sys/device.h>
52 
53 #include <uvm/uvm_extern.h>
54 
55 #include <machine/cpu.h>
56 #include <machine/intr.h>
57 #include <machine/pio.h>
58 #include <machine/cpufunc.h>
59 #include <machine/pcb.h>
60 #include <machine/trap.h>
61 #include <machine/specialreg.h>
62 
63 #include <dev/isa/isareg.h>
64 #include <dev/isa/isavar.h>
65 #include <i386/isa/icu.h>
66 
67 #if 0
68 #define IPRINTF(x)      printf x
69 #else
70 #define IPRINTF(x)
71 #endif
72 
73 /*
74  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
75  *
76  * We do lazy initialization and switching using the TS bit in cr0 and the
77  * MDP_USEDFPU bit in mdproc.
78  *
79  * DNA exceptions are handled like this:
80  *
81  * 1) If there is no NPX, return and go to the emulator.
82  * 2) If someone else has used the NPX, save its state into that process's PCB.
83  * 3a) If MDP_USEDFPU is not set, set it and initialize the NPX.
84  * 3b) Otherwise, reload the process's previous NPX state.
85  *
86  * When a process is created or exec()s, its saved cr0 image has the TS bit
87  * set and the MDP_USEDFPU bit clear.  The MDP_USEDFPU bit is set when the
88  * process first gets a DNA and the NPX is initialized.  The TS bit is turned
89  * off when the NPX is used, and turned on again later when the process's NPX
90  * state is saved.
91  */
92 
93 #define	fldcw(addr)		__asm("fldcw %0" : : "m" (*addr))
94 #define	fnclex()		__asm("fnclex")
95 #define	fninit()		__asm("fninit")
96 #define	fnsave(addr)		__asm("fnsave %0" : "=m" (*addr))
97 #define	fnstcw(addr)		__asm("fnstcw %0" : "=m" (*addr))
98 #define	fnstsw(addr)		__asm("fnstsw %0" : "=m" (*addr))
99 #define	fp_divide_by_0()	__asm("fldz; fld1; fdiv %st,%st(1); fwait")
100 #define	frstor(addr)		__asm("frstor %0" : : "m" (*addr))
101 #define	fwait()			__asm("fwait")
102 #define	clts()			__asm("clts")
103 #define	stts()			lcr0(rcr0() | CR0_TS)
104 
105 int npxintr(void *);
106 static int npxprobe1(struct isa_attach_args *);
107 static void npxsave1(void);
108 
109 struct npx_softc {
110 	struct device sc_dev;
111 	void *sc_ih;
112 };
113 
114 int npxprobe(struct device *, void *, void *);
115 void npxattach(struct device *, struct device *, void *);
116 
117 struct cfattach npx_ca = {
118 	sizeof(struct npx_softc), npxprobe, npxattach
119 };
120 
121 struct cfdriver npx_cd = {
122 	NULL, "npx", DV_DULL
123 };
124 
125 enum npx_type {
126 	NPX_NONE = 0,
127 	NPX_INTERRUPT,
128 	NPX_EXCEPTION,
129 	NPX_BROKEN,
130 	NPX_CPUID,
131 };
132 
133 struct proc	*npxproc;
134 
135 static	enum npx_type		npx_type;
136 static	int			npx_nointr;
137 static	volatile u_int		npx_intrs_while_probing;
138 static	volatile u_int		npx_traps_while_probing;
139 
140 extern int i386_fpu_present;
141 extern int i386_fpu_exception;
142 extern int i386_fpu_fdivbug;
143 
144 #ifdef I686_CPU
145 #define        fxsave(addr)            __asm("fxsave %0" : "=m" (*addr))
146 #define        fxrstor(addr)           __asm("fxrstor %0" : : "m" (*addr))
147 #endif /* I686_CPU */
148 
149 static __inline void
fpu_save(union savefpu * addr)150 fpu_save(union savefpu *addr)
151 {
152 
153 #ifdef I686_CPU
154 	if (i386_use_fxsave) {
155 		fxsave(&addr->sv_xmm);
156 		/* FXSAVE doesn't FNINIT like FNSAVE does -- so do it here. */
157 		fninit();
158 	} else
159 #endif /* I686_CPU */
160 		fnsave(&addr->sv_87);
161 }
162 
163 static int
npxdna_notset(struct proc * p)164 npxdna_notset(struct proc *p)
165 {
166 	panic("npxdna vector not initialized");
167 }
168 
169 int    (*npxdna_func)(struct proc *) = npxdna_notset;
170 int    npxdna_s87(struct proc *);
171 #ifdef I686_CPU
172 int    npxdna_xmm(struct proc *);
173 #endif /* I686_CPU */
174 void   npxexit(void);
175 
176 /*
177  * Special interrupt handlers.  Someday intr0-intr15 will be used to count
178  * interrupts.  We'll still need a special exception 16 handler.  The busy
179  * latch stuff in probintr() can be moved to npxprobe().
180  */
181 void probeintr(void);
182 asm (".text\n\t"
183 "probeintr:\n\t"
184 	"ss\n\t"
185 	"incl	npx_intrs_while_probing\n\t"
186 	"pushl	%eax\n\t"
187 	"movb	$0x20,%al	# EOI (asm in strings loses cpp features)\n\t"
188 	"outb	%al,$0xa0	# IO_ICU2\n\t"
189 	"outb	%al,$0x20	# IO_ICU1\n\t"
190 	"movb	$0,%al\n\t"
191 	"outb	%al,$0xf0	# clear BUSY# latch\n\t"
192 	"popl	%eax\n\t"
193 	"iret\n\t");
194 
195 void probetrap(void);
196 asm (".text\n\t"
197 "probetrap:\n\t"
198 	"ss\n\t"
199 	"incl	npx_traps_while_probing\n\t"
200 	"fnclex\n\t"
201 	"iret\n\t");
202 
203 static inline int
npxprobe1(ia)204 npxprobe1(ia)
205 	struct isa_attach_args *ia;
206 {
207 #ifndef ALWAYS_MATH_EMULATE
208 	int control;
209 	int status;
210 
211 	ia->ia_iosize = 16;
212 	ia->ia_msize = 0;
213 
214 	/*
215 	 * Finish resetting the coprocessor, if any.  If there is an error
216 	 * pending, then we may get a bogus IRQ13, but probeintr() will handle
217 	 * it OK.  Bogus halts have never been observed, but we enabled
218 	 * IRQ13 and cleared the BUSY# latch early to handle them anyway.
219 	 */
220 	fninit();
221 	delay(1000);		/* wait for any IRQ13 (fwait might hang) */
222 
223 	/*
224 	 * Check for a status of mostly zero.
225 	 */
226 	status = 0x5a5a;
227 	fnstsw(&status);
228 	if ((status & 0xb8ff) == 0) {
229 		/*
230 		 * Good, now check for a proper control word.
231 		 */
232 		control = 0x5a5a;
233 		fnstcw(&control);
234 		if ((control & 0x1f3f) == 0x033f) {
235 			/*
236 			 * We have an npx, now divide by 0 to see if exception
237 			 * 16 works.
238 			 */
239 			control &= ~(1 << 2);	/* enable divide by 0 trap */
240 			fldcw(&control);
241 			npx_traps_while_probing = npx_intrs_while_probing = 0;
242 			fp_divide_by_0();
243 			delay(1);
244 			if (npx_traps_while_probing != 0) {
245 				/*
246 				 * Good, exception 16 works.
247 				 */
248 				npx_type = NPX_EXCEPTION;
249 				ia->ia_irq = IRQUNK;	/* zap the interrupt */
250 				i386_fpu_exception = 1;
251 			} else if (npx_intrs_while_probing != 0) {
252 				/*
253 				 * Bad, we are stuck with IRQ13.
254 				 */
255 				npx_type = NPX_INTERRUPT;
256 			} else {
257 				/*
258 				 * Worse, even IRQ13 is broken.  Use emulator.
259 				 */
260 				npx_type = NPX_BROKEN;
261 				ia->ia_irq = IRQUNK;
262 			}
263 			return 1;
264 		}
265 	}
266 #else
267 	npx_intrs_while_probing = npx_traps_while_probing = 0;
268 #endif
269 
270 	/*
271 	 * Probe failed.  There is no usable FPU.
272 	 */
273 	npx_type = NPX_NONE;
274 	return 0;
275 }
276 
277 /*
278  * Probe routine.  Initialize cr0 to give correct behaviour for [f]wait
279  * whether the device exists or not (XXX should be elsewhere).  Set flags
280  * to tell npxattach() what to do.  Modify device struct if npx doesn't
281  * need to use interrupts.  Return 1 if device exists.
282  */
283 int
npxprobe(parent,match,aux)284 npxprobe(parent, match, aux)
285 	struct device *parent;
286 	void *match, *aux;
287 {
288 	struct	isa_attach_args *ia = aux;
289 	int	irq;
290 	int	result;
291 	u_long	save_eflags;
292 	unsigned save_imen;
293 	struct	gate_descriptor save_idt_npxintr;
294 	struct	gate_descriptor save_idt_npxtrap;
295 
296 	if (cpu_feature & CPUID_FPU) {
297 		npx_type = NPX_CPUID;
298 		i386_fpu_exception = 1;
299 		ia->ia_irq = IRQUNK;	/* Don't want the interrupt vector */
300 		ia->ia_iosize = 16;
301 		ia->ia_msize = 0;
302 		return 1;
303 	}
304 
305 	/*
306 	 * This routine is now just a wrapper for npxprobe1(), to install
307 	 * special npx interrupt and trap handlers, to enable npx interrupts
308 	 * and to disable other interrupts.  Someday isa_configure() will
309 	 * install suitable handlers and run with interrupts enabled so we
310 	 * won't need to do so much here.
311 	 */
312 	irq = NRSVIDT + ia->ia_irq;
313 	save_eflags = read_eflags();
314 	disable_intr();
315 	save_idt_npxintr = idt[irq];
316 	save_idt_npxtrap = idt[16];
317 	setgate(&idt[irq], probeintr, 0, SDT_SYS386IGT, SEL_KPL, GICODE_SEL);
318 	setgate(&idt[16], probetrap, 0, SDT_SYS386TGT, SEL_KPL, GCODE_SEL);
319 	save_imen = imen;
320 	imen = ~((1 << IRQ_SLAVE) | (1 << ia->ia_irq));
321 	SET_ICUS();
322 
323 	/*
324 	 * Partially reset the coprocessor, if any.  Some BIOS's don't reset
325 	 * it after a warm boot.
326 	 */
327 	outb(0xf1, 0);		/* full reset on some systems, NOP on others */
328 	delay(1000);
329 	outb(0xf0, 0);		/* clear BUSY# latch */
330 
331 	/*
332 	 * We set CR0 in locore to trap all ESC and WAIT instructions.
333 	 * We have to turn off the CR0_EM bit temporarily while probing.
334 	 */
335 	lcr0(rcr0() & ~(CR0_EM|CR0_TS));
336 	enable_intr();
337 	result = npxprobe1(ia);
338 	disable_intr();
339 	lcr0(rcr0() | (CR0_EM|CR0_TS));
340 
341 	imen = save_imen;
342 	SET_ICUS();
343 	idt[irq] = save_idt_npxintr;
344 	idt[16] = save_idt_npxtrap;
345 	write_eflags(save_eflags);
346 	return (result);
347 }
348 
349 int npx586bug1(int, int);
350 asm (".text\n\t"
351 "npx586bug1:\n\t"
352 	"fildl	4(%esp)		# x\n\t"
353 	"fildl	8(%esp)		# y\n\t"
354 	"fld	%st(1)\n\t"
355 	"fdiv	%st(1),%st	# x/y\n\t"
356 	"fmulp	%st,%st(1)	# (x/y)*y\n\t"
357 	"fsubrp	%st,%st(1)	# x-(x/y)*y\n\t"
358 	"pushl	$0\n\t"
359 	"fistpl	(%esp)\n\t"
360 	"popl	%eax\n\t"
361 	"ret\n\t");
362 
363 /*
364  * Attach routine - announce which it is, and wire into system
365  */
366 void
npxattach(parent,self,aux)367 npxattach(parent, self, aux)
368 	struct device *parent, *self;
369 	void *aux;
370 {
371 	struct npx_softc *sc = (void *)self;
372 	struct isa_attach_args *ia = aux;
373 
374 	switch (npx_type) {
375 	case NPX_INTERRUPT:
376 		printf("\n");
377 		lcr0(rcr0() & ~CR0_NE);
378 		sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq,
379 		    IST_EDGE, IPL_NONE, npxintr, 0, sc->sc_dev.dv_xname);
380 		break;
381 	case NPX_EXCEPTION:
382 		printf(": using exception 16\n");
383 		break;
384 	case NPX_CPUID:
385 		printf(": reported by CPUID; using exception 16\n");
386 		npx_type = NPX_EXCEPTION;
387 		break;
388 	case NPX_BROKEN:
389 		printf(": error reporting broken; not using\n");
390 		npx_type = NPX_NONE;
391 		return;
392 	case NPX_NONE:
393 		return;
394 	}
395 
396 	lcr0(rcr0() & ~(CR0_EM|CR0_TS));
397 	fninit();
398 	if (npx586bug1(4195835, 3145727) != 0) {
399 		i386_fpu_fdivbug = 1;
400 		printf("WARNING: Pentium FDIV bug detected!\n");
401 	}
402 	lcr0(rcr0() | (CR0_TS));
403 	i386_fpu_present = 1;
404 
405 #ifdef I686_CPU
406 	if (i386_use_fxsave)
407 		npxdna_func = npxdna_xmm;
408 	else
409 #endif /* I686_CPU */
410 		npxdna_func = npxdna_s87;
411 }
412 
413 /*
414  * Record the FPU state and reinitialize it all except for the control word.
415  * Then generate a SIGFPE.
416  *
417  * Reinitializing the state allows naive SIGFPE handlers to longjmp without
418  * doing any fixups.
419  *
420  * XXX there is currently no way to pass the full error state to signal
421  * handlers, and if this is a nested interrupt there is no way to pass even
422  * a status code!  So there is no way to have a non-naive SIGFPE handler.  At
423  * best a handler could do an fninit followed by an fldcw of a static value.
424  * fnclex would be of little use because it would leave junk on the FPU stack.
425  * Returning from the handler would be even less safe than usual because
426  * IRQ13 exception handling makes exceptions even less precise than usual.
427  */
428 int
npxintr(arg)429 npxintr(arg)
430 	void *arg;
431 {
432 	register struct proc *p = npxproc;
433 	union savefpu *addr;
434 	struct intrframe *frame = arg;
435 	int code;
436 	union sigval sv;
437 
438 	uvmexp.traps++;
439 	iprintf(("Intr"));
440 
441 	if (p == 0 || npx_type == NPX_NONE) {
442 		/* XXX no %p in stand/printf.c.  Cast to quiet gcc -Wall. */
443 		printf("npxintr: p = %lx, curproc = %lx, npx_type = %d\n",
444 		       (u_long) p, (u_long) curproc, npx_type);
445 		panic("npxintr from nowhere");
446 	}
447 	/*
448 	 * Clear the interrupt latch.
449 	 */
450 	outb(0xf0, 0);
451 	/*
452 	 * If we're saving, ignore the interrupt.  The FPU will happily
453 	 * generate another one when we restore the state later.
454 	 */
455 	if (npx_nointr != 0)
456 		return (1);
457 	/*
458 	 * Find the address of npxproc's savefpu.  This is not necessarily
459 	 * the one in curpcb.
460 	 */
461 	addr = &p->p_addr->u_pcb.pcb_savefpu;
462 	/*
463 	 * Save state.  This does an implied fninit.  It had better not halt
464 	 * the cpu or we'll hang.
465 	 */
466 	fpu_save(addr);
467 	fwait();
468 	/*
469 	 * Restore control word (was clobbered by fpu_save).
470 	 */
471 	if (i386_use_fxsave) {
472 		fldcw(&addr->sv_xmm.sv_env.en_cw);
473 		/*
474 		 * FNINIT doesn't affect MXCSR or the XMM registers;
475 		 * no need to re-load MXCSR here.
476 		 */
477 	} else
478 		fldcw(&addr->sv_87.sv_env.en_cw);
479 	fwait();
480 	/*
481 	 * Remember the exception status word and tag word.  The current
482 	 * (almost fninit'ed) fpu state is in the fpu and the exception
483 	 * state just saved will soon be junk.  However, the implied fninit
484 	 * doesn't change the error pointers or register contents, and we
485 	 * preserved the control word and will copy the status and tag
486 	 * words, so the complete exception state can be recovered.
487 	 */
488 	if (i386_use_fxsave) {
489 	        addr->sv_xmm.sv_ex_sw = addr->sv_xmm.sv_env.en_sw;
490 	        addr->sv_xmm.sv_ex_tw = addr->sv_xmm.sv_env.en_tw;
491 	} else {
492 	        addr->sv_87.sv_ex_sw = addr->sv_87.sv_env.en_sw;
493 	        addr->sv_87.sv_ex_tw = addr->sv_87.sv_env.en_tw;
494 	}
495 
496 	/*
497 	 * Pass exception to process.  If it's the current process, try to do
498 	 * it immediately.
499 	 */
500 	if (p == curproc && USERMODE(frame->if_cs, frame->if_eflags)) {
501 		/*
502 		 * Interrupt is essentially a trap, so we can afford to call
503 		 * the SIGFPE handler (if any) as soon as the interrupt
504 		 * returns.
505 		 *
506 		 * XXX little or nothing is gained from this, and plenty is
507 		 * lost - the interrupt frame has to contain the trap frame
508 		 * (this is otherwise only necessary for the rescheduling trap
509 		 * in doreti, and the frame for that could easily be set up
510 		 * just before it is used).
511 		 */
512 		p->p_md.md_regs = (struct trapframe *)&frame->if_es;
513 
514 		/*
515 		 * Encode the appropriate code for detailed information on
516 		 * this exception.
517 		 */
518 		if (addr->sv_87.sv_ex_sw & EN_SW_IE)
519 			code = FPE_FLTINV;
520 #ifdef notyet
521 		else if (addr->sv_ex_sw & EN_SW_DE)
522 			code = FPE_FLTDEN;
523 #endif
524 		else if (addr->sv_87.sv_ex_sw & EN_SW_ZE)
525 			code = FPE_FLTDIV;
526 		else if (addr->sv_87.sv_ex_sw & EN_SW_OE)
527 			code = FPE_FLTOVF;
528 		else if (addr->sv_87.sv_ex_sw & EN_SW_UE)
529 			code = FPE_FLTUND;
530 		else if (addr->sv_87.sv_ex_sw & EN_SW_PE)
531 			code = FPE_FLTRES;
532 		else
533 			code = 0;		/* XXX unknown */
534 		sv.sival_int = frame->if_eip;
535 		trapsignal(p, SIGFPE, T_ARITHTRAP, code, sv);
536 	} else {
537 		/*
538 		 * Nested interrupt.  These losers occur when:
539 		 *	o an IRQ13 is bogusly generated at a bogus time, e.g.:
540 		 *		o immediately after an fnsave or frstor of an
541 		 *		  error state.
542 		 *		o a couple of 386 instructions after
543 		 *		  "fstpl _memvar" causes a stack overflow.
544 		 *	  These are especially nasty when combined with a
545 		 *	  trace trap.
546 		 *	o an IRQ13 occurs at the same time as another higher-
547 		 *	  priority interrupt.
548 		 *
549 		 * Treat them like a true async interrupt.
550 		 */
551 		psignal(p, SIGFPE);
552 	}
553 
554 	return (1);
555 }
556 
557 /*
558  * Wrapper for fnsave instruction to handle h/w bugs.  If there is an error
559  * pending, then fnsave generates a bogus IRQ13 on some systems.  Force any
560  * IRQ13 to be handled immediately, and then ignore it.
561  *
562  * This routine is always called at spl0.  If it might called with the NPX
563  * interrupt masked, it would be necessary to forcibly unmask the NPX interrupt
564  * so that it could succeed.
565  */
566 static __inline void
npxsave1(void)567 npxsave1(void)
568 {
569 	register struct pcb *pcb;
570 
571 	npx_nointr = 1;
572 	pcb = &npxproc->p_addr->u_pcb;
573 	fpu_save(&pcb->pcb_savefpu);
574 	pcb->pcb_cr0 |= CR0_TS;
575 	fwait();
576 	npx_nointr = 0;
577 }
578 
579 /*
580  * Implement device not available (DNA) exception
581  *
582  * If the we were the last process to use the FPU, we can simply return.
583  * Otherwise, we save the previous state, if necessary, and restore our last
584  * saved state.
585  */
586 #ifdef I686_CPU
587 int
npxdna_xmm(struct proc * p)588 npxdna_xmm(struct proc *p)
589 {
590 
591 #ifdef DIAGNOSTIC
592 	if (cpl != 0 || npx_nointr != 0)
593 	        panic("npxdna: masked");
594 #endif
595 
596 	p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS;
597 	clts();
598 
599 	/*
600 	 * Initialize the FPU state to clear any exceptions.  If someone else
601 	 * was using the FPU, save their state (which does an implicit
602 	 * initialization).
603 	 */
604 	npx_nointr = 1;
605 	if (npxproc != 0 && npxproc != p) {
606 	        IPRINTF(("Save"));
607 	        npxsave1();
608 	} else {
609 	        IPRINTF(("Init"));
610 	        fninit();
611 	        fwait();
612 	}
613 	npx_nointr = 0;
614 	npxproc = p;
615 
616 	if ((p->p_md.md_flags & MDP_USEDFPU) == 0) {
617 		fldcw(&p->p_addr->u_pcb.pcb_savefpu.sv_xmm.sv_env.en_cw);
618 		p->p_md.md_flags |= MDP_USEDFPU;
619 	} else {
620 		static double	zero = 0.0;
621 
622 		/*
623 		 * amd fpu does not restore fip, fdp, fop on fxrstor
624 		 * thus leaking other process' execution history.
625 		 */
626 		fnclex();
627 		__asm __volatile("ffree %%st(7)\n\tfld %0" : : "m" (zero));
628 		fxrstor(&p->p_addr->u_pcb.pcb_savefpu.sv_xmm);
629 	}
630 
631 	return (1);
632 }
633 #endif /* I686_CPU */
634 
635 int
npxdna_s87(struct proc * p)636 npxdna_s87(struct proc *p)
637 {
638 	static u_short control = __NPXCW__;
639 
640 	if (npx_type == NPX_NONE) {
641 		iprintf(("Emul"));
642 		return (0);
643 	}
644 
645 #ifdef DIAGNOSTIC
646 	if (cpl != IPL_NONE || npx_nointr != 0)
647 		panic("npxdna: masked");
648 #endif
649 
650 	p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS;
651 	clts();
652 
653 	if ((p->p_md.md_flags & MDP_USEDFPU) == 0) {
654 		p->p_md.md_flags |= MDP_USEDFPU;
655 		iprintf(("Init"));
656 		if (npxproc != 0 && npxproc != p)
657 			npxsave1();
658 		else {
659 			npx_nointr = 1;
660 			fninit();
661 			fwait();
662 			npx_nointr = 0;
663 		}
664 		npxproc = p;
665 		fldcw(&control);
666 	} else {
667 		if (npxproc != 0) {
668 #ifdef DIAGNOSTIC
669 			if (npxproc == p)
670 				panic("npxdna: same process");
671 #endif
672 			iprintf(("Save"));
673 			npxsave1();
674 		}
675 		npxproc = p;
676 		/*
677 		 * The following frstor may cause an IRQ13 when the state being
678 		 * restored has a pending error.  The error will appear to have
679 		 * been triggered by the current (npx) user instruction even
680 		 * when that instruction is a no-wait instruction that should
681 		 * not trigger an error (e.g., fnclex).  On at least one 486
682 		 * system all of the no-wait instructions are broken the same
683 		 * as frstor, so our treatment does not amplify the breakage.
684 		 * On at least one 386/Cyrix 387 system, fnclex works correctly
685 		 * while frstor and fnsave are broken, so our treatment breaks
686 		 * fnclex if it is the first FPU instruction after a context
687 		 * switch.
688 		 */
689 		frstor(&p->p_addr->u_pcb.pcb_savefpu.sv_87);
690 	}
691 
692 	return (1);
693 }
694 
695 /*
696  * Drop the current FPU state on the floor.
697  */
698 void
npxdrop()699 npxdrop()
700 {
701 
702 	stts();
703 	npxproc->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
704 	npxproc = 0;
705 }
706 
707 /*
708  * Save npxproc's FPU state.
709  *
710  * The FNSAVE instruction clears the FPU state.  Rather than reloading the FPU
711  * immediately, we clear npxproc and turn on CR0_TS to force a DNA and a reload
712  * of the FPU state the next time we try to use it.  This routine is only
713  * called when forking or core dump, so this algorithm at worst forces us to
714  * trap once per fork(), and at best saves us a reload once per fork().
715  */
716 void
npxsave()717 npxsave()
718 {
719 
720 #ifdef DIAGNOSTIC
721 	if (cpl != IPL_NONE || npx_nointr != 0)
722 		panic("npxsave: masked");
723 #endif
724 	iprintf(("Fork"));
725 	clts();
726 	npxsave1();
727 	stts();
728 	npxproc = 0;
729 }
730