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 #include <linux/segment.h>
32
33 #include "fpu_system.h"
34 #include "fpu_emu.h"
35 #include "exception.h"
36 #include "control_w.h"
37 #include "status_w.h"
38
39 #include <asm/segment.h>
40
41
42 #define __BAD__ Un_impl
43
44 #ifndef NO_UNDOC_CODE
45
46
47
48
49
50
51 #define _d9_d8_ fstp_i
52 #define _dc_d0_ fcom_st
53 #define _dc_d8_ fcompst
54 #define _dd_c8_ fxch_i
55 #define _de_d0_ fcompst
56 #define _df_c0_ ffreep
57 #define _df_c8_ fxch_i
58 #define _df_d0_ fstp_i
59 #define _df_d8_ fstp_i
60
61 static FUNC st_instr_table[64] = {
62 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
63 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
64 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
65 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
66 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
67 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
68 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
69 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
70 };
71
72 #else
73
74 static FUNC st_instr_table[64] = {
75 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
76 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
77 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
78 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
79 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
80 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
81 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
82 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
83 };
84
85 #endif NO_UNDOC_CODE
86
87
88 #define _NONE_ 0
89 #define _REG0_ 1
90 #define _REGI_ 2
91 #define _REGi_ 0
92 #define _PUSH_ 3
93 #define _null_ 4
94 #define _REGIi 5
95 #define _REGIp 6
96 #define _REGIc 0
97 #define _REGIn 0
98
99 #ifndef NO_UNDOC_CODE
100
101
102
103 static unsigned char type_table[64] = {
104 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
105 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
106 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
107 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
108 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
109 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
110 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
111 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
112 };
113
114 #else
115
116 static unsigned char type_table[64] = {
117 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
118 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
119 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
120 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
121 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
122 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
123 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
124 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
125 };
126
127 #endif NO_UNDOC_CODE
128
129
130
131
132 unsigned char FPU_rm;
133 char FPU_st0_tag;
134 FPU_REG *FPU_st0_ptr;
135
136 #ifdef PARANOID
137 char emulating=0;
138 #endif PARANOID
139
140 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
141
142
143 extern "C" void math_emulate(long arg)
144 {
145 unsigned char FPU_modrm;
146 unsigned short code;
147
148 #ifdef PARANOID
149 if ( emulating )
150 {
151 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
152 }
153 RE_ENTRANT_CHECK_ON
154 #endif PARANOID
155
156 if (!current->used_math)
157 {
158 finit();
159 current->used_math = 1;
160 }
161
162 FPU_info = (struct info *) &arg;
163
164
165 if (FPU_EFLAGS & 0x00020000)
166 {
167 FPU_ORIG_EIP = FPU_EIP;
168 math_abort(FPU_info,SIGILL);
169 }
170
171
172 if (FPU_CS != USER_CS)
173 {
174 printk("math_emulate: %04x:%08x\n",FPU_CS,FPU_EIP);
175 panic("Math emulation needed in kernel");
176 }
177
178 FPU_lookahead = 1;
179 if (current->flags & PF_PTRACED)
180 FPU_lookahead = 0;
181
182 do_another_FPU_instruction:
183
184 RE_ENTRANT_CHECK_OFF
185 code = get_fs_word((unsigned short *) FPU_EIP);
186 RE_ENTRANT_CHECK_ON
187
188 if ( (code & 0xff) == 0x9b )
189 {
190 if (status_word & SW_Summary)
191 goto do_the_FPU_interrupt;
192 else
193 {
194 FPU_EIP++;
195 goto FPU_instruction_done;
196 }
197 }
198
199 if (status_word & SW_Summary)
200 {
201
202
203
204
205
206
207
208 if ( ! ( (((code & 0xf803) == 0xe003) ||
209 (((code & 0x3003) == 0x3001) &&
210
211 ((code & 0xc000) != 0xc000))) ) )
212 {
213
214
215
216
217
218
219
220
221
222
223
224 do_the_FPU_interrupt:
225 cs_selector &= 0xffff0000;
226 cs_selector |= (status_word & ~SW_Top) | ((top&7) << SW_Top_Shift);
227 operand_selector = tag_word();
228 status_word = 0;
229 top = 0;
230 {
231 int r;
232 for (r = 0; r < 8; r++)
233 {
234 regs[r].tag = TW_Empty;
235 }
236 }
237
238 RE_ENTRANT_CHECK_OFF
239 send_sig(SIGFPE, current, 1);
240 return;
241 }
242 }
243
244 FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
245
246 if ( (code & 0xff) == 0x66 )
247 {
248 FPU_EIP++;
249 RE_ENTRANT_CHECK_OFF
250 code = get_fs_word((unsigned short *) FPU_EIP);
251 RE_ENTRANT_CHECK_ON
252 }
253 FPU_EIP += 2;
254
255 FPU_modrm = code >> 8;
256 FPU_rm = FPU_modrm & 7;
257
258 if ( FPU_modrm < 0300 )
259 {
260
261 get_address(FPU_modrm);
262 if ( !(code & 1) )
263 {
264 unsigned short status1 = status_word;
265 FPU_st0_ptr = &st(0);
266 FPU_st0_tag = FPU_st0_ptr->tag;
267
268
269 if ( NOT_EMPTY_0 )
270 {
271 switch ( (code >> 1) & 3 )
272 {
273 case 0:
274 reg_load_single();
275 break;
276 case 1:
277 reg_load_int32();
278 break;
279 case 2:
280 reg_load_double();
281 break;
282 case 3:
283 reg_load_int16();
284 break;
285 }
286
287
288
289 FPU_st0_ptr = &st(0);
290 FPU_st0_tag = FPU_st0_ptr->tag;
291
292
293
294
295 if ( (FPU_st0_tag == TW_NaN) ||
296 (FPU_loaded_data.tag == TW_NaN) )
297 {
298
299
300 status_word = status1;
301 if ( (FPU_modrm & 0x30) == 0x10 )
302 {
303
304 EXCEPTION(EX_Invalid);
305 setcc(SW_C3 | SW_C2 | SW_C0);
306 if ( FPU_modrm & 0x08 )
307 pop();
308 }
309 else
310 real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
311 goto reg_mem_instr_done;
312 }
313
314 switch ( (FPU_modrm >> 3) & 7 )
315 {
316 case 0:
317 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
318 control_word);
319 break;
320 case 1:
321 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
322 control_word);
323 break;
324 case 2:
325 compare_st_data();
326 break;
327 case 3:
328 compare_st_data();
329 pop();
330 break;
331 case 4:
332 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
333 control_word);
334 break;
335 case 5:
336 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
337 control_word);
338 break;
339 case 6:
340 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
341 control_word);
342 break;
343 case 7:
344 if ( FPU_st0_tag == TW_Zero )
345 status_word = status1;
346
347 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
348 control_word);
349 break;
350 }
351 }
352 else
353 {
354 if ( (FPU_modrm & 0x30) == 0x10 )
355 {
356
357 EXCEPTION(EX_StackUnder);
358 setcc(SW_C3 | SW_C2 | SW_C0);
359 if ( FPU_modrm & 0x08 )
360 pop();
361 }
362 else
363 stack_underflow();
364 }
365 }
366 else
367 {
368 load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
369 }
370
371 reg_mem_instr_done:
372
373 data_operand_offset = (unsigned long)FPU_data_address;
374 }
375 else
376 {
377
378 unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
379
380 FPU_st0_ptr = &st(0);
381 FPU_st0_tag = FPU_st0_ptr->tag;
382 switch ( type_table[(int) instr_index] )
383 {
384 case _NONE_:
385 break;
386 case _REG0_:
387 if ( !NOT_EMPTY_0 )
388 {
389 stack_underflow();
390 goto FPU_instruction_done;
391 }
392 break;
393 case _REGIi:
394 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
395 {
396 stack_underflow_i(FPU_rm);
397 goto FPU_instruction_done;
398 }
399 break;
400 case _REGIp:
401 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
402 {
403 stack_underflow_i(FPU_rm);
404 pop();
405 goto FPU_instruction_done;
406 }
407 break;
408 case _REGI_:
409 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
410 {
411 stack_underflow();
412 goto FPU_instruction_done;
413 }
414 break;
415 case _PUSH_:
416 break;
417 case _null_:
418 Un_impl();
419 goto FPU_instruction_done;
420 default:
421 EXCEPTION(EX_INTERNAL|0x111);
422 goto FPU_instruction_done;
423 }
424 (*st_instr_table[(int) instr_index])();
425 }
426
427 FPU_instruction_done:
428
429 ip_offset = FPU_entry_eip;
430 bswapw(code);
431 *(1 + (unsigned short *)&cs_selector) = code & 0x7ff;
432
433 #ifdef DEBUG
434 RE_ENTRANT_CHECK_OFF
435 emu_printall();
436 RE_ENTRANT_CHECK_ON
437 #endif DEBUG
438
439 if (FPU_lookahead && !need_resched)
440 {
441 unsigned char next;
442
443
444 while ( 1 )
445 {
446 RE_ENTRANT_CHECK_OFF
447 next = get_fs_byte((unsigned char *) FPU_EIP);
448 RE_ENTRANT_CHECK_ON
449 if ( ((next & 0xf8) == 0xd8) || (next == 0x9b) )
450 {
451 goto do_another_FPU_instruction;
452 }
453 else if ( next == 0x66 )
454 {
455 RE_ENTRANT_CHECK_OFF
456 next = get_fs_byte((unsigned char *) (FPU_EIP+1));
457 RE_ENTRANT_CHECK_ON
458 if ( (next & 0xf8) == 0xd8 )
459 {
460 FPU_EIP++;
461 goto do_another_FPU_instruction;
462 }
463 }
464 break;
465 }
466 }
467
468 RE_ENTRANT_CHECK_OFF
469 }
470
471
472 void __math_abort(struct info * info, unsigned int signal)
473 {
474 FPU_EIP = FPU_ORIG_EIP;
475 send_sig(signal,current,1);
476 RE_ENTRANT_CHECK_OFF
477 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
478 #ifdef PARANOID
479 printk("ERROR: wm-FPU-emu math_abort failed!\n");
480 #endif PARANOID
481 }
482
483 #else
484
485 #include <linux/signal.h>
486 #include <linux/sched.h>
487
488 extern "C" void math_emulate(long arg)
489 {
490 printk("math-meulation not enabled and no coprocessor found.\n");
491 printk("killing %s.\n",current->comm);
492 send_sig(SIGFPE,current,1);
493 schedule();
494 }
495
496 #endif