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