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 */
npxinit(control)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 */
npxdna()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