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
38void 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
77void FPU_illegal(void)
78{
79 math_abort(FPU_info, SIGILL);
80}
81
82void 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 switch (tagi) {
182 case TAG_Empty:
183 continue;
184 break;
185 case TAG_Zero:
186 case TAG_Special:
187 tagi = FPU_Special(r);
188 case TAG_Valid:
189 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
190 getsign(r) ? '-' : '+',
191 (long)(r->sigh >> 16),
192 (long)(r->sigh & 0xFFFF),
193 (long)(r->sigl >> 16),
194 (long)(r->sigl & 0xFFFF),
195 exponent(r) - EXP_BIAS + 1);
196 break;
197 default:
198 printk("Whoops! Error in errors.c: tag%d is %d ", i,
199 tagi);
200 continue;
201 break;
202 }
203 printk("%s\n", tag_desc[(int)(unsigned)tagi]);
204 }
205
206 RE_ENTRANT_CHECK_ON;
207
208}
209
210static struct {
211 int type;
212 const char *name;
213} exception_names[] = {
214 {
215 EX_StackOver, "stack overflow"}, {
216 EX_StackUnder, "stack underflow"}, {
217 EX_Precision, "loss of precision"}, {
218 EX_Underflow, "underflow"}, {
219 EX_Overflow, "overflow"}, {
220 EX_ZeroDiv, "divide by zero"}, {
221 EX_Denormal, "denormalized operand"}, {
222 EX_Invalid, "invalid operation"}, {
223 EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
224 0, NULL}
225};
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
306asmlinkage __visible void FPU_exception(int n)
307{
308 int i, int_type;
309
310 int_type = 0;
311 if (n & EX_INTERNAL) {
312 int_type = n - EX_INTERNAL;
313 n = EX_INTERNAL;
314
315 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
316 } else {
317
318 n &= (SW_Exc_Mask);
319
320 partial_status |= n;
321
322 if (partial_status & ~control_word & CW_Exceptions)
323 partial_status |= (SW_Summary | SW_Backward);
324 if (n & (SW_Stack_Fault | EX_Precision)) {
325 if (!(n & SW_C1))
326
327
328 partial_status &= ~SW_C1;
329 }
330 }
331
332 RE_ENTRANT_CHECK_OFF;
333 if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
334
335 for (i = 0; exception_names[i].type; i++)
336 if ((exception_names[i].type & n) ==
337 exception_names[i].type)
338 break;
339
340 if (exception_names[i].type) {
341#ifdef PRINT_MESSAGES
342 printk("FP Exception: %s!\n", exception_names[i].name);
343#endif
344 } else
345 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
346
347 if (n == EX_INTERNAL) {
348 printk("FPU emulator: Internal error type 0x%04x\n",
349 int_type);
350 FPU_printall();
351 }
352#ifdef PRINT_MESSAGES
353 else
354 FPU_printall();
355#endif
356
357
358
359
360
361
362 }
363 RE_ENTRANT_CHECK_ON;
364
365#ifdef __DEBUG__
366 math_abort(FPU_info, SIGFPE);
367#endif
368
369}
370
371
372
373int real_1op_NaN(FPU_REG *a)
374{
375 int signalling, isNaN;
376
377 isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
378
379
380
381 signalling = isNaN && !(a->sigh & 0x40000000);
382
383 if (!signalling) {
384 if (!isNaN) {
385 if (control_word & CW_Invalid) {
386
387 reg_copy(&CONST_QNaN, a);
388 }
389 EXCEPTION(EX_Invalid);
390 return (!(control_word & CW_Invalid) ? FPU_Exception :
391 0) | TAG_Special;
392 }
393 return TAG_Special;
394 }
395
396 if (control_word & CW_Invalid) {
397
398 if (!(a->sigh & 0x80000000)) {
399 reg_copy(&CONST_QNaN, a);
400 }
401
402 a->sigh |= 0x40000000;
403 }
404
405 EXCEPTION(EX_Invalid);
406
407 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
408}
409
410
411
412int real_2op_NaN(FPU_REG const *b, u_char tagb,
413 int deststnr, FPU_REG const *defaultNaN)
414{
415 FPU_REG *dest = &st(deststnr);
416 FPU_REG const *a = dest;
417 u_char taga = FPU_gettagi(deststnr);
418 FPU_REG const *x;
419 int signalling, unsupported;
420
421 if (taga == TAG_Special)
422 taga = FPU_Special(a);
423 if (tagb == TAG_Special)
424 tagb = FPU_Special(b);
425
426
427 unsupported = ((taga == TW_NaN)
428 && !((exponent(a) == EXP_OVER)
429 && (a->sigh & 0x80000000)))
430 || ((tagb == TW_NaN)
431 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
432 if (unsupported) {
433 if (control_word & CW_Invalid) {
434
435 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
436 }
437 EXCEPTION(EX_Invalid);
438 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
439 TAG_Special;
440 }
441
442 if (taga == TW_NaN) {
443 x = a;
444 if (tagb == TW_NaN) {
445 signalling = !(a->sigh & b->sigh & 0x40000000);
446 if (significand(b) > significand(a))
447 x = b;
448 else if (significand(b) == significand(a)) {
449
450
451 x = defaultNaN;
452 }
453 } else {
454
455 signalling = !(a->sigh & 0x40000000);
456 }
457 } else
458#ifdef PARANOID
459 if (tagb == TW_NaN)
460#endif
461 {
462 signalling = !(b->sigh & 0x40000000);
463 x = b;
464 }
465#ifdef PARANOID
466 else {
467 signalling = 0;
468 EXCEPTION(EX_INTERNAL | 0x113);
469 x = &CONST_QNaN;
470 }
471#endif
472
473 if ((!signalling) || (control_word & CW_Invalid)) {
474 if (!x)
475 x = b;
476
477 if (!(x->sigh & 0x80000000))
478 x = &CONST_QNaN;
479
480 FPU_copy_to_regi(x, TAG_Special, deststnr);
481
482 if (!signalling)
483 return TAG_Special;
484
485
486 dest->sigh |= 0x40000000;
487 }
488
489 EXCEPTION(EX_Invalid);
490
491 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
492}
493
494
495
496asmlinkage __visible int arith_invalid(int deststnr)
497{
498
499 EXCEPTION(EX_Invalid);
500
501 if (control_word & CW_Invalid) {
502
503 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
504 }
505
506 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
507
508}
509
510
511asmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign)
512{
513 FPU_REG *dest = &st(deststnr);
514 int tag = TAG_Valid;
515
516 if (control_word & CW_ZeroDiv) {
517
518 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
519 setsign(dest, sign);
520 tag = TAG_Special;
521 }
522
523 EXCEPTION(EX_ZeroDiv);
524
525 return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
526
527}
528
529
530int set_precision_flag(int flags)
531{
532 if (control_word & CW_Precision) {
533 partial_status &= ~(SW_C1 & flags);
534 partial_status |= flags;
535 return 0;
536 } else {
537 EXCEPTION(flags);
538 return 1;
539 }
540}
541
542
543asmlinkage __visible void set_precision_flag_up(void)
544{
545 if (control_word & CW_Precision)
546 partial_status |= (SW_Precision | SW_C1);
547 else
548 EXCEPTION(EX_Precision | SW_C1);
549}
550
551
552asmlinkage __visible void set_precision_flag_down(void)
553{
554 if (control_word & CW_Precision) {
555 partial_status &= ~SW_C1;
556 partial_status |= SW_Precision;
557 } else
558 EXCEPTION(EX_Precision);
559}
560
561asmlinkage __visible int denormal_operand(void)
562{
563 if (control_word & CW_Denormal) {
564 partial_status |= SW_Denorm_Op;
565 return TAG_Special;
566 } else {
567 EXCEPTION(EX_Denormal);
568 return TAG_Special | FPU_Exception;
569 }
570}
571
572asmlinkage __visible int arith_overflow(FPU_REG *dest)
573{
574 int tag = TAG_Valid;
575
576 if (control_word & CW_Overflow) {
577
578
579 reg_copy(&CONST_INF, dest);
580 tag = TAG_Special;
581 } else {
582
583 addexponent(dest, (-3 * (1 << 13)));
584 }
585
586 EXCEPTION(EX_Overflow);
587 if (control_word & CW_Overflow) {
588
589
590
591
592 EXCEPTION(EX_Precision | SW_C1);
593 return tag;
594 }
595
596 return tag;
597
598}
599
600asmlinkage __visible int arith_underflow(FPU_REG *dest)
601{
602 int tag = TAG_Valid;
603
604 if (control_word & CW_Underflow) {
605
606 if (exponent16(dest) <= EXP_UNDER - 63) {
607 reg_copy(&CONST_Z, dest);
608 partial_status &= ~SW_C1;
609 tag = TAG_Zero;
610 } else {
611 stdexp(dest);
612 }
613 } else {
614
615 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
616 }
617
618 EXCEPTION(EX_Underflow);
619 if (control_word & CW_Underflow) {
620
621 EXCEPTION(EX_Precision);
622 return tag;
623 }
624
625 return tag;
626
627}
628
629void FPU_stack_overflow(void)
630{
631
632 if (control_word & CW_Invalid) {
633
634 top--;
635 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
636 }
637
638 EXCEPTION(EX_StackOver);
639
640 return;
641
642}
643
644void FPU_stack_underflow(void)
645{
646
647 if (control_word & CW_Invalid) {
648
649 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
650 }
651
652 EXCEPTION(EX_StackUnder);
653
654 return;
655
656}
657
658void FPU_stack_underflow_i(int i)
659{
660
661 if (control_word & CW_Invalid) {
662
663 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
664 }
665
666 EXCEPTION(EX_StackUnder);
667
668 return;
669
670}
671
672void FPU_stack_underflow_pop(int i)
673{
674
675 if (control_word & CW_Invalid) {
676
677 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
678 FPU_pop();
679 }
680
681 EXCEPTION(EX_StackUnder);
682
683 return;
684
685}
686