This source file includes following definitions.
- Un_impl
- FPU_illegal
- FPU_printall
- FPU_exception
- real_1op_NaN
- real_2op_NaN
- arith_invalid
- FPU_divide_by_zero
- set_precision_flag
- set_precision_flag_up
- set_precision_flag_down
- denormal_operand
- arith_overflow
- arith_underflow
- FPU_stack_overflow
- FPU_stack_underflow
- FPU_stack_underflow_i
- FPU_stack_underflow_pop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <linux/signal.h>
22
23 #include <linux/uaccess.h>
24
25 #include "fpu_emu.h"
26 #include "fpu_system.h"
27 #include "exception.h"
28 #include "status_w.h"
29 #include "control_w.h"
30 #include "reg_constant.h"
31 #include "version.h"
32
33
34 #undef PRINT_MESSAGES
35
36
37 #if 0
38 void Un_impl(void)
39 {
40 u_char byte1, FPU_modrm;
41 unsigned long address = FPU_ORIG_EIP;
42
43 RE_ENTRANT_CHECK_OFF;
44
45 printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address);
46 if (FPU_CS == __USER_CS) {
47 while (1) {
48 FPU_get_user(byte1, (u_char __user *) address);
49 if ((byte1 & 0xf8) == 0xd8)
50 break;
51 printk("[%02x]", byte1);
52 address++;
53 }
54 printk("%02x ", byte1);
55 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
56
57 if (FPU_modrm >= 0300)
58 printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8,
59 FPU_modrm & 7);
60 else
61 printk("/%d\n", (FPU_modrm >> 3) & 7);
62 } else {
63 printk("cs selector = %04x\n", FPU_CS);
64 }
65
66 RE_ENTRANT_CHECK_ON;
67
68 EXCEPTION(EX_Invalid);
69
70 }
71 #endif
72
73
74
75
76
77 void FPU_illegal(void)
78 {
79 math_abort(FPU_info, SIGILL);
80 }
81
82 void FPU_printall(void)
83 {
84 int i;
85 static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
86 "DeNorm", "Inf", "NaN"
87 };
88 u_char byte1, FPU_modrm;
89 unsigned long address = FPU_ORIG_EIP;
90
91 RE_ENTRANT_CHECK_OFF;
92
93 printk("At %p:", (void *)address);
94 if (FPU_CS == __USER_CS) {
95 #define MAX_PRINTED_BYTES 20
96 for (i = 0; i < MAX_PRINTED_BYTES; i++) {
97 FPU_get_user(byte1, (u_char __user *) address);
98 if ((byte1 & 0xf8) == 0xd8) {
99 printk(" %02x", byte1);
100 break;
101 }
102 printk(" [%02x]", byte1);
103 address++;
104 }
105 if (i == MAX_PRINTED_BYTES)
106 printk(" [more..]\n");
107 else {
108 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
109
110 if (FPU_modrm >= 0300)
111 printk(" %02x (%02x+%d)\n", FPU_modrm,
112 FPU_modrm & 0xf8, FPU_modrm & 7);
113 else
114 printk(" /%d, mod=%d rm=%d\n",
115 (FPU_modrm >> 3) & 7,
116 (FPU_modrm >> 6) & 3, FPU_modrm & 7);
117 }
118 } else {
119 printk("%04x\n", FPU_CS);
120 }
121
122 partial_status = status_word();
123
124 #ifdef DEBUGGING
125 if (partial_status & SW_Backward)
126 printk("SW: backward compatibility\n");
127 if (partial_status & SW_C3)
128 printk("SW: condition bit 3\n");
129 if (partial_status & SW_C2)
130 printk("SW: condition bit 2\n");
131 if (partial_status & SW_C1)
132 printk("SW: condition bit 1\n");
133 if (partial_status & SW_C0)
134 printk("SW: condition bit 0\n");
135 if (partial_status & SW_Summary)
136 printk("SW: exception summary\n");
137 if (partial_status & SW_Stack_Fault)
138 printk("SW: stack fault\n");
139 if (partial_status & SW_Precision)
140 printk("SW: loss of precision\n");
141 if (partial_status & SW_Underflow)
142 printk("SW: underflow\n");
143 if (partial_status & SW_Overflow)
144 printk("SW: overflow\n");
145 if (partial_status & SW_Zero_Div)
146 printk("SW: divide by zero\n");
147 if (partial_status & SW_Denorm_Op)
148 printk("SW: denormalized operand\n");
149 if (partial_status & SW_Invalid)
150 printk("SW: invalid operation\n");
151 #endif
152
153 printk(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0,
154 (partial_status & 0x3800) >> 11,
155 partial_status & 0x80 ? 1 : 0,
156 partial_status & 0x40 ? 1 : 0,
157 partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0,
158 partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0,
159 partial_status & SW_Precision ? 1 : 0,
160 partial_status & SW_Underflow ? 1 : 0,
161 partial_status & SW_Overflow ? 1 : 0,
162 partial_status & SW_Zero_Div ? 1 : 0,
163 partial_status & SW_Denorm_Op ? 1 : 0,
164 partial_status & SW_Invalid ? 1 : 0);
165
166 printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
167 control_word & 0x1000 ? 1 : 0,
168 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
169 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
170 control_word & 0x80 ? 1 : 0,
171 control_word & SW_Precision ? 1 : 0,
172 control_word & SW_Underflow ? 1 : 0,
173 control_word & SW_Overflow ? 1 : 0,
174 control_word & SW_Zero_Div ? 1 : 0,
175 control_word & SW_Denorm_Op ? 1 : 0,
176 control_word & SW_Invalid ? 1 : 0);
177
178 for (i = 0; i < 8; i++) {
179 FPU_REG *r = &st(i);
180 u_char tagi = FPU_gettagi(i);
181
182 switch (tagi) {
183 case TAG_Empty:
184 continue;
185 case TAG_Zero:
186 case TAG_Special:
187
188 tagi = FPU_Special(r);
189
190 case TAG_Valid:
191 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
192 getsign(r) ? '-' : '+',
193 (long)(r->sigh >> 16),
194 (long)(r->sigh & 0xFFFF),
195 (long)(r->sigl >> 16),
196 (long)(r->sigl & 0xFFFF),
197 exponent(r) - EXP_BIAS + 1);
198 break;
199 default:
200 printk("Whoops! Error in errors.c: tag%d is %d ", i,
201 tagi);
202 continue;
203 }
204 printk("%s\n", tag_desc[(int)(unsigned)tagi]);
205 }
206
207 RE_ENTRANT_CHECK_ON;
208
209 }
210
211 static struct {
212 int type;
213 const char *name;
214 } exception_names[] = {
215 {
216 EX_StackOver, "stack overflow"}, {
217 EX_StackUnder, "stack underflow"}, {
218 EX_Precision, "loss of precision"}, {
219 EX_Underflow, "underflow"}, {
220 EX_Overflow, "overflow"}, {
221 EX_ZeroDiv, "divide by zero"}, {
222 EX_Denormal, "denormalized operand"}, {
223 EX_Invalid, "invalid operation"}, {
224 EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
225 0, NULL}
226 };
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 asmlinkage __visible void FPU_exception(int n)
308 {
309 int i, int_type;
310
311 int_type = 0;
312 if (n & EX_INTERNAL) {
313 int_type = n - EX_INTERNAL;
314 n = EX_INTERNAL;
315
316 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
317 } else {
318
319 n &= (SW_Exc_Mask);
320
321 partial_status |= n;
322
323 if (partial_status & ~control_word & CW_Exceptions)
324 partial_status |= (SW_Summary | SW_Backward);
325 if (n & (SW_Stack_Fault | EX_Precision)) {
326 if (!(n & SW_C1))
327
328
329 partial_status &= ~SW_C1;
330 }
331 }
332
333 RE_ENTRANT_CHECK_OFF;
334 if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
335
336 for (i = 0; exception_names[i].type; i++)
337 if ((exception_names[i].type & n) ==
338 exception_names[i].type)
339 break;
340
341 if (exception_names[i].type) {
342 #ifdef PRINT_MESSAGES
343 printk("FP Exception: %s!\n", exception_names[i].name);
344 #endif
345 } else
346 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
347
348 if (n == EX_INTERNAL) {
349 printk("FPU emulator: Internal error type 0x%04x\n",
350 int_type);
351 FPU_printall();
352 }
353 #ifdef PRINT_MESSAGES
354 else
355 FPU_printall();
356 #endif
357
358
359
360
361
362
363 }
364 RE_ENTRANT_CHECK_ON;
365
366 #ifdef __DEBUG__
367 math_abort(FPU_info, SIGFPE);
368 #endif
369
370 }
371
372
373
374 int real_1op_NaN(FPU_REG *a)
375 {
376 int signalling, isNaN;
377
378 isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
379
380
381
382 signalling = isNaN && !(a->sigh & 0x40000000);
383
384 if (!signalling) {
385 if (!isNaN) {
386 if (control_word & CW_Invalid) {
387
388 reg_copy(&CONST_QNaN, a);
389 }
390 EXCEPTION(EX_Invalid);
391 return (!(control_word & CW_Invalid) ? FPU_Exception :
392 0) | TAG_Special;
393 }
394 return TAG_Special;
395 }
396
397 if (control_word & CW_Invalid) {
398
399 if (!(a->sigh & 0x80000000)) {
400 reg_copy(&CONST_QNaN, a);
401 }
402
403 a->sigh |= 0x40000000;
404 }
405
406 EXCEPTION(EX_Invalid);
407
408 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
409 }
410
411
412
413 int real_2op_NaN(FPU_REG const *b, u_char tagb,
414 int deststnr, FPU_REG const *defaultNaN)
415 {
416 FPU_REG *dest = &st(deststnr);
417 FPU_REG const *a = dest;
418 u_char taga = FPU_gettagi(deststnr);
419 FPU_REG const *x;
420 int signalling, unsupported;
421
422 if (taga == TAG_Special)
423 taga = FPU_Special(a);
424 if (tagb == TAG_Special)
425 tagb = FPU_Special(b);
426
427
428 unsupported = ((taga == TW_NaN)
429 && !((exponent(a) == EXP_OVER)
430 && (a->sigh & 0x80000000)))
431 || ((tagb == TW_NaN)
432 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
433 if (unsupported) {
434 if (control_word & CW_Invalid) {
435
436 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
437 }
438 EXCEPTION(EX_Invalid);
439 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
440 TAG_Special;
441 }
442
443 if (taga == TW_NaN) {
444 x = a;
445 if (tagb == TW_NaN) {
446 signalling = !(a->sigh & b->sigh & 0x40000000);
447 if (significand(b) > significand(a))
448 x = b;
449 else if (significand(b) == significand(a)) {
450
451
452 x = defaultNaN;
453 }
454 } else {
455
456 signalling = !(a->sigh & 0x40000000);
457 }
458 } else
459 #ifdef PARANOID
460 if (tagb == TW_NaN)
461 #endif
462 {
463 signalling = !(b->sigh & 0x40000000);
464 x = b;
465 }
466 #ifdef PARANOID
467 else {
468 signalling = 0;
469 EXCEPTION(EX_INTERNAL | 0x113);
470 x = &CONST_QNaN;
471 }
472 #endif
473
474 if ((!signalling) || (control_word & CW_Invalid)) {
475 if (!x)
476 x = b;
477
478 if (!(x->sigh & 0x80000000))
479 x = &CONST_QNaN;
480
481 FPU_copy_to_regi(x, TAG_Special, deststnr);
482
483 if (!signalling)
484 return TAG_Special;
485
486
487 dest->sigh |= 0x40000000;
488 }
489
490 EXCEPTION(EX_Invalid);
491
492 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
493 }
494
495
496
497 asmlinkage __visible int arith_invalid(int deststnr)
498 {
499
500 EXCEPTION(EX_Invalid);
501
502 if (control_word & CW_Invalid) {
503
504 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
505 }
506
507 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
508
509 }
510
511
512 asmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign)
513 {
514 FPU_REG *dest = &st(deststnr);
515 int tag = TAG_Valid;
516
517 if (control_word & CW_ZeroDiv) {
518
519 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
520 setsign(dest, sign);
521 tag = TAG_Special;
522 }
523
524 EXCEPTION(EX_ZeroDiv);
525
526 return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
527
528 }
529
530
531 int set_precision_flag(int flags)
532 {
533 if (control_word & CW_Precision) {
534 partial_status &= ~(SW_C1 & flags);
535 partial_status |= flags;
536 return 0;
537 } else {
538 EXCEPTION(flags);
539 return 1;
540 }
541 }
542
543
544 asmlinkage __visible void set_precision_flag_up(void)
545 {
546 if (control_word & CW_Precision)
547 partial_status |= (SW_Precision | SW_C1);
548 else
549 EXCEPTION(EX_Precision | SW_C1);
550 }
551
552
553 asmlinkage __visible void set_precision_flag_down(void)
554 {
555 if (control_word & CW_Precision) {
556 partial_status &= ~SW_C1;
557 partial_status |= SW_Precision;
558 } else
559 EXCEPTION(EX_Precision);
560 }
561
562 asmlinkage __visible int denormal_operand(void)
563 {
564 if (control_word & CW_Denormal) {
565 partial_status |= SW_Denorm_Op;
566 return TAG_Special;
567 } else {
568 EXCEPTION(EX_Denormal);
569 return TAG_Special | FPU_Exception;
570 }
571 }
572
573 asmlinkage __visible int arith_overflow(FPU_REG *dest)
574 {
575 int tag = TAG_Valid;
576
577 if (control_word & CW_Overflow) {
578
579
580 reg_copy(&CONST_INF, dest);
581 tag = TAG_Special;
582 } else {
583
584 addexponent(dest, (-3 * (1 << 13)));
585 }
586
587 EXCEPTION(EX_Overflow);
588 if (control_word & CW_Overflow) {
589
590
591
592
593 EXCEPTION(EX_Precision | SW_C1);
594 return tag;
595 }
596
597 return tag;
598
599 }
600
601 asmlinkage __visible int arith_underflow(FPU_REG *dest)
602 {
603 int tag = TAG_Valid;
604
605 if (control_word & CW_Underflow) {
606
607 if (exponent16(dest) <= EXP_UNDER - 63) {
608 reg_copy(&CONST_Z, dest);
609 partial_status &= ~SW_C1;
610 tag = TAG_Zero;
611 } else {
612 stdexp(dest);
613 }
614 } else {
615
616 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
617 }
618
619 EXCEPTION(EX_Underflow);
620 if (control_word & CW_Underflow) {
621
622 EXCEPTION(EX_Precision);
623 return tag;
624 }
625
626 return tag;
627
628 }
629
630 void FPU_stack_overflow(void)
631 {
632
633 if (control_word & CW_Invalid) {
634
635 top--;
636 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
637 }
638
639 EXCEPTION(EX_StackOver);
640
641 return;
642
643 }
644
645 void FPU_stack_underflow(void)
646 {
647
648 if (control_word & CW_Invalid) {
649
650 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
651 }
652
653 EXCEPTION(EX_StackUnder);
654
655 return;
656
657 }
658
659 void FPU_stack_underflow_i(int i)
660 {
661
662 if (control_word & CW_Invalid) {
663
664 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
665 }
666
667 EXCEPTION(EX_StackUnder);
668
669 return;
670
671 }
672
673 void FPU_stack_underflow_pop(int i)
674 {
675
676 if (control_word & CW_Invalid) {
677
678 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
679 FPU_pop();
680 }
681
682 EXCEPTION(EX_StackUnder);
683
684 return;
685
686 }