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