xref: /original-bsd/sys/i386/isa/npx.c (revision 3705696b)
1 /*-
2  * Copyright (c) 1990 William Jolitz.
3  * Copyright (c) 1991, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  *
8  *	@(#)npx.c	8.1 (Berkeley) 06/11/93
9  */
10 #include "npx.h"
11 #if NNPX > 0
12 
13 #include <sys/param.h>
14 #include <sys/systm.h>
15 #include <sys/conf.h>
16 #include <sys/file.h>
17 #include <sys/proc.h>
18 #include <sys/user.h>
19 #include <sys/ioctl.h>
20 
21 #include <machine/cpu.h>
22 #include <machine/trap.h>
23 #include <machine/specialreg.h>
24 #include <i386/isa/isa_device.h>
25 #include <i386/isa/icu.h>
26 /*
27  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
28  */
29 
30 int	npxprobe(), npxattach(), npxintr();
31 struct	isa_driver npxdriver = {
32 	npxprobe, npxattach, "npx",
33 };
34 
35 struct proc *npxproc;	/* process who owns device, otherwise zero */
36 struct pcb *npxpcb;	/* owners context structure */
37 static npxexists;
38 extern long npx0mask;
39 
40 /*
41  * Probe routine - look device, otherwise set emulator bit
42  */
43 npxprobe(dvp)
44 	struct isa_device *dvp;
45 {	static status, control;
46 
47 #ifdef lint
48 	npxintr();
49 #endif
50 
51 	/* insure EM bit off */
52 	load_cr0(rcr0() & ~CR0_EM);
53 
54 	asm("	fninit ");	/* put device in known state */
55 
56 	/* check for a proper status of zero */
57 	status = 0xa5a5;
58 	asm ("	fnstsw	%0 " : "=m" (status) : "m" (status) );
59 
60 	if (status == 0) {
61 
62 		/* good, now check for a proper control word */
63 		control = 0xa5a5;
64 		asm ("	fnstcw %0 " : "=m" (control) : "m" (control));
65 
66 		if ((control&0x103f) == 0x3f) {
67 			/* then we have a numeric coprocessor */
68 		/* XXX should force an exception here to generate an intr */
69 			return (1);
70 		}
71 	}
72 
73 	/* insure EM bit on */
74 	load_cr0(rcr0() | CR0_EM);
75 	return (0);
76 }
77 
78 /*
79  * Attach routine - announce which it is, and wire into system
80  */
81 npxattach(dvp)
82 	struct isa_device *dvp;
83 {
84 
85 	npxinit(0x262);
86 	/* check for ET bit to decide 387/287 */
87 	npxexists++;
88 	npx0mask = dvp->id_irq;
89 }
90 
91 /*
92  * Initialize floating point unit, usually after an error
93  */
94 npxinit(control) {
95 
96 	if (npxexists == 0) return;
97 
98 	load_cr0(rcr0() & ~CR0_EM);	/* stop emulating */
99 #ifdef INTEL_COMPAT
100 	asm ("	finit");
101 	asm("	fldcw %0" : : "g" (control));
102 	asm("	fnsave %0 " : : "g" (curpcb->pcb_savefpu) );
103 #else
104 	asm("fninit");
105 	asm("	fnsave %0 " : : "g" (curpcb->pcb_savefpu) );
106 #endif
107 	load_cr0(rcr0() | CR0_EM);	/* start emulating */
108 
109 }
110 
111 /*
112  * Record information needed in processing an exception and clear status word
113  */
114 npxintr(frame)
115 	struct intrframe frame;
116 {
117 	if (npxexists == 0) {
118 		printf ("stray npxintr\n");
119 		return;
120 	}
121 
122 	outb(0xf0,0);		/* reset coprocessor */
123 
124 	/*
125 	 * npxproc may be NULL, if this is a delayed interrupt from
126 	 * a process that just exited.
127 	 */
128 	if (npxproc) {
129 		/*
130 		 * sync state in process context structure, in advance
131 		 * of debugger/process looking for it.
132 		 */
133 		asm("fnsave %0" :: "g" (npxproc->p_addr->u_pcb.pcb_savefpu));
134 		psignal(npxproc, SIGFPE);
135 
136 		/* clear the exception so we can catch others like it */
137 		asm ("	fnclex");
138 	}
139 }
140 
141 /*
142  * Implement device not available (DNA) exception
143  */
144 npxdna()
145 {
146 	if (npxexists == 0)
147 		return(0);
148 
149 	load_cr0(rcr0() & ~CR0_EM);	/* stop emulating */
150 	if (npxproc != curproc) {
151 		if (npxproc)
152 			asm(" fnsave %0 "::"g"
153 			    (npxproc->p_addr->u_pcb.pcb_savefpu));
154 		asm("	frstor %0 " : : "g" (curpcb->pcb_savefpu));
155 		npxproc = curproc;
156 	}
157 	return (1);
158 }
159 #endif
160