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