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