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