This source file includes following definitions.
- math_emulate
- valid_prefix
- __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 #define FWAIT_OPCODE 0x9b
42 #define OP_SIZE_PREFIX 0x66
43 #define ADDR_SIZE_PREFIX 0x67
44 #define PREFIX_CS 0x2e
45 #define PREFIX_DS 0x3e
46 #define PREFIX_ES 0x26
47 #define PREFIX_SS 0x36
48 #define PREFIX_FS 0x64
49 #define PREFIX_GS 0x65
50
51 #define __BAD__ Un_impl
52
53 #ifndef NO_UNDOC_CODE
54
55
56
57
58
59
60 #define _d9_d8_ fstp_i
61 #define _dc_d0_ fcom_st
62 #define _dc_d8_ fcompst
63 #define _dd_c8_ fxch_i
64 #define _de_d0_ fcompst
65 #define _df_c0_ ffreep
66 #define _df_c8_ fxch_i
67 #define _df_d0_ fstp_i
68 #define _df_d8_ fstp_i
69
70 static FUNC st_instr_table[64] = {
71 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
72 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
73 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
74 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
75 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
76 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
77 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
78 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
79 };
80
81 #else
82
83 static FUNC st_instr_table[64] = {
84 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
85 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
86 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
87 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
88 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
89 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
90 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
91 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
92 };
93
94 #endif NO_UNDOC_CODE
95
96
97 #define _NONE_ 0
98 #define _REG0_ 1
99 #define _REGI_ 2
100 #define _REGi_ 0
101 #define _PUSH_ 3
102 #define _null_ 4
103 #define _REGIi 5
104 #define _REGIp 6
105 #define _REGIc 0
106 #define _REGIn 0
107
108 #ifndef NO_UNDOC_CODE
109
110
111
112 static unsigned char type_table[64] = {
113 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
114 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
115 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
116 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
117 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
118 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
119 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
120 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
121 };
122
123 #else
124
125 static unsigned char type_table[64] = {
126 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
127 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
128 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
129 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
130 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
131 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
132 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
133 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
134 };
135
136 #endif NO_UNDOC_CODE
137
138
139
140
141 unsigned char FPU_rm;
142 char FPU_st0_tag;
143 FPU_REG *FPU_st0_ptr;
144
145
146 unsigned long FPU_entry_op_cs;
147 unsigned short FPU_data_selector;
148
149
150 #ifdef PARANOID
151 char emulating=0;
152 #endif PARANOID
153
154 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
155 static int valid_prefix(unsigned char byte);
156
157
158 asmlinkage void math_emulate(long arg)
159 {
160 unsigned char FPU_modrm;
161 unsigned short code;
162 int unmasked;
163
164 #ifdef PARANOID
165 if ( emulating )
166 {
167 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
168 }
169 RE_ENTRANT_CHECK_ON;
170 #endif PARANOID
171
172 if (!current->used_math)
173 {
174 int i;
175 for ( i = 0; i < 8; i++ )
176 {
177
178
179 regs[i].exp = 0;
180 regs[i].sigh = 0x80000000;
181 }
182 finit();
183 current->used_math = 1;
184 }
185
186 SETUP_DATA_AREA(arg);
187
188
189 if (FPU_EFLAGS & 0x00020000)
190 {
191 FPU_ORIG_EIP = FPU_EIP;
192 math_abort(FPU_info,SIGILL);
193 }
194
195
196 if (FPU_CS != USER_CS)
197 {
198 printk("math_emulate: %04x:%08x\n",FPU_CS,FPU_EIP);
199 panic("Math emulation needed in kernel");
200 }
201
202 FPU_lookahead = 1;
203 if (current->flags & PF_PTRACED)
204 FPU_lookahead = 0;
205
206 do_another_FPU_instruction:
207
208 RE_ENTRANT_CHECK_OFF;
209 code = get_fs_word((unsigned short *) FPU_EIP);
210 RE_ENTRANT_CHECK_ON;
211
212 #ifdef PECULIAR_486
213
214
215
216 FPU_data_selector = FPU_DS;
217 #endif PECULIAR_486
218
219 if ( (code & 0xf8) != 0xd8 )
220 {
221 if ( (code & 0xff) == FWAIT_OPCODE )
222 {
223 if (partial_status & SW_Summary)
224 goto do_the_FPU_interrupt;
225 else
226 {
227 FPU_EIP++;
228 goto FPU_fwait_done;
229 }
230 }
231 else if ( valid_prefix(code & 0xff) )
232 {
233 goto do_another_FPU_instruction;
234 }
235 #ifdef PARANOID
236 RE_ENTRANT_CHECK_OFF;
237 printk("FPU emulator: Unknown prefix byte 0x%02x\n", code & 0xff);
238 RE_ENTRANT_CHECK_ON;
239 EXCEPTION(EX_INTERNAL|0x126);
240 FPU_EIP++;
241 goto do_the_FPU_interrupt;
242 #endif PARANOID
243 }
244
245 if (partial_status & SW_Summary)
246 {
247
248
249
250
251
252
253
254 if ( ! ( (((code & 0xf803) == 0xe003) ||
255 (((code & 0x3003) == 0x3001) &&
256
257 ((code & 0xc000) != 0xc000))) ) )
258 {
259
260
261
262
263
264
265
266
267 do_the_FPU_interrupt:
268 cs_selector &= 0xffff0000;
269 cs_selector |= status_word();
270 operand_selector = tag_word();
271 partial_status = 0;
272 top = 0;
273 {
274 int r;
275 for (r = 0; r < 8; r++)
276 {
277 regs[r].tag = TW_Empty;
278 }
279 }
280
281 RE_ENTRANT_CHECK_OFF;
282 send_sig(SIGFPE, current, 1);
283 return;
284 }
285 }
286
287 FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
288
289 {
290 unsigned short swapped_code = code;
291 bswapw(swapped_code);
292 FPU_entry_op_cs = (swapped_code << 16) | (FPU_CS & 0xffff) ;
293 }
294
295 if ( (code & 0xff) == OP_SIZE_PREFIX )
296 {
297 FPU_EIP++;
298 RE_ENTRANT_CHECK_OFF;
299 code = get_fs_word((unsigned short *) FPU_EIP);
300 RE_ENTRANT_CHECK_ON;
301 }
302 FPU_EIP += 2;
303
304 FPU_modrm = code >> 8;
305 FPU_rm = FPU_modrm & 7;
306
307 if ( FPU_modrm < 0300 )
308 {
309
310 get_address(FPU_modrm);
311 if ( !(code & 1) )
312 {
313 unsigned short status1 = partial_status;
314 FPU_st0_ptr = &st(0);
315 FPU_st0_tag = FPU_st0_ptr->tag;
316
317
318 if ( NOT_EMPTY_0 )
319 {
320 unmasked = 0;
321 switch ( (code >> 1) & 3 )
322 {
323 case 0:
324 unmasked = reg_load_single();
325 break;
326 case 1:
327 reg_load_int32();
328 break;
329 case 2:
330 unmasked = reg_load_double();
331 break;
332 case 3:
333 reg_load_int16();
334 break;
335 }
336
337
338
339 FPU_st0_ptr = &st(0);
340 FPU_st0_tag = FPU_st0_ptr->tag;
341
342
343
344
345 if ( (FPU_st0_tag == TW_NaN) ||
346 (FPU_loaded_data.tag == TW_NaN) )
347 {
348
349
350 partial_status = status1;
351 if ( (FPU_modrm & 0x30) == 0x10 )
352 {
353
354 EXCEPTION(EX_Invalid);
355 setcc(SW_C3 | SW_C2 | SW_C0);
356 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
357 pop();
358 }
359 else
360 {
361 #ifdef PECULIAR_486
362
363
364 if ( (FPU_modrm & 0x28) == 0x20 )
365
366 real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
367 FPU_st0_ptr);
368 else
369 #endif PECULIAR_486
370
371 real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
372 FPU_st0_ptr);
373 }
374 goto reg_mem_instr_done;
375 }
376
377 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
378 {
379
380 if ( (FPU_modrm & 0x38) == 0x38 )
381 {
382
383 if ( (FPU_st0_tag == TW_Zero) &&
384 (FPU_loaded_data.tag == TW_Valid) )
385 {
386 if ( divide_by_zero(FPU_loaded_data.sign,
387 FPU_st0_ptr) )
388 {
389
390
391
392
393 partial_status &= ~SW_Denorm_Op;
394 partial_status |= status1 & SW_Denorm_Op;
395 }
396 }
397 }
398 goto reg_mem_instr_done;
399 }
400
401 switch ( (FPU_modrm >> 3) & 7 )
402 {
403 case 0:
404 clear_C1();
405 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
406 control_word);
407 break;
408 case 1:
409 clear_C1();
410 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
411 control_word);
412 break;
413 case 2:
414 compare_st_data();
415 break;
416 case 3:
417 if ( !compare_st_data() && !unmasked )
418 pop();
419 break;
420 case 4:
421 clear_C1();
422 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
423 control_word);
424 break;
425 case 5:
426 clear_C1();
427 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
428 control_word);
429 break;
430 case 6:
431 clear_C1();
432 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
433 control_word);
434 break;
435 case 7:
436 clear_C1();
437 if ( FPU_st0_tag == TW_Zero )
438 partial_status = status1;
439
440 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
441 control_word);
442 break;
443 }
444 }
445 else
446 {
447 if ( (FPU_modrm & 0x30) == 0x10 )
448 {
449
450 EXCEPTION(EX_StackUnder);
451 setcc(SW_C3 | SW_C2 | SW_C0);
452 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
453 pop();
454 }
455 else
456 stack_underflow();
457 }
458 }
459 else
460 {
461 load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
462 }
463
464 reg_mem_instr_done:
465
466 #ifndef PECULIAR_486
467 *(unsigned short *)&operand_selector = FPU_data_selector;
468 #endif PECULIAR_486
469 ;
470 }
471 else
472 {
473
474 unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
475
476 #ifdef PECULIAR_486
477
478
479 FPU_data_address = 0;
480 #endif PECULIAR_486
481
482 FPU_st0_ptr = &st(0);
483 FPU_st0_tag = FPU_st0_ptr->tag;
484 switch ( type_table[(int) instr_index] )
485 {
486 case _NONE_:
487 break;
488 case _REG0_:
489 if ( !NOT_EMPTY_0 )
490 {
491 stack_underflow();
492 goto FPU_instruction_done;
493 }
494 break;
495 case _REGIi:
496 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
497 {
498 stack_underflow_i(FPU_rm);
499 goto FPU_instruction_done;
500 }
501 break;
502 case _REGIp:
503 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
504 {
505 stack_underflow_pop(FPU_rm);
506 goto FPU_instruction_done;
507 }
508 break;
509 case _REGI_:
510 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
511 {
512 stack_underflow();
513 goto FPU_instruction_done;
514 }
515 break;
516 case _PUSH_:
517 break;
518 case _null_:
519 Un_impl();
520 goto FPU_instruction_done;
521 default:
522 EXCEPTION(EX_INTERNAL|0x111);
523 goto FPU_instruction_done;
524 }
525 (*st_instr_table[(int) instr_index])();
526 }
527
528 FPU_instruction_done:
529
530 ip_offset = FPU_entry_eip;
531 cs_selector = FPU_entry_op_cs;
532 data_operand_offset = (unsigned long)FPU_data_address;
533 #ifdef PECULIAR_486
534 *(unsigned short *)&operand_selector = FPU_data_selector;
535 #endif PECULIAR_486
536
537 FPU_fwait_done:
538
539 #ifdef DEBUG
540 RE_ENTRANT_CHECK_OFF;
541 emu_printall();
542 RE_ENTRANT_CHECK_ON;
543 #endif DEBUG
544
545 if (FPU_lookahead && !need_resched)
546 {
547 unsigned char next;
548
549 RE_ENTRANT_CHECK_OFF;
550 next = get_fs_byte((unsigned char *) FPU_EIP);
551 RE_ENTRANT_CHECK_ON;
552 if ( valid_prefix(next) )
553 goto do_another_FPU_instruction;
554 }
555
556 RE_ENTRANT_CHECK_OFF;
557 }
558
559
560
561
562
563
564 static int valid_prefix(unsigned char byte)
565 {
566 unsigned long ip = FPU_EIP;
567
568 while ( 1 )
569 {
570 switch ( byte )
571 {
572 case ADDR_SIZE_PREFIX:
573 case PREFIX_DS:
574 case PREFIX_CS:
575 case PREFIX_ES:
576 case PREFIX_SS:
577 case PREFIX_FS:
578 case PREFIX_GS:
579
580 case OP_SIZE_PREFIX:
581 RE_ENTRANT_CHECK_OFF;
582 byte = get_fs_byte((unsigned char *) (++FPU_EIP));
583 RE_ENTRANT_CHECK_ON;
584 break;
585 case FWAIT_OPCODE:
586 return 1;
587 default:
588 if ( (byte & 0xf8) == 0xd8 )
589 return 1;
590 else
591 {
592 FPU_EIP = ip;
593 return 0;
594 }
595 }
596 }
597 }
598
599
600 void __math_abort(struct info * info, unsigned int signal)
601 {
602 FPU_EIP = FPU_ORIG_EIP;
603 send_sig(signal,current,1);
604 RE_ENTRANT_CHECK_OFF;
605 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
606 #ifdef PARANOID
607 printk("ERROR: wm-FPU-emu math_abort failed!\n");
608 #endif PARANOID
609 }
610
611 #else
612
613 #include <linux/signal.h>
614 #include <linux/sched.h>
615
616 asmlinkage void math_emulate(long arg)
617 {
618 printk("math-emulation not enabled and no coprocessor found.\n");
619 printk("killing %s.\n",current->comm);
620 send_sig(SIGFPE,current,1);
621 schedule();
622 }
623
624 #endif