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 fpu_addr_modes addr_modes;
148 int unmasked;
149
150 #ifdef PARANOID
151 if ( emulating )
152 {
153 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
154 }
155 RE_ENTRANT_CHECK_ON;
156 #endif PARANOID
157
158 if (!current->used_math)
159 {
160 int i;
161 for ( i = 0; i < 8; i++ )
162 {
163
164
165 regs[i].exp = 0;
166 regs[i].sigh = 0x80000000;
167 }
168 finit();
169 current->used_math = 1;
170 }
171
172 SETUP_DATA_AREA(arg);
173
174 addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0;
175
176 if ( addr_modes.vm86 )
177 FPU_EIP += FPU_CS << 4;
178
179 FPU_ORIG_EIP = FPU_EIP;
180
181 if ( !addr_modes.vm86 )
182 {
183
184 if (FPU_CS == KERNEL_CS)
185 {
186 printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
187 panic("Math emulation needed in kernel");
188 }
189
190
191 if (FPU_CS != USER_CS || FPU_DS != USER_DS)
192 {
193 math_abort(FPU_info,SIGILL);
194 }
195 }
196
197 FPU_lookahead = 1;
198 if (current->flags & PF_PTRACED)
199 FPU_lookahead = 0;
200
201 if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
202 &addr_modes.override) )
203 {
204 RE_ENTRANT_CHECK_OFF;
205 printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
206 "FPU emulator: self-modifying code! (emulation impossible)\n",
207 byte1);
208 RE_ENTRANT_CHECK_ON;
209 EXCEPTION(EX_INTERNAL|0x126);
210 math_abort(FPU_info,SIGILL);
211 }
212
213 do_another_FPU_instruction:
214
215 FPU_EIP++;
216
217 #ifdef PECULIAR_486
218
219
220
221 FPU_data_selector = FPU_DS;
222 #endif PECULIAR_486
223
224 if ( (byte1 & 0xf8) != 0xd8 )
225 {
226 if ( byte1 == FWAIT_OPCODE )
227 {
228 if (partial_status & SW_Summary)
229 goto do_the_FPU_interrupt;
230 else
231 goto FPU_fwait_done;
232 }
233 #ifdef PARANOID
234 EXCEPTION(EX_INTERNAL|0x128);
235 math_abort(FPU_info,SIGILL);
236 #endif PARANOID
237 }
238
239 RE_ENTRANT_CHECK_OFF;
240 FPU_code_verify_area(1);
241 FPU_modrm = get_fs_byte((unsigned short *) FPU_EIP);
242 RE_ENTRANT_CHECK_ON;
243 FPU_EIP++;
244
245 if (partial_status & SW_Summary)
246 {
247
248
249
250
251
252
253 unsigned short code = (FPU_modrm << 8) | byte1;
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 current->tss.trap_no = 16;
283 current->tss.error_code = 0;
284 send_sig(SIGFPE, current, 1);
285 return;
286 }
287 }
288
289 FPU_entry_eip = FPU_ORIG_EIP;
290
291 FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ;
292
293 FPU_rm = FPU_modrm & 7;
294
295 if ( FPU_modrm < 0300 )
296 {
297
298 if ( addr_modes.vm86
299 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
300 get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
301 else
302 get_address(FPU_modrm, &FPU_EIP, addr_modes);
303 if ( !(byte1 & 1) )
304 {
305 unsigned short status1 = partial_status;
306 FPU_st0_ptr = &st(0);
307 FPU_st0_tag = FPU_st0_ptr->tag;
308
309
310 if ( NOT_EMPTY_0 )
311 {
312 unmasked = 0;
313 switch ( (byte1 >> 1) & 3 )
314 {
315 case 0:
316 unmasked = reg_load_single();
317 break;
318 case 1:
319 reg_load_int32();
320 break;
321 case 2:
322 unmasked = reg_load_double();
323 break;
324 case 3:
325 reg_load_int16();
326 break;
327 }
328
329
330
331 FPU_st0_ptr = &st(0);
332 FPU_st0_tag = FPU_st0_ptr->tag;
333
334
335
336
337 if ( (FPU_st0_tag == TW_NaN) ||
338 (FPU_loaded_data.tag == TW_NaN) )
339 {
340
341
342 partial_status = status1;
343 if ( (FPU_modrm & 0x30) == 0x10 )
344 {
345
346 EXCEPTION(EX_Invalid);
347 setcc(SW_C3 | SW_C2 | SW_C0);
348 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
349 pop();
350 }
351 else
352 {
353 #ifdef PECULIAR_486
354
355
356 if ( (FPU_modrm & 0x28) == 0x20 )
357
358 real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr,
359 FPU_st0_ptr);
360 else
361 #endif PECULIAR_486
362
363 real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data,
364 FPU_st0_ptr);
365 }
366 goto reg_mem_instr_done;
367 }
368
369 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
370 {
371
372 if ( (FPU_modrm & 0x38) == 0x38 )
373 {
374
375 if ( (FPU_st0_tag == TW_Zero) &&
376 (FPU_loaded_data.tag == TW_Valid) )
377 {
378 if ( divide_by_zero(FPU_loaded_data.sign,
379 FPU_st0_ptr) )
380 {
381
382
383
384
385 partial_status &= ~SW_Denorm_Op;
386 partial_status |= status1 & SW_Denorm_Op;
387 }
388 }
389 }
390 goto reg_mem_instr_done;
391 }
392
393 switch ( (FPU_modrm >> 3) & 7 )
394 {
395 case 0:
396 clear_C1();
397 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
398 control_word);
399 break;
400 case 1:
401 clear_C1();
402 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
403 control_word);
404 break;
405 case 2:
406 compare_st_data();
407 break;
408 case 3:
409 if ( !compare_st_data() && !unmasked )
410 pop();
411 break;
412 case 4:
413 clear_C1();
414 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
415 control_word);
416 break;
417 case 5:
418 clear_C1();
419 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
420 control_word);
421 break;
422 case 6:
423 clear_C1();
424 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr,
425 control_word);
426 break;
427 case 7:
428 clear_C1();
429 if ( FPU_st0_tag == TW_Zero )
430 partial_status = status1;
431
432 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr,
433 control_word);
434 break;
435 }
436 }
437 else
438 {
439 if ( (FPU_modrm & 0x30) == 0x10 )
440 {
441
442 EXCEPTION(EX_StackUnder);
443 setcc(SW_C3 | SW_C2 | SW_C0);
444 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
445 pop();
446 }
447 else
448 stack_underflow();
449 }
450 }
451 else
452 {
453 load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
454 addr_modes);
455 }
456
457 reg_mem_instr_done:
458
459 #ifndef PECULIAR_486
460 *(unsigned short *)&operand_selector = FPU_data_selector;
461 #endif PECULIAR_486
462 ;
463 }
464 else
465 {
466
467 unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
468
469 #ifdef PECULIAR_486
470
471
472 FPU_data_address = 0;
473 #endif PECULIAR_486
474
475 FPU_st0_ptr = &st(0);
476 FPU_st0_tag = FPU_st0_ptr->tag;
477 switch ( type_table[(int) instr_index] )
478 {
479 case _NONE_:
480 break;
481 case _REG0_:
482 if ( !NOT_EMPTY_0 )
483 {
484 stack_underflow();
485 goto FPU_instruction_done;
486 }
487 break;
488 case _REGIi:
489 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
490 {
491 stack_underflow_i(FPU_rm);
492 goto FPU_instruction_done;
493 }
494 break;
495 case _REGIp:
496 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
497 {
498 stack_underflow_pop(FPU_rm);
499 goto FPU_instruction_done;
500 }
501 break;
502 case _REGI_:
503 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
504 {
505 stack_underflow();
506 goto FPU_instruction_done;
507 }
508 break;
509 case _PUSH_:
510 break;
511 case _null_:
512 FPU_illegal();
513 goto FPU_instruction_done;
514 default:
515 EXCEPTION(EX_INTERNAL|0x111);
516 goto FPU_instruction_done;
517 }
518 (*st_instr_table[(int) instr_index])();
519 }
520
521 FPU_instruction_done:
522
523 ip_offset = FPU_entry_eip;
524 cs_selector = FPU_entry_op_cs;
525 data_operand_offset = (unsigned long)FPU_data_address;
526 #ifdef PECULIAR_486
527 *(unsigned short *)&operand_selector = FPU_data_selector;
528 #endif PECULIAR_486
529
530 FPU_fwait_done:
531
532 #ifdef DEBUG
533 RE_ENTRANT_CHECK_OFF;
534 emu_printall();
535 RE_ENTRANT_CHECK_ON;
536 #endif DEBUG
537
538 if (FPU_lookahead && !need_resched)
539 {
540 FPU_ORIG_EIP = FPU_EIP;
541 if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
542 &addr_modes.override) )
543 goto do_another_FPU_instruction;
544 }
545
546 if ( addr_modes.vm86 )
547 FPU_EIP -= FPU_CS << 4;
548
549 RE_ENTRANT_CHECK_OFF;
550 }
551
552
553
554
555
556
557 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
558 overrides *override)
559 {
560 unsigned char byte;
561 unsigned char *ip = *fpu_eip;
562
563 *override = (overrides) { 0, 0, PREFIX_DS_ };
564
565 RE_ENTRANT_CHECK_OFF;
566 FPU_code_verify_area(1);
567 byte = get_fs_byte(ip);
568 RE_ENTRANT_CHECK_ON;
569
570 while ( 1 )
571 {
572 switch ( byte )
573 {
574 case ADDR_SIZE_PREFIX:
575 override->address_size = ADDR_SIZE_PREFIX;
576 goto do_next_byte;
577
578 case OP_SIZE_PREFIX:
579 override->operand_size = OP_SIZE_PREFIX;
580 goto do_next_byte;
581
582 case PREFIX_CS:
583 override->segment = PREFIX_CS_;
584 goto do_next_byte;
585 case PREFIX_ES:
586 override->segment = PREFIX_ES_;
587 goto do_next_byte;
588 case PREFIX_SS:
589 override->segment = PREFIX_SS_;
590 goto do_next_byte;
591 case PREFIX_FS:
592 override->segment = PREFIX_FS_;
593 goto do_next_byte;
594 case PREFIX_GS:
595 override->segment = PREFIX_GS_;
596 goto do_next_byte;
597
598 case PREFIX_DS:
599 override->segment = PREFIX_DS_;
600
601
602
603
604
605
606 case PREFIX_REPE:
607 case PREFIX_REPNE:
608
609 do_next_byte:
610 ip++;
611 RE_ENTRANT_CHECK_OFF;
612 FPU_code_verify_area(1);
613 byte = get_fs_byte(ip);
614 RE_ENTRANT_CHECK_ON;
615 break;
616 case FWAIT_OPCODE:
617 *Byte = byte;
618 return 1;
619 default:
620 if ( (byte & 0xf8) == 0xd8 )
621 {
622 *Byte = byte;
623 *fpu_eip = ip;
624 return 1;
625 }
626 else
627 {
628
629
630 *Byte = byte;
631 return 0;
632 }
633 }
634 }
635 }
636
637
638 void math_abort(struct info * info, unsigned int signal)
639 {
640 FPU_EIP = FPU_ORIG_EIP;
641 current->tss.trap_no = 16;
642 current->tss.error_code = 0;
643 send_sig(signal,current,1);
644 RE_ENTRANT_CHECK_OFF;
645 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
646 #ifdef PARANOID
647 printk("ERROR: wm-FPU-emu math_abort failed!\n");
648 #endif PARANOID
649 }