xref: /csrg-svn/sys/i386/isa/npx.c (revision 63364)
149617Sbostic /*-
249617Sbostic  * Copyright (c) 1990 William Jolitz.
3*63364Sbostic  * Copyright (c) 1991, 1993
4*63364Sbostic  *	The Regents of the University of California.  All rights reserved.
549617Sbostic  *
649617Sbostic  * %sccs.include.redist.c%
749617Sbostic  *
8*63364Sbostic  *	@(#)npx.c	8.1 (Berkeley) 06/11/93
945624Sbill  */
1045624Sbill #include "npx.h"
1149617Sbostic #if NNPX > 0
1245624Sbill 
1356513Sbostic #include <sys/param.h>
1456513Sbostic #include <sys/systm.h>
1556513Sbostic #include <sys/conf.h>
1656513Sbostic #include <sys/file.h>
1756513Sbostic #include <sys/proc.h>
1856513Sbostic #include <sys/user.h>
1956513Sbostic #include <sys/ioctl.h>
2056513Sbostic 
2156513Sbostic #include <machine/cpu.h>
2256513Sbostic #include <machine/trap.h>
2356513Sbostic #include <machine/specialreg.h>
2456513Sbostic #include <i386/isa/isa_device.h>
2556513Sbostic #include <i386/isa/icu.h>
2645624Sbill /*
2745547Sbill  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
2845547Sbill  */
2945547Sbill 
3045547Sbill int	npxprobe(), npxattach(), npxintr();
3145624Sbill struct	isa_driver npxdriver = {
3245547Sbill 	npxprobe, npxattach, "npx",
3345547Sbill };
3445547Sbill 
3549694Swilliam struct proc *npxproc;	/* process who owns device, otherwise zero */
3649694Swilliam struct pcb *npxpcb;	/* owners context structure */
3749573Swilliam static npxexists;
3849573Swilliam extern long npx0mask;
3945547Sbill 
4045547Sbill /*
4145547Sbill  * Probe routine - look device, otherwise set emulator bit
4245547Sbill  */
4345547Sbill npxprobe(dvp)
4445624Sbill 	struct isa_device *dvp;
4545624Sbill {	static status, control;
4645547Sbill 
4745547Sbill #ifdef lint
4845547Sbill 	npxintr();
4945547Sbill #endif
5045547Sbill 
5145624Sbill 	/* insure EM bit off */
5253642Sbostic 	load_cr0(rcr0() & ~CR0_EM);
5353642Sbostic 
5445624Sbill 	asm("	fninit ");	/* put device in known state */
5545624Sbill 
5645547Sbill 	/* check for a proper status of zero */
5745547Sbill 	status = 0xa5a5;
5845624Sbill 	asm ("	fnstsw	%0 " : "=m" (status) : "m" (status) );
5945547Sbill 
6045547Sbill 	if (status == 0) {
6145547Sbill 
6245547Sbill 		/* good, now check for a proper control word */
6345547Sbill 		control = 0xa5a5;
6445624Sbill 		asm ("	fnstcw %0 " : "=m" (control) : "m" (control));
6545547Sbill 
6645624Sbill 		if ((control&0x103f) == 0x3f) {
6745547Sbill 			/* then we have a numeric coprocessor */
6845547Sbill 		/* XXX should force an exception here to generate an intr */
6945547Sbill 			return (1);
7045547Sbill 		}
7145547Sbill 	}
7245547Sbill 
7353642Sbostic 	/* insure EM bit on */
7453642Sbostic 	load_cr0(rcr0() | CR0_EM);
7545547Sbill 	return (0);
7645547Sbill }
7745547Sbill 
7845547Sbill /*
7945547Sbill  * Attach routine - announce which it is, and wire into system
8045547Sbill  */
8145547Sbill npxattach(dvp)
8245624Sbill 	struct isa_device *dvp;
8345547Sbill {
8445547Sbill 
8545624Sbill 	npxinit(0x262);
8645547Sbill 	/* check for ET bit to decide 387/287 */
8749573Swilliam 	npxexists++;
8849573Swilliam 	npx0mask = dvp->id_irq;
8945547Sbill }
9045547Sbill 
9145547Sbill /*
9245547Sbill  * Initialize floating point unit, usually after an error
9345547Sbill  */
npxinit(control)9445624Sbill npxinit(control) {
9545547Sbill 
9649573Swilliam 	if (npxexists == 0) return;
9749573Swilliam 
9849573Swilliam 	load_cr0(rcr0() & ~CR0_EM);	/* stop emulating */
9949573Swilliam #ifdef INTEL_COMPAT
10049573Swilliam 	asm ("	finit");
10145624Sbill 	asm("	fldcw %0" : : "g" (control));
10249694Swilliam 	asm("	fnsave %0 " : : "g" (curpcb->pcb_savefpu) );
10349573Swilliam #else
10449573Swilliam 	asm("fninit");
10549694Swilliam 	asm("	fnsave %0 " : : "g" (curpcb->pcb_savefpu) );
10649573Swilliam #endif
10749573Swilliam 	load_cr0(rcr0() | CR0_EM);	/* start emulating */
10845547Sbill 
10945547Sbill }
11045547Sbill 
11145547Sbill /*
11245547Sbill  * Record information needed in processing an exception and clear status word
11345547Sbill  */
11453642Sbostic npxintr(frame)
11553642Sbostic 	struct intrframe frame;
11653642Sbostic {
11753642Sbostic 	if (npxexists == 0) {
11853642Sbostic 		printf ("stray npxintr\n");
11953642Sbostic 		return;
12053642Sbostic 	}
12145547Sbill 
12253642Sbostic 	outb(0xf0,0);		/* reset coprocessor */
12349573Swilliam 
12449694Swilliam 	/*
12553642Sbostic 	 * npxproc may be NULL, if this is a delayed interrupt from
12653642Sbostic 	 * a process that just exited.
12749694Swilliam 	 */
12853642Sbostic 	if (npxproc) {
12953642Sbostic 		/*
13053642Sbostic 		 * sync state in process context structure, in advance
13153642Sbostic 		 * of debugger/process looking for it.
13253642Sbostic 		 */
13353642Sbostic 		asm("fnsave %0" :: "g" (npxproc->p_addr->u_pcb.pcb_savefpu));
13453642Sbostic 		psignal(npxproc, SIGFPE);
13545547Sbill 
13653642Sbostic 		/* clear the exception so we can catch others like it */
13753642Sbostic 		asm ("	fnclex");
13853642Sbostic 	}
13945547Sbill }
14045547Sbill 
14145547Sbill /*
14245547Sbill  * Implement device not available (DNA) exception
14345547Sbill  */
npxdna()14453642Sbostic npxdna()
14553642Sbostic {
14653642Sbostic 	if (npxexists == 0)
14753642Sbostic 		return(0);
14849573Swilliam 
14953642Sbostic 	load_cr0(rcr0() & ~CR0_EM);	/* stop emulating */
15053642Sbostic 	if (npxproc != curproc) {
15151728Swilliam 		if (npxproc)
15253642Sbostic 			asm(" fnsave %0 "::"g"
15353642Sbostic 			    (npxproc->p_addr->u_pcb.pcb_savefpu));
15451728Swilliam 		asm("	frstor %0 " : : "g" (curpcb->pcb_savefpu));
15551728Swilliam 		npxproc = curproc;
15651728Swilliam 	}
15751728Swilliam 	return (1);
15845547Sbill }
15945624Sbill #endif
160