This source file includes following definitions.
- math_emulate
- __math_abort
- math_emulate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include <linux/config.h>
27
28 #ifdef CONFIG_MATH_EMULATION
29
30 #include <linux/signal.h>
31
32 #include "fpu_system.h"
33 #include "fpu_emu.h"
34 #include "exception.h"
35 #include "control_w.h"
36
37 #include <asm/segment.h>
38
39
40 #define __BAD__ Un_impl
41
42 #ifndef NO_UNDOC_CODE
43
44
45
46
47
48
49 #define _d9_d8_ fstp_i
50 #define _dc_d0_ fcom_st
51 #define _dc_d8_ fcompst
52 #define _dd_c8_ fxch_i
53 #define _de_d0_ fcompst
54 #define _df_c0_ ffreep
55 #define _df_c8_ fxch_i
56 #define _df_d0_ fstp_i
57 #define _df_d8_ fstp_i
58
59 static FUNC st_instr_table[64] = {
60 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
61 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
62 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
63 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
64 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
65 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
66 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
67 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
68 };
69
70 #else
71
72 static FUNC st_instr_table[64] = {
73 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
74 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
75 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
76 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
77 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
78 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
79 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
80 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
81 };
82
83 #endif NO_UNDOC_CODE
84
85
86 #define _NONE_ 0
87 #define _REG0_ 1
88 #define _REGI_ 2
89 #define _REGi_ 0
90 #define _PUSH_ 3
91 #define _null_ 4
92
93 #ifndef NO_UNDOC_CODE
94
95
96
97 static unsigned char type_table[64] = {
98 _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _REGi_,
99 _REGI_, _REGI_, _null_, _null_, _REGI_, _REGI_, _REGI_, _REGI_,
100 _REGI_, _NONE_, _null_, _null_, _REGI_, _REG0_, _REGI_, _REG0_,
101 _REGI_, _REG0_, _null_, _null_, _REGI_, _REG0_, _REGI_, _REG0_,
102 _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
103 _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
104 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
105 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
106 };
107
108 #else
109
110 static unsigned char type_table[64] = {
111 _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _null_,
112 _REGI_, _REGI_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
113 _REGI_, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
114 _REGI_, _null_, _null_, _null_, _null_, _REG0_, _REGI_, _null_,
115 _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
116 _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
117 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
118 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
119 };
120
121 #endif NO_UNDOC_CODE
122
123
124
125
126 unsigned char FPU_rm;
127 char FPU_st0_tag;
128 FPU_REG *FPU_st0_ptr;
129
130 #ifdef PARANOID
131 char emulating=0;
132 #endif PARANOID
133
134 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
135
136
137 void math_emulate(long arg)
138 {
139 unsigned char FPU_modrm;
140 unsigned short code;
141
142 #ifdef PARANOID
143 if ( emulating )
144 {
145 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
146 }
147 RE_ENTRANT_CHECK_ON
148 #endif PARANOID
149
150 if (!current->used_math)
151 {
152 finit();
153 current->used_math = 1;
154 control_word = 0x037f;
155 status_word = 0x0000;
156 }
157
158 FPU_info = (struct info *) &arg;
159
160
161 if (FPU_EFLAGS & 0x00020000)
162 {
163 FPU_ORIG_EIP = FPU_EIP;
164 math_abort(FPU_info,SIGILL);
165 }
166
167
168 if (FPU_CS != 0x000f)
169 {
170 printk("math_emulate: %04x:%08x\n",FPU_CS,FPU_EIP);
171 panic("Math emulation needed in kernel");
172 }
173
174 FPU_lookahead = 1;
175 if (current->flags & PF_PTRACED)
176 FPU_lookahead = 0;
177 do_another:
178
179 FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
180
181 RE_ENTRANT_CHECK_OFF
182 code = get_fs_word((unsigned short *) FPU_EIP);
183 RE_ENTRANT_CHECK_ON
184
185 if ( (code & 0xff) == 0x66 )
186 {
187 FPU_EIP++;
188 RE_ENTRANT_CHECK_OFF
189 code = get_fs_word((unsigned short *) FPU_EIP);
190 RE_ENTRANT_CHECK_ON
191 }
192 FPU_EIP += 2;
193
194 FPU_modrm = code >> 8;
195 FPU_rm = FPU_modrm & 7;
196
197 if ( FPU_modrm < 0300 )
198 {
199
200 get_address(FPU_modrm);
201 if ( !(code & 1) )
202 {
203 switch ( (code >> 1) & 3 )
204 {
205 case 0:
206 reg_load_single();
207 break;
208 case 1:
209 reg_load_int32();
210 break;
211 case 2:
212 reg_load_double();
213 break;
214 case 3:
215 reg_load_int16();
216 break;
217 }
218
219
220
221 FPU_st0_ptr = &st(0);
222 FPU_st0_tag = FPU_st0_ptr->tag;
223 if ( NOT_EMPTY_0 )
224 {
225 switch ( (FPU_modrm >> 3) & 7 )
226 {
227 case 0:
228 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
229 control_word);
230 break;
231 case 1:
232 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
233 control_word);
234 break;
235 case 2:
236 compare_st_data();
237 break;
238 case 3:
239 compare_st_data();
240 pop();
241 break;
242 case 4:
243 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
244 control_word);
245 break;
246 case 5:
247 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
248 control_word);
249 break;
250 case 6:
251 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
252 control_word);
253 break;
254 case 7:
255 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
256 control_word);
257 break;
258 }
259 }
260 else
261 stack_underflow();
262 }
263 else
264 {
265 load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
266 }
267
268 data_operand_offset = (unsigned long)FPU_data_address;
269 }
270 else
271 {
272
273 unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
274 FPU_st0_ptr = &st(0);
275 FPU_st0_tag = FPU_st0_ptr->tag;
276 switch ( type_table[(int) instr_index] )
277 {
278 case _NONE_:
279 break;
280 case _REG0_:
281 if ( !NOT_EMPTY_0 )
282 {
283 stack_underflow();
284 goto instruction_done;
285 }
286 break;
287 case _REGI_:
288 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
289 {
290 stack_underflow();
291 goto instruction_done;
292 }
293 break;
294 case _PUSH_:
295 break;
296 case _null_:
297 Un_impl();
298 goto instruction_done;
299 default:
300 EXCEPTION(EX_INTERNAL|0x111);
301 goto instruction_done;
302 }
303 (*st_instr_table[(int) instr_index])();
304 }
305
306 instruction_done:
307
308 ip_offset = FPU_entry_eip;
309 bswapw(code);
310 *(1 + (unsigned short *)&cs_selector) = code & 0x7ff;
311
312 if (FPU_lookahead && !need_resched)
313 {
314 unsigned char next;
315 skip_fwait:
316 RE_ENTRANT_CHECK_OFF
317 next = get_fs_byte((unsigned char *) FPU_EIP);
318 RE_ENTRANT_CHECK_ON
319 test_for_fp:
320 if ( (next & 0xf8) == 0xd8 )
321 {
322 goto do_another;
323 }
324 if ( next == 0x9b )
325 { FPU_EIP++; goto skip_fwait; }
326 if ( next == 0x66 )
327 {
328 RE_ENTRANT_CHECK_OFF
329 next = get_fs_byte((unsigned char *) (FPU_EIP+1));
330 RE_ENTRANT_CHECK_ON
331 if ( (next & 0xf8) == 0xd8 )
332 goto test_for_fp;
333 }
334 }
335
336 RE_ENTRANT_CHECK_OFF
337 }
338
339
340 void __math_abort(struct info * info, unsigned int signal)
341 {
342 FPU_EIP = FPU_ORIG_EIP;
343 send_sig(signal,current,1);
344 RE_ENTRANT_CHECK_OFF
345 __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
346 #ifdef PARANOID
347 printk("ERROR: wm-FPU-emu math_abort failed!\n");
348 #endif PARANOID
349 }
350
351 #else
352
353 #include <linux/signal.h>
354 #include <linux/sched.h>
355
356 void math_emulate(long arg)
357 {
358 printk("math-meulation not enabled and no coprocessor found.\n");
359 printk("killing %s.\n",current->comm);
360 send_sig(SIGFPE,current,1);
361 schedule();
362 }
363
364 #endif