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
177 if ( addr_modes.vm86 )
178 FPU_EIP += FPU_CS << 4;
179
180 FPU_ORIG_EIP = FPU_EIP;
181
182 if ( !addr_modes.vm86 )
183 {
184
185 if (FPU_CS == KERNEL_CS)
186 {
187 printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
188 panic("Math emulation needed in kernel");
189 }
190
191
192 if (FPU_CS != USER_CS || FPU_DS != USER_DS)
193 {
194 math_abort(FPU_info,SIGILL);
195 }
196 }
197
198 FPU_lookahead = 1;
199 if (current->flags & PF_PTRACED)
200 FPU_lookahead = 0;
201
202 if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
203 &addr_modes.override) )
204 {
205 RE_ENTRANT_CHECK_OFF;
206 printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
207 "FPU emulator: self-modifying code! (emulation impossible)\n",
208 byte1);
209 RE_ENTRANT_CHECK_ON;
210 EXCEPTION(EX_INTERNAL|0x126);
211 math_abort(FPU_info,SIGILL);
212 }
213
214 do_another_FPU_instruction:
215
216 FPU_EIP++;
217
218 #ifdef PECULIAR_486
219
220
221
222 FPU_data_selector = FPU_DS;
223 #endif PECULIAR_486
224
225 if ( (byte1 & 0xf8) != 0xd8 )
226 {
227 if ( byte1 == FWAIT_OPCODE )
228 {
229 if (partial_status & SW_Summary)
230 goto do_the_FPU_interrupt;
231 else
232 goto FPU_fwait_done;
233 }
234 #ifdef PARANOID
235 EXCEPTION(EX_INTERNAL|0x128);
236 math_abort(FPU_info,SIGILL);
237 #endif PARANOID
238 }
239
240 RE_ENTRANT_CHECK_OFF;
241 FPU_code_verify_area(1);
242 FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP);
243 RE_ENTRANT_CHECK_ON;
244 FPU_EIP++;
245
246 if (partial_status & SW_Summary)
247 {
248
249
250
251
252
253
254 code = (FPU_modrm << 8) | byte1;
255 if ( ! ( (((code & 0xf803) == 0xe003) ||
256 (((code & 0x3003) == 0x3001) &&
257
258 ((code & 0xc000) != 0xc000))) ) )
259 {
260
261
262
263
264
265
266
267
268 do_the_FPU_interrupt:
269 cs_selector &= 0xffff0000;
270 cs_selector |= status_word();
271 operand_selector = tag_word();
272 partial_status = 0;
273 top = 0;
274 {
275 int r;
276 for (r = 0; r < 8; r++)
277 {
278 regs[r].tag = TW_Empty;
279 }
280 }
281
282 FPU_EIP = FPU_ORIG_EIP;
283
284 if ( addr_modes.vm86 )
285 FPU_EIP -= FPU_CS << 4;
286
287 RE_ENTRANT_CHECK_OFF;
288 current->tss.trap_no = 16;
289 current->tss.error_code = 0;
290 send_sig(SIGFPE, current, 1);
291 return;
292 }
293 }
294
295 FPU_entry_eip = FPU_ORIG_EIP;
296
297 FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
298
299 FPU_rm = FPU_modrm & 7;
300
301 if ( FPU_modrm < 0300 )
302 {
303
304 if ( addr_modes.vm86
305 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
306 get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
307 else
308 get_address(FPU_modrm, &FPU_EIP, addr_modes);
309
310 if ( !(byte1 & 1) )
311 {
312 unsigned short status1 = partial_status;
313 FPU_st0_ptr = &st(0);
314 FPU_st0_tag = FPU_st0_ptr->tag;
315
316
317 if ( NOT_EMPTY_0 )
318 {
319 unmasked = 0;
320 switch ( (byte1 >> 1) & 3 )
321 {
322 case 0:
323 unmasked = reg_load_single();
324 break;
325 case 1:
326 reg_load_int32();
327 break;
328 case 2:
329 unmasked = reg_load_double();
330 break;
331 case 3:
332 reg_load_int16();
333 break;
334 }
335
336
337
338 FPU_st0_ptr = &st(0);
339 FPU_st0_tag = FPU_st0_ptr->tag;
340
341
342
343
344 if ( (FPU_st0_tag == TW_NaN) ||
345 (FPU_loaded_data.tag == TW_NaN) )
346 {
347
348
349 partial_status = status1;
350 if ( (FPU_modrm & 0x30) == 0x10 )
351 {
352
353 EXCEPTION(EX_Invalid);
354 setcc(SW_C3 | SW_C2 | SW_C0);
355 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
356 pop();
357 }
358 else
359 {
360 #ifdef PECULIAR_486
361
362
363 if ( (FPU_modrm & 0x28) == 0x20 )
364
365 real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
366 FPU_st0_ptr);
367 else
368 #endif PECULIAR_486
369
370 real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
371 FPU_st0_ptr);
372 }
373 goto reg_mem_instr_done;
374 }
375
376 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
377 {
378
379 if ( (FPU_modrm & 0x38) == 0x38 )
380 {
381
382 if ( (FPU_st0_tag == TW_Zero) &&
383 (FPU_loaded_data.tag == TW_Valid) )
384 {
385 if ( divide_by_zero(FPU_loaded_data.sign,
386 FPU_st0_ptr) )
387 {
388
389
390
391
392 partial_status &= ~SW_Denorm_Op;
393 partial_status |= status1 & SW_Denorm_Op;
394 }
395 }
396 }
397 goto reg_mem_instr_done;
398 }
399
400 switch ( (FPU_modrm >> 3) & 7 )
401 {
402 case 0:
403 clear_C1();
404 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
405 control_word);
406 break;
407 case 1:
408 clear_C1();
409 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
410 control_word);
411 break;
412 case 2:
413 compare_st_data();
414 break;
415 case 3:
416 if ( !compare_st_data() && !unmasked )
417 pop();
418 break;
419 case 4:
420 clear_C1();
421 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
422 control_word);
423 break;
424 case 5:
425 clear_C1();
426 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
427 control_word);
428 break;
429 case 6:
430 clear_C1();
431 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
432 control_word);
433 break;
434 case 7:
435 clear_C1();
436 if ( FPU_st0_tag == TW_Zero )
437 partial_status = status1;
438
439 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
440 control_word);
441 break;
442 }
443 }
444 else
445 {
446 if ( (FPU_modrm & 0x30) == 0x10 )
447 {
448
449 EXCEPTION(EX_StackUnder);
450 setcc(SW_C3 | SW_C2 | SW_C0);
451 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
452 pop();
453 }
454 else
455 stack_underflow();
456 }
457 }
458 else
459 {
460 load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
461 addr_modes);
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) | (byte1 & 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 FPU_illegal();
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 FPU_ORIG_EIP = FPU_EIP;
548 if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
549 &addr_modes.override) )
550 goto do_another_FPU_instruction;
551 }
552
553 if ( addr_modes.vm86 )
554 FPU_EIP -= FPU_CS << 4;
555
556 RE_ENTRANT_CHECK_OFF;
557 }
558
559
560
561
562
563
564 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
565 overrides *override)
566 {
567 unsigned char byte;
568 unsigned char *ip = *fpu_eip;
569
570 *override = (overrides) { 0, 0, PREFIX_DEFAULT };
571
572 RE_ENTRANT_CHECK_OFF;
573 FPU_code_verify_area(1);
574 byte = get_fs_byte(ip);
575 RE_ENTRANT_CHECK_ON;
576
577 while ( 1 )
578 {
579 switch ( byte )
580 {
581 case ADDR_SIZE_PREFIX:
582 override->address_size = ADDR_SIZE_PREFIX;
583 goto do_next_byte;
584
585 case OP_SIZE_PREFIX:
586 override->operand_size = OP_SIZE_PREFIX;
587 goto do_next_byte;
588
589 case PREFIX_CS:
590 override->segment = PREFIX_CS_;
591 goto do_next_byte;
592 case PREFIX_ES:
593 override->segment = PREFIX_ES_;
594 goto do_next_byte;
595 case PREFIX_SS:
596 override->segment = PREFIX_SS_;
597 goto do_next_byte;
598 case PREFIX_FS:
599 override->segment = PREFIX_FS_;
600 goto do_next_byte;
601 case PREFIX_GS:
602 override->segment = PREFIX_GS_;
603 goto do_next_byte;
604 case PREFIX_DS:
605 override->segment = PREFIX_DS_;
606 goto do_next_byte;
607
608
609
610
611
612
613 case PREFIX_REPE:
614 case PREFIX_REPNE:
615
616 do_next_byte:
617 ip++;
618 RE_ENTRANT_CHECK_OFF;
619 FPU_code_verify_area(1);
620 byte = get_fs_byte(ip);
621 RE_ENTRANT_CHECK_ON;
622 break;
623 case FWAIT_OPCODE:
624 *Byte = byte;
625 return 1;
626 default:
627 if ( (byte & 0xf8) == 0xd8 )
628 {
629 *Byte = byte;
630 *fpu_eip = ip;
631 return 1;
632 }
633 else
634 {
635
636
637 *Byte = byte;
638 return 0;
639 }
640 }
641 }
642 }
643
644
645 void math_abort(struct info * info, unsigned int signal)
646 {
647 FPU_EIP = FPU_ORIG_EIP;
648 current->tss.trap_no = 16;
649 current->tss.error_code = 0;
650 send_sig(signal,current,1);
651 RE_ENTRANT_CHECK_OFF;
652 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
653 #ifdef PARANOID
654 printk("ERROR: wm-FPU-emu math_abort failed!\n");
655 #endif PARANOID
656 }