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 code = get_fs_word((unsigned short *) FPU_EIP);
213 RE_ENTRANT_CHECK_ON;
214
215 #ifdef PECULIAR_486
216
217
218
219 FPU_data_selector = FPU_DS;
220 #endif PECULIAR_486
221
222 if ( (code & 0xf8) != 0xd8 )
223 {
224 if ( (code & 0xff) == FWAIT_OPCODE )
225 {
226 if (partial_status & SW_Summary)
227 goto do_the_FPU_interrupt;
228 else
229 {
230 FPU_EIP++;
231 goto FPU_fwait_done;
232 }
233 }
234 else if ( valid_prefix(code & 0xff) )
235 {
236 goto do_another_FPU_instruction;
237 }
238 #ifdef PARANOID
239 RE_ENTRANT_CHECK_OFF;
240 printk("FPU emulator: Unknown prefix byte 0x%02x\n", code & 0xff);
241 RE_ENTRANT_CHECK_ON;
242 EXCEPTION(EX_INTERNAL|0x126);
243 FPU_EIP++;
244 goto do_the_FPU_interrupt;
245 #endif PARANOID
246 }
247
248 if (partial_status & SW_Summary)
249 {
250
251
252
253
254
255
256
257 if ( ! ( (((code & 0xf803) == 0xe003) ||
258 (((code & 0x3003) == 0x3001) &&
259
260 ((code & 0xc000) != 0xc000))) ) )
261 {
262
263
264
265
266
267
268
269
270 do_the_FPU_interrupt:
271 cs_selector &= 0xffff0000;
272 cs_selector |= status_word();
273 operand_selector = tag_word();
274 partial_status = 0;
275 top = 0;
276 {
277 int r;
278 for (r = 0; r < 8; r++)
279 {
280 regs[r].tag = TW_Empty;
281 }
282 }
283
284 RE_ENTRANT_CHECK_OFF;
285 current->tss.trap_no = 16;
286 current->tss.error_code = 0;
287 send_sig(SIGFPE, current, 1);
288 return;
289 }
290 }
291
292 FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
293
294 {
295 unsigned short swapped_code = code;
296 bswapw(swapped_code);
297 FPU_entry_op_cs = (swapped_code << 16) | (FPU_CS & 0xffff) ;
298 }
299
300 if ( (code & 0xff) == OP_SIZE_PREFIX )
301 {
302 FPU_EIP++;
303 RE_ENTRANT_CHECK_OFF;
304 code = get_fs_word((unsigned short *) FPU_EIP);
305 RE_ENTRANT_CHECK_ON;
306 }
307 FPU_EIP += 2;
308
309 FPU_modrm = code >> 8;
310 FPU_rm = FPU_modrm & 7;
311
312 if ( FPU_modrm < 0300 )
313 {
314
315 get_address(FPU_modrm);
316 if ( !(code & 1) )
317 {
318 unsigned short status1 = partial_status;
319 FPU_st0_ptr = &st(0);
320 FPU_st0_tag = FPU_st0_ptr->tag;
321
322
323 if ( NOT_EMPTY_0 )
324 {
325 unmasked = 0;
326 switch ( (code >> 1) & 3 )
327 {
328 case 0:
329 unmasked = reg_load_single();
330 break;
331 case 1:
332 reg_load_int32();
333 break;
334 case 2:
335 unmasked = reg_load_double();
336 break;
337 case 3:
338 reg_load_int16();
339 break;
340 }
341
342
343
344 FPU_st0_ptr = &st(0);
345 FPU_st0_tag = FPU_st0_ptr->tag;
346
347
348
349
350 if ( (FPU_st0_tag == TW_NaN) ||
351 (FPU_loaded_data.tag == TW_NaN) )
352 {
353
354
355 partial_status = status1;
356 if ( (FPU_modrm & 0x30) == 0x10 )
357 {
358
359 EXCEPTION(EX_Invalid);
360 setcc(SW_C3 | SW_C2 | SW_C0);
361 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
362 pop();
363 }
364 else
365 {
366 #ifdef PECULIAR_486
367
368
369 if ( (FPU_modrm & 0x28) == 0x20 )
370
371 real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
372 FPU_st0_ptr);
373 else
374 #endif PECULIAR_486
375
376 real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
377 FPU_st0_ptr);
378 }
379 goto reg_mem_instr_done;
380 }
381
382 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
383 {
384
385 if ( (FPU_modrm & 0x38) == 0x38 )
386 {
387
388 if ( (FPU_st0_tag == TW_Zero) &&
389 (FPU_loaded_data.tag == TW_Valid) )
390 {
391 if ( divide_by_zero(FPU_loaded_data.sign,
392 FPU_st0_ptr) )
393 {
394
395
396
397
398 partial_status &= ~SW_Denorm_Op;
399 partial_status |= status1 & SW_Denorm_Op;
400 }
401 }
402 }
403 goto reg_mem_instr_done;
404 }
405
406 switch ( (FPU_modrm >> 3) & 7 )
407 {
408 case 0:
409 clear_C1();
410 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
411 control_word);
412 break;
413 case 1:
414 clear_C1();
415 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
416 control_word);
417 break;
418 case 2:
419 compare_st_data();
420 break;
421 case 3:
422 if ( !compare_st_data() && !unmasked )
423 pop();
424 break;
425 case 4:
426 clear_C1();
427 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
428 control_word);
429 break;
430 case 5:
431 clear_C1();
432 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
433 control_word);
434 break;
435 case 6:
436 clear_C1();
437 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
438 control_word);
439 break;
440 case 7:
441 clear_C1();
442 if ( FPU_st0_tag == TW_Zero )
443 partial_status = status1;
444
445 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
446 control_word);
447 break;
448 }
449 }
450 else
451 {
452 if ( (FPU_modrm & 0x30) == 0x10 )
453 {
454
455 EXCEPTION(EX_StackUnder);
456 setcc(SW_C3 | SW_C2 | SW_C0);
457 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
458 pop();
459 }
460 else
461 stack_underflow();
462 }
463 }
464 else
465 {
466 load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
467 }
468
469 reg_mem_instr_done:
470
471 #ifndef PECULIAR_486
472 *(unsigned short *)&operand_selector = FPU_data_selector;
473 #endif PECULIAR_486
474 ;
475 }
476 else
477 {
478
479 unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
480
481 #ifdef PECULIAR_486
482
483
484 FPU_data_address = 0;
485 #endif PECULIAR_486
486
487 FPU_st0_ptr = &st(0);
488 FPU_st0_tag = FPU_st0_ptr->tag;
489 switch ( type_table[(int) instr_index] )
490 {
491 case _NONE_:
492 break;
493 case _REG0_:
494 if ( !NOT_EMPTY_0 )
495 {
496 stack_underflow();
497 goto FPU_instruction_done;
498 }
499 break;
500 case _REGIi:
501 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
502 {
503 stack_underflow_i(FPU_rm);
504 goto FPU_instruction_done;
505 }
506 break;
507 case _REGIp:
508 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
509 {
510 stack_underflow_pop(FPU_rm);
511 goto FPU_instruction_done;
512 }
513 break;
514 case _REGI_:
515 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
516 {
517 stack_underflow();
518 goto FPU_instruction_done;
519 }
520 break;
521 case _PUSH_:
522 break;
523 case _null_:
524 Un_impl();
525 goto FPU_instruction_done;
526 default:
527 EXCEPTION(EX_INTERNAL|0x111);
528 goto FPU_instruction_done;
529 }
530 (*st_instr_table[(int) instr_index])();
531 }
532
533 FPU_instruction_done:
534
535 #ifdef DEBUG
536 {
537 static unsigned int count = 0;
538 if ( (++count % 10000) == 0 )
539 printk("%d FP instr., current=0x%04x\n", count, code);
540 }
541 #endif DEBUG
542
543 ip_offset = FPU_entry_eip;
544 cs_selector = FPU_entry_op_cs;
545 data_operand_offset = (unsigned long)FPU_data_address;
546 #ifdef PECULIAR_486
547 *(unsigned short *)&operand_selector = FPU_data_selector;
548 #endif PECULIAR_486
549
550 FPU_fwait_done:
551
552 #ifdef DEBUG
553 RE_ENTRANT_CHECK_OFF;
554 emu_printall();
555 RE_ENTRANT_CHECK_ON;
556 #endif DEBUG
557
558 if (FPU_lookahead && !need_resched)
559 {
560 unsigned char next;
561
562 RE_ENTRANT_CHECK_OFF;
563 next = get_fs_byte((unsigned char *) FPU_EIP);
564 RE_ENTRANT_CHECK_ON;
565 if ( valid_prefix(next) )
566 goto do_another_FPU_instruction;
567 }
568
569 RE_ENTRANT_CHECK_OFF;
570 }
571
572
573
574
575
576
577 static int valid_prefix(unsigned char byte)
578 {
579 unsigned long ip = FPU_EIP;
580
581 while ( 1 )
582 {
583 switch ( byte )
584 {
585 case ADDR_SIZE_PREFIX:
586 case PREFIX_DS:
587 case PREFIX_CS:
588 case PREFIX_ES:
589 case PREFIX_SS:
590 case PREFIX_FS:
591 case PREFIX_GS:
592
593 case OP_SIZE_PREFIX:
594 RE_ENTRANT_CHECK_OFF;
595 byte = get_fs_byte((unsigned char *) (++FPU_EIP));
596 RE_ENTRANT_CHECK_ON;
597 break;
598 case FWAIT_OPCODE:
599 return 1;
600 default:
601 if ( (byte & 0xf8) == 0xd8 )
602 return 1;
603 else
604 {
605 FPU_EIP = ip;
606 return 0;
607 }
608 }
609 }
610 }
611
612
613 void __math_abort(struct info * info, unsigned int signal)
614 {
615 FPU_EIP = FPU_ORIG_EIP;
616 current->tss.trap_no = 16;
617 current->tss.error_code = 0;
618 send_sig(signal,current,1);
619 RE_ENTRANT_CHECK_OFF;
620 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
621 #ifdef PARANOID
622 printk("ERROR: wm-FPU-emu math_abort failed!\n");
623 #endif PARANOID
624 }