Commit | Line | Data |
---|---|---|
d4a75cc0 KB |
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 | * | |
2b689d63 | 8 | * @(#)npx.c 7.3 (Berkeley) %G% |
4686adac BJ |
9 | */ |
10 | #include "npx.h" | |
d4a75cc0 | 11 | #if NNPX > 0 |
4686adac BJ |
12 | |
13 | #include "param.h" | |
14 | #include "systm.h" | |
15 | #include "conf.h" | |
16 | #include "file.h" | |
8dfab1b8 | 17 | #include "proc.h" |
a9096eab | 18 | #include "machine/cpu.h" |
2b689d63 | 19 | #include "user.h" |
a9096eab | 20 | #include "machine/trap.h" |
8dfab1b8 WN |
21 | #include "ioctl.h" |
22 | #include "machine/specialreg.h" | |
23 | #include "i386/isa/isa_device.h" | |
4686adac | 24 | #include "icu.h" |
33822afd BJ |
25 | /* |
26 | * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. | |
33822afd BJ |
27 | */ |
28 | ||
29 | int npxprobe(), npxattach(), npxintr(); | |
4686adac | 30 | struct isa_driver npxdriver = { |
33822afd BJ |
31 | npxprobe, npxattach, "npx", |
32 | }; | |
33 | ||
a9096eab WN |
34 | struct proc *npxproc; /* process who owns device, otherwise zero */ |
35 | struct pcb *npxpcb; /* owners context structure */ | |
8dfab1b8 WN |
36 | static npxexists; |
37 | extern long npx0mask; | |
33822afd BJ |
38 | |
39 | /* | |
40 | * Probe routine - look device, otherwise set emulator bit | |
41 | */ | |
42 | npxprobe(dvp) | |
4686adac BJ |
43 | struct isa_device *dvp; |
44 | { static status, control; | |
33822afd BJ |
45 | |
46 | #ifdef lint | |
47 | npxintr(); | |
48 | #endif | |
4686adac BJ |
49 | |
50 | /* insure EM bit off */ | |
51 | asm(" fninit "); /* put device in known state */ | |
33822afd BJ |
52 | |
53 | /* check for a proper status of zero */ | |
54 | status = 0xa5a5; | |
4686adac | 55 | asm (" fnstsw %0 " : "=m" (status) : "m" (status) ); |
33822afd BJ |
56 | |
57 | if (status == 0) { | |
33822afd BJ |
58 | |
59 | /* good, now check for a proper control word */ | |
60 | control = 0xa5a5; | |
4686adac | 61 | asm (" fnstcw %0 " : "=m" (control) : "m" (control)); |
33822afd | 62 | |
4686adac | 63 | if ((control&0x103f) == 0x3f) { |
33822afd BJ |
64 | /* then we have a numeric coprocessor */ |
65 | /* XXX should force an exception here to generate an intr */ | |
66 | return (1); | |
67 | } | |
68 | } | |
69 | ||
70 | /* insure EM bit on */ | |
71 | return (0); | |
72 | } | |
73 | ||
74 | /* | |
75 | * Attach routine - announce which it is, and wire into system | |
76 | */ | |
77 | npxattach(dvp) | |
4686adac | 78 | struct isa_device *dvp; |
33822afd | 79 | { |
33822afd | 80 | |
4686adac | 81 | npxinit(0x262); |
33822afd | 82 | /* check for ET bit to decide 387/287 */ |
33822afd | 83 | /*outb(0xb1,0); /* reset processor */ |
8dfab1b8 WN |
84 | npxexists++; |
85 | npx0mask = dvp->id_irq; | |
33822afd BJ |
86 | } |
87 | ||
88 | /* | |
89 | * Initialize floating point unit, usually after an error | |
90 | */ | |
4686adac | 91 | npxinit(control) { |
33822afd | 92 | |
8dfab1b8 WN |
93 | if (npxexists == 0) return; |
94 | ||
95 | ||
96 | load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ | |
97 | #ifdef INTEL_COMPAT | |
98 | asm (" finit"); | |
4686adac | 99 | asm(" fldcw %0" : : "g" (control)); |
a9096eab | 100 | asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); |
8dfab1b8 WN |
101 | #else |
102 | asm("fninit"); | |
a9096eab | 103 | asm(" fnsave %0 " : : "g" (curpcb->pcb_savefpu) ); |
8dfab1b8 WN |
104 | #endif |
105 | load_cr0(rcr0() | CR0_EM); /* start emulating */ | |
33822afd BJ |
106 | |
107 | } | |
108 | ||
109 | /* | |
110 | * Load floating point context and record ownership to suite | |
111 | */ | |
112 | npxload() { | |
113 | ||
114 | if (npxproc) panic ("npxload"); | |
8dfab1b8 | 115 | npxproc = curproc; |
a9096eab WN |
116 | npxpcb = curpcb; |
117 | asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu) ); | |
33822afd BJ |
118 | } |
119 | ||
120 | /* | |
121 | * Unload floating point context and relinquish ownership | |
122 | */ | |
123 | npxunload() { | |
124 | ||
125 | if (npxproc == 0) panic ("npxunload"); | |
a9096eab | 126 | asm(" fsave %0 " : : "g" (npxpcb->pcb_savefpu) ); |
33822afd BJ |
127 | npxproc = 0 ; |
128 | } | |
129 | ||
130 | /* | |
131 | * Record information needed in processing an exception and clear status word | |
132 | */ | |
a9096eab WN |
133 | npxintr(frame) struct intrframe frame; { |
134 | struct trapframe tf; | |
8dfab1b8 WN |
135 | |
136 | outb(0xf0,0); /* reset processor */ | |
33822afd | 137 | |
a9096eab | 138 | /* sync state in process context structure, in advance of debugger/process looking for it */ |
8dfab1b8 | 139 | if (npxproc == 0 || npxexists == 0) panic ("npxintr"); |
2b689d63 | 140 | asm (" fnsave %0 " : : "g" (npxproc->p_addr->u_pcb.pcb_savefpu) ); |
a9096eab WN |
141 | |
142 | /* | |
143 | * Prepair a trap frame for our generic exception processing routine, trap() | |
144 | */ | |
145 | bcopy(&frame.if_es, &tf, sizeof(tf)); | |
146 | tf.tf_trapno = T_ARITHTRAP; | |
8dfab1b8 | 147 | #ifdef notyet |
a9096eab WN |
148 | /* encode the appropriate code for detailed information on this exception */ |
149 | tf.tf_err = ???; | |
8dfab1b8 | 150 | #endif |
a9096eab | 151 | trap(tf); |
33822afd BJ |
152 | |
153 | /* | |
a9096eab | 154 | * Restore with any changes to superior frame |
33822afd | 155 | */ |
a9096eab | 156 | bcopy(&tf, &frame.if_es, sizeof(tf)); |
33822afd BJ |
157 | |
158 | /* clear the exception so we can catch others like it */ | |
159 | asm (" fnclex"); | |
160 | } | |
161 | ||
33822afd BJ |
162 | /* |
163 | * Implement device not available (DNA) exception | |
164 | */ | |
165 | npxdna() { | |
8dfab1b8 WN |
166 | |
167 | if (npxexists == 0) return(0); | |
2b689d63 WN |
168 | if (npxproc == curproc) |
169 | load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ | |
170 | else { | |
171 | load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ | |
172 | if (npxproc) | |
173 | asm(" fnsave %0 "::"g" (npxproc->p_addr->u_pcb.pcb_savefpu)); | |
174 | asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); | |
175 | npxproc = curproc; | |
176 | } | |
177 | #ifdef garbage | |
a9096eab WN |
178 | if (!(curpcb->pcb_flags & FP_WASUSED) |
179 | ||(curpcb->pcb_flags & FP_NEEDSRESTORE)) { | |
8dfab1b8 | 180 | load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ |
a9096eab WN |
181 | asm(" frstor %0 " : : "g" (curpcb->pcb_savefpu)); |
182 | curpcb->pcb_flags |= FP_WASUSED | FP_NEEDSSAVE; | |
183 | curpcb->pcb_flags &= ~FP_NEEDSRESTORE; | |
8dfab1b8 | 184 | npxproc = curproc; |
a9096eab | 185 | npxpcb = curpcb; |
8dfab1b8 | 186 | } |
2b689d63 WN |
187 | load_cr0(rcr0() & ~CR0_EM); /* stop emulating */ |
188 | #endif | |
189 | return (1); | |
33822afd | 190 | } |
4686adac | 191 | #endif |