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