This source file includes following definitions.
- math_emulate
- valid_prefix
- math_abort
- restore_i387_soft
- save_i387_soft
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
27 #include <linux/signal.h>
28
29 #include <asm/segment.h>
30
31 #include "fpu_system.h"
32 #include "fpu_emu.h"
33 #include "exception.h"
34 #include "control_w.h"
35 #include "status_w.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 #ifdef RE_ENTRANT_CHECKING
126 char emulating=0;
127 #endif RE_ENTRANT_CHECKING
128
129 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
130 overrides *override);
131
132 asmlinkage void math_emulate(long arg)
133 {
134 unsigned char FPU_modrm, byte1;
135 unsigned short code;
136 fpu_addr_modes addr_modes;
137 int unmasked;
138 FPU_REG loaded_data;
139 void *data_address;
140 struct address data_sel_off;
141 struct address entry_sel_off;
142 unsigned long code_base = 0;
143 unsigned long code_limit = 0;
144 char st0_tag;
145 FPU_REG *st0_ptr;
146 struct desc_struct code_descriptor;
147
148 #ifdef RE_ENTRANT_CHECKING
149 if ( emulating )
150 {
151 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
152 }
153 RE_ENTRANT_CHECK_ON;
154 #endif RE_ENTRANT_CHECKING
155
156 if (!current->used_math)
157 {
158 int i;
159 for ( i = 0; i < 8; i++ )
160 {
161
162
163 if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
164 && (regs[i].sigl == 0)) )
165 regs[i].sigh |= 0x80000000;
166 }
167 finit();
168 current->used_math = 1;
169 }
170
171 SETUP_DATA_AREA(arg);
172
173 FPU_ORIG_EIP = FPU_EIP;
174
175 if ( (FPU_EFLAGS & 0x00020000) != 0 )
176 {
177
178 addr_modes.default_mode = VM86;
179 FPU_EIP += code_base = FPU_CS << 4;
180 code_limit = code_base + 0xffff;
181 }
182 else if ( FPU_CS == USER_CS && FPU_DS == USER_DS )
183 {
184 addr_modes.default_mode = 0;
185 }
186 else if ( FPU_CS == KERNEL_CS )
187 {
188 printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
189 panic("Math emulation needed in kernel");
190 }
191 else
192 {
193
194 if ( (FPU_CS & 4) != 4 )
195 {
196
197
198 printk("FPU emulator: Unsupported addressing mode\n");
199 math_abort(FPU_info, SIGILL);
200 }
201
202 if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) )
203 {
204
205
206 addr_modes.default_mode = SEG32;
207 }
208 else
209 {
210
211 addr_modes.default_mode = PM16;
212 }
213 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
214 code_limit = code_base
215 + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
216 - 1;
217 if ( code_limit < code_base ) code_limit = 0xffffffff;
218 }
219
220 FPU_lookahead = 1;
221 if (current->flags & PF_PTRACED)
222 FPU_lookahead = 0;
223
224 if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
225 &addr_modes.override) )
226 {
227 RE_ENTRANT_CHECK_OFF;
228 printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
229 "FPU emulator: self-modifying code! (emulation impossible)\n",
230 byte1);
231 RE_ENTRANT_CHECK_ON;
232 EXCEPTION(EX_INTERNAL|0x126);
233 math_abort(FPU_info,SIGILL);
234 }
235
236 do_another_FPU_instruction:
237
238 no_ip_update = 0;
239
240 FPU_EIP++;
241
242 if ( addr_modes.default_mode )
243 {
244
245
246 if ( FPU_EIP > code_limit )
247 math_abort(FPU_info,SIGSEGV);
248 }
249
250 if ( (byte1 & 0xf8) != 0xd8 )
251 {
252 if ( byte1 == FWAIT_OPCODE )
253 {
254 if (partial_status & SW_Summary)
255 goto do_the_FPU_interrupt;
256 else
257 goto FPU_fwait_done;
258 }
259 #ifdef PARANOID
260 EXCEPTION(EX_INTERNAL|0x128);
261 math_abort(FPU_info,SIGILL);
262 #endif PARANOID
263 }
264
265 RE_ENTRANT_CHECK_OFF;
266 FPU_code_verify_area(1);
267 FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP);
268 RE_ENTRANT_CHECK_ON;
269 FPU_EIP++;
270
271 if (partial_status & SW_Summary)
272 {
273
274
275
276
277
278
279 code = (FPU_modrm << 8) | byte1;
280 if ( ! ( (((code & 0xf803) == 0xe003) ||
281 (((code & 0x3003) == 0x3001) &&
282
283 ((code & 0xc000) != 0xc000))) ) )
284 {
285
286
287
288
289 do_the_FPU_interrupt:
290 FPU_EIP = FPU_ORIG_EIP;
291
292 RE_ENTRANT_CHECK_OFF;
293 current->tss.trap_no = 16;
294 current->tss.error_code = 0;
295 send_sig(SIGFPE, current, 1);
296 return;
297 }
298 }
299
300 entry_sel_off.offset = FPU_ORIG_EIP;
301 entry_sel_off.selector = FPU_CS;
302 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
303
304 FPU_rm = FPU_modrm & 7;
305
306 if ( FPU_modrm < 0300 )
307 {
308
309
310 if ( (addr_modes.default_mode & SIXTEEN)
311 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
312 data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
313 addr_modes);
314 else
315 data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
316 addr_modes);
317
318 if ( addr_modes.default_mode )
319 {
320 if ( FPU_EIP-1 > code_limit )
321 math_abort(FPU_info,SIGSEGV);
322 }
323
324 if ( !(byte1 & 1) )
325 {
326 unsigned short status1 = partial_status;
327
328 st0_ptr = &st(0);
329 st0_tag = st0_ptr->tag;
330
331
332 if ( NOT_EMPTY_ST0 )
333 {
334 if ( addr_modes.default_mode & PROTECTED )
335 {
336
337 if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
338 math_abort(FPU_info,SIGSEGV);
339 }
340
341 unmasked = 0;
342 switch ( (byte1 >> 1) & 3 )
343 {
344 case 0:
345 unmasked = reg_load_single((float *)data_address,
346 &loaded_data);
347 break;
348 case 1:
349 reg_load_int32((long *)data_address, &loaded_data);
350 break;
351 case 2:
352 unmasked = reg_load_double((double *)data_address,
353 &loaded_data);
354 break;
355 case 3:
356 reg_load_int16((short *)data_address, &loaded_data);
357 break;
358 }
359
360
361
362
363
364
365
366 if ( (st0_tag == TW_NaN) ||
367 (loaded_data.tag == TW_NaN) )
368 {
369
370
371 partial_status = status1;
372 if ( (FPU_modrm & 0x30) == 0x10 )
373 {
374
375 EXCEPTION(EX_Invalid);
376 setcc(SW_C3 | SW_C2 | SW_C0);
377 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
378 pop();
379 }
380 else
381 {
382 #ifdef PECULIAR_486
383
384
385 if ( (FPU_modrm & 0x28) == 0x20 )
386
387 real_2op_NaN(&loaded_data, st0_ptr,
388 st0_ptr);
389 else
390 #endif PECULIAR_486
391
392 real_2op_NaN(st0_ptr, &loaded_data,
393 st0_ptr);
394 }
395 goto reg_mem_instr_done;
396 }
397
398 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
399 {
400
401 if ( (FPU_modrm & 0x38) == 0x38 )
402 {
403
404 if ( (st0_tag == TW_Zero) &&
405 (loaded_data.tag == TW_Valid) )
406 {
407 if ( divide_by_zero(loaded_data.sign,
408 st0_ptr) )
409 {
410
411
412
413
414 partial_status &= ~SW_Denorm_Op;
415 partial_status |= status1 & SW_Denorm_Op;
416 }
417 }
418 }
419 goto reg_mem_instr_done;
420 }
421
422 switch ( (FPU_modrm >> 3) & 7 )
423 {
424 case 0:
425 clear_C1();
426 reg_add(st0_ptr, &loaded_data, st0_ptr,
427 control_word);
428 break;
429 case 1:
430 clear_C1();
431 reg_mul(st0_ptr, &loaded_data, st0_ptr,
432 control_word);
433 break;
434 case 2:
435 compare_st_data(&loaded_data);
436 break;
437 case 3:
438 if ( !compare_st_data(&loaded_data) && !unmasked )
439 pop();
440 break;
441 case 4:
442 clear_C1();
443 reg_sub(st0_ptr, &loaded_data, st0_ptr,
444 control_word);
445 break;
446 case 5:
447 clear_C1();
448 reg_sub(&loaded_data, st0_ptr, st0_ptr,
449 control_word);
450 break;
451 case 6:
452 clear_C1();
453 reg_div(st0_ptr, &loaded_data, st0_ptr,
454 control_word);
455 break;
456 case 7:
457 clear_C1();
458 if ( st0_tag == TW_Zero )
459 partial_status = status1;
460
461 reg_div(&loaded_data, st0_ptr, st0_ptr,
462 control_word);
463 break;
464 }
465 }
466 else
467 {
468 if ( (FPU_modrm & 0x30) == 0x10 )
469 {
470
471 EXCEPTION(EX_StackUnder);
472 setcc(SW_C3 | SW_C2 | SW_C0);
473 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
474 pop();
475 }
476 else
477 stack_underflow();
478 }
479 reg_mem_instr_done:
480 operand_address = data_sel_off;
481 }
482 else
483 {
484 if ( !(no_ip_update =
485 load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
486 addr_modes, data_address)) )
487 {
488 operand_address = data_sel_off;
489 }
490 }
491
492 }
493 else
494 {
495
496 unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
497
498 #ifdef PECULIAR_486
499
500
501 operand_address.offset = 0;
502 operand_address.selector = FPU_DS;
503 #endif PECULIAR_486
504
505 st0_ptr = &st(0);
506 st0_tag = st0_ptr->tag;
507 switch ( type_table[(int) instr_index] )
508 {
509 case _NONE_:
510 break;
511 case _REG0_:
512 if ( !NOT_EMPTY_ST0 )
513 {
514 stack_underflow();
515 goto FPU_instruction_done;
516 }
517 break;
518 case _REGIi:
519 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
520 {
521 stack_underflow_i(FPU_rm);
522 goto FPU_instruction_done;
523 }
524 break;
525 case _REGIp:
526 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
527 {
528 stack_underflow_pop(FPU_rm);
529 goto FPU_instruction_done;
530 }
531 break;
532 case _REGI_:
533 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
534 {
535 stack_underflow();
536 goto FPU_instruction_done;
537 }
538 break;
539 case _PUSH_:
540 break;
541 case _null_:
542 FPU_illegal();
543 goto FPU_instruction_done;
544 default:
545 EXCEPTION(EX_INTERNAL|0x111);
546 goto FPU_instruction_done;
547 }
548 (*st_instr_table[(int) instr_index])();
549
550 FPU_instruction_done:
551 ;
552 }
553
554 if ( ! no_ip_update )
555 instruction_address = entry_sel_off;
556
557 FPU_fwait_done:
558
559 #ifdef DEBUG
560 RE_ENTRANT_CHECK_OFF;
561 emu_printall();
562 RE_ENTRANT_CHECK_ON;
563 #endif DEBUG
564
565 if (FPU_lookahead && !need_resched)
566 {
567 FPU_ORIG_EIP = FPU_EIP - code_base;
568 if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
569 &addr_modes.override) )
570 goto do_another_FPU_instruction;
571 }
572
573 if ( addr_modes.default_mode )
574 FPU_EIP -= code_base;
575
576 RE_ENTRANT_CHECK_OFF;
577 }
578
579
580
581
582
583
584 static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
585 overrides *override)
586 {
587 unsigned char byte;
588 unsigned char *ip = *fpu_eip;
589
590 *override = (overrides) { 0, 0, PREFIX_DEFAULT };
591
592 RE_ENTRANT_CHECK_OFF;
593 FPU_code_verify_area(1);
594 byte = get_fs_byte(ip);
595 RE_ENTRANT_CHECK_ON;
596
597 while ( 1 )
598 {
599 switch ( byte )
600 {
601 case ADDR_SIZE_PREFIX:
602 override->address_size = ADDR_SIZE_PREFIX;
603 goto do_next_byte;
604
605 case OP_SIZE_PREFIX:
606 override->operand_size = OP_SIZE_PREFIX;
607 goto do_next_byte;
608
609 case PREFIX_CS:
610 override->segment = PREFIX_CS_;
611 goto do_next_byte;
612 case PREFIX_ES:
613 override->segment = PREFIX_ES_;
614 goto do_next_byte;
615 case PREFIX_SS:
616 override->segment = PREFIX_SS_;
617 goto do_next_byte;
618 case PREFIX_FS:
619 override->segment = PREFIX_FS_;
620 goto do_next_byte;
621 case PREFIX_GS:
622 override->segment = PREFIX_GS_;
623 goto do_next_byte;
624 case PREFIX_DS:
625 override->segment = PREFIX_DS_;
626 goto do_next_byte;
627
628
629
630
631
632
633 case PREFIX_REPE:
634 case PREFIX_REPNE:
635
636 do_next_byte:
637 ip++;
638 RE_ENTRANT_CHECK_OFF;
639 FPU_code_verify_area(1);
640 byte = get_fs_byte(ip);
641 RE_ENTRANT_CHECK_ON;
642 break;
643 case FWAIT_OPCODE:
644 *Byte = byte;
645 return 1;
646 default:
647 if ( (byte & 0xf8) == 0xd8 )
648 {
649 *Byte = byte;
650 *fpu_eip = ip;
651 return 1;
652 }
653 else
654 {
655
656
657 *Byte = byte;
658 return 0;
659 }
660 }
661 }
662 }
663
664
665 void math_abort(struct info * info, unsigned int signal)
666 {
667 FPU_EIP = FPU_ORIG_EIP;
668 current->tss.trap_no = 16;
669 current->tss.error_code = 0;
670 send_sig(signal,current,1);
671 RE_ENTRANT_CHECK_OFF;
672 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
673 #ifdef PARANOID
674 printk("ERROR: wm-FPU-emu math_abort failed!\n");
675 #endif PARANOID
676 }
677
678
679
680 void restore_i387_soft(struct _fpstate *buf)
681 {
682 fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
683
684 frstor(addr_modes, (char *)buf);
685 }
686
687
688 struct _fpstate * save_i387_soft(struct _fpstate * buf)
689 {
690 fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
691
692 fsave(addr_modes, (char *)buf);
693
694 return buf;
695 }