Merge git://git.infradead.org/~kmpark/onenand-mtd-2.6
[linux-2.6] / arch / x86 / math-emu / errors.c
1 /*---------------------------------------------------------------------------+
2  |  errors.c                                                                 |
3  |                                                                           |
4  |  The error handling functions for wm-FPU-emu                              |
5  |                                                                           |
6  | Copyright (C) 1992,1993,1994,1996                                         |
7  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8  |                  E-mail   billm@jacobi.maths.monash.edu.au                |
9  |                                                                           |
10  |                                                                           |
11  +---------------------------------------------------------------------------*/
12
13 /*---------------------------------------------------------------------------+
14  | Note:                                                                     |
15  |    The file contains code which accesses user memory.                     |
16  |    Emulator static data may change when user memory is accessed, due to   |
17  |    other processes using the emulator while swapping is in progress.      |
18  +---------------------------------------------------------------------------*/
19
20 #include <linux/signal.h>
21
22 #include <asm/uaccess.h>
23
24 #include "fpu_emu.h"
25 #include "fpu_system.h"
26 #include "exception.h"
27 #include "status_w.h"
28 #include "control_w.h"
29 #include "reg_constant.h"
30 #include "version.h"
31
32 /* */
33 #undef PRINT_MESSAGES
34 /* */
35
36 #if 0
37 void Un_impl(void)
38 {
39         u_char byte1, FPU_modrm;
40         unsigned long address = FPU_ORIG_EIP;
41
42         RE_ENTRANT_CHECK_OFF;
43         /* No need to check access_ok(), we have previously fetched these bytes. */
44         printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address);
45         if (FPU_CS == __USER_CS) {
46                 while (1) {
47                         FPU_get_user(byte1, (u_char __user *) address);
48                         if ((byte1 & 0xf8) == 0xd8)
49                                 break;
50                         printk("[%02x]", byte1);
51                         address++;
52                 }
53                 printk("%02x ", byte1);
54                 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
55
56                 if (FPU_modrm >= 0300)
57                         printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8,
58                                FPU_modrm & 7);
59                 else
60                         printk("/%d\n", (FPU_modrm >> 3) & 7);
61         } else {
62                 printk("cs selector = %04x\n", FPU_CS);
63         }
64
65         RE_ENTRANT_CHECK_ON;
66
67         EXCEPTION(EX_Invalid);
68
69 }
70 #endif /*  0  */
71
72 /*
73    Called for opcodes which are illegal and which are known to result in a
74    SIGILL with a real 80486.
75    */
76 void FPU_illegal(void)
77 {
78         math_abort(FPU_info, SIGILL);
79 }
80
81 void FPU_printall(void)
82 {
83         int i;
84         static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
85                 "DeNorm", "Inf", "NaN"
86         };
87         u_char byte1, FPU_modrm;
88         unsigned long address = FPU_ORIG_EIP;
89
90         RE_ENTRANT_CHECK_OFF;
91         /* No need to check access_ok(), we have previously fetched these bytes. */
92         printk("At %p:", (void *)address);
93         if (FPU_CS == __USER_CS) {
94 #define MAX_PRINTED_BYTES 20
95                 for (i = 0; i < MAX_PRINTED_BYTES; i++) {
96                         FPU_get_user(byte1, (u_char __user *) address);
97                         if ((byte1 & 0xf8) == 0xd8) {
98                                 printk(" %02x", byte1);
99                                 break;
100                         }
101                         printk(" [%02x]", byte1);
102                         address++;
103                 }
104                 if (i == MAX_PRINTED_BYTES)
105                         printk(" [more..]\n");
106                 else {
107                         FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
108
109                         if (FPU_modrm >= 0300)
110                                 printk(" %02x (%02x+%d)\n", FPU_modrm,
111                                        FPU_modrm & 0xf8, FPU_modrm & 7);
112                         else
113                                 printk(" /%d, mod=%d rm=%d\n",
114                                        (FPU_modrm >> 3) & 7,
115                                        (FPU_modrm >> 6) & 3, FPU_modrm & 7);
116                 }
117         } else {
118                 printk("%04x\n", FPU_CS);
119         }
120
121         partial_status = status_word();
122
123 #ifdef DEBUGGING
124         if (partial_status & SW_Backward)
125                 printk("SW: backward compatibility\n");
126         if (partial_status & SW_C3)
127                 printk("SW: condition bit 3\n");
128         if (partial_status & SW_C2)
129                 printk("SW: condition bit 2\n");
130         if (partial_status & SW_C1)
131                 printk("SW: condition bit 1\n");
132         if (partial_status & SW_C0)
133                 printk("SW: condition bit 0\n");
134         if (partial_status & SW_Summary)
135                 printk("SW: exception summary\n");
136         if (partial_status & SW_Stack_Fault)
137                 printk("SW: stack fault\n");
138         if (partial_status & SW_Precision)
139                 printk("SW: loss of precision\n");
140         if (partial_status & SW_Underflow)
141                 printk("SW: underflow\n");
142         if (partial_status & SW_Overflow)
143                 printk("SW: overflow\n");
144         if (partial_status & SW_Zero_Div)
145                 printk("SW: divide by zero\n");
146         if (partial_status & SW_Denorm_Op)
147                 printk("SW: denormalized operand\n");
148         if (partial_status & SW_Invalid)
149                 printk("SW: invalid operation\n");
150 #endif /* DEBUGGING */
151
152         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,    /* busy */
153                (partial_status & 0x3800) >> 11, /* stack top pointer */
154                partial_status & 0x80 ? 1 : 0,   /* Error summary status */
155                partial_status & 0x40 ? 1 : 0,   /* Stack flag */
156                partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0,  /* cc */
157                partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0,  /* cc */
158                partial_status & SW_Precision ? 1 : 0,
159                partial_status & SW_Underflow ? 1 : 0,
160                partial_status & SW_Overflow ? 1 : 0,
161                partial_status & SW_Zero_Div ? 1 : 0,
162                partial_status & SW_Denorm_Op ? 1 : 0,
163                partial_status & SW_Invalid ? 1 : 0);
164
165         printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d     ef=%d%d%d%d%d%d\n",
166                control_word & 0x1000 ? 1 : 0,
167                (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
168                (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
169                control_word & 0x80 ? 1 : 0,
170                control_word & SW_Precision ? 1 : 0,
171                control_word & SW_Underflow ? 1 : 0,
172                control_word & SW_Overflow ? 1 : 0,
173                control_word & SW_Zero_Div ? 1 : 0,
174                control_word & SW_Denorm_Op ? 1 : 0,
175                control_word & SW_Invalid ? 1 : 0);
176
177         for (i = 0; i < 8; i++) {
178                 FPU_REG *r = &st(i);
179                 u_char tagi = FPU_gettagi(i);
180                 switch (tagi) {
181                 case TAG_Empty:
182                         continue;
183                         break;
184                 case TAG_Zero:
185                 case TAG_Special:
186                         tagi = FPU_Special(r);
187                 case TAG_Valid:
188                         printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
189                                getsign(r) ? '-' : '+',
190                                (long)(r->sigh >> 16),
191                                (long)(r->sigh & 0xFFFF),
192                                (long)(r->sigl >> 16),
193                                (long)(r->sigl & 0xFFFF),
194                                exponent(r) - EXP_BIAS + 1);
195                         break;
196                 default:
197                         printk("Whoops! Error in errors.c: tag%d is %d ", i,
198                                tagi);
199                         continue;
200                         break;
201                 }
202                 printk("%s\n", tag_desc[(int)(unsigned)tagi]);
203         }
204
205         RE_ENTRANT_CHECK_ON;
206
207 }
208
209 static struct {
210         int type;
211         const char *name;
212 } exception_names[] = {
213         {
214         EX_StackOver, "stack overflow"}, {
215         EX_StackUnder, "stack underflow"}, {
216         EX_Precision, "loss of precision"}, {
217         EX_Underflow, "underflow"}, {
218         EX_Overflow, "overflow"}, {
219         EX_ZeroDiv, "divide by zero"}, {
220         EX_Denormal, "denormalized operand"}, {
221         EX_Invalid, "invalid operation"}, {
222         EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
223         0, NULL}
224 };
225
226 /*
227  EX_INTERNAL is always given with a code which indicates where the
228  error was detected.
229
230  Internal error types:
231        0x14   in fpu_etc.c
232        0x1nn  in a *.c file:
233               0x101  in reg_add_sub.c
234               0x102  in reg_mul.c
235               0x104  in poly_atan.c
236               0x105  in reg_mul.c
237               0x107  in fpu_trig.c
238               0x108  in reg_compare.c
239               0x109  in reg_compare.c
240               0x110  in reg_add_sub.c
241               0x111  in fpe_entry.c
242               0x112  in fpu_trig.c
243               0x113  in errors.c
244               0x115  in fpu_trig.c
245               0x116  in fpu_trig.c
246               0x117  in fpu_trig.c
247               0x118  in fpu_trig.c
248               0x119  in fpu_trig.c
249               0x120  in poly_atan.c
250               0x121  in reg_compare.c
251               0x122  in reg_compare.c
252               0x123  in reg_compare.c
253               0x125  in fpu_trig.c
254               0x126  in fpu_entry.c
255               0x127  in poly_2xm1.c
256               0x128  in fpu_entry.c
257               0x129  in fpu_entry.c
258               0x130  in get_address.c
259               0x131  in get_address.c
260               0x132  in get_address.c
261               0x133  in get_address.c
262               0x140  in load_store.c
263               0x141  in load_store.c
264               0x150  in poly_sin.c
265               0x151  in poly_sin.c
266               0x160  in reg_ld_str.c
267               0x161  in reg_ld_str.c
268               0x162  in reg_ld_str.c
269               0x163  in reg_ld_str.c
270               0x164  in reg_ld_str.c
271               0x170  in fpu_tags.c
272               0x171  in fpu_tags.c
273               0x172  in fpu_tags.c
274               0x180  in reg_convert.c
275        0x2nn  in an *.S file:
276               0x201  in reg_u_add.S
277               0x202  in reg_u_div.S
278               0x203  in reg_u_div.S
279               0x204  in reg_u_div.S
280               0x205  in reg_u_mul.S
281               0x206  in reg_u_sub.S
282               0x207  in wm_sqrt.S
283               0x208  in reg_div.S
284               0x209  in reg_u_sub.S
285               0x210  in reg_u_sub.S
286               0x211  in reg_u_sub.S
287               0x212  in reg_u_sub.S
288               0x213  in wm_sqrt.S
289               0x214  in wm_sqrt.S
290               0x215  in wm_sqrt.S
291               0x220  in reg_norm.S
292               0x221  in reg_norm.S
293               0x230  in reg_round.S
294               0x231  in reg_round.S
295               0x232  in reg_round.S
296               0x233  in reg_round.S
297               0x234  in reg_round.S
298               0x235  in reg_round.S
299               0x236  in reg_round.S
300               0x240  in div_Xsig.S
301               0x241  in div_Xsig.S
302               0x242  in div_Xsig.S
303  */
304
305 asmlinkage void FPU_exception(int n)
306 {
307         int i, int_type;
308
309         int_type = 0;           /* Needed only to stop compiler warnings */
310         if (n & EX_INTERNAL) {
311                 int_type = n - EX_INTERNAL;
312                 n = EX_INTERNAL;
313                 /* Set lots of exception bits! */
314                 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
315         } else {
316                 /* Extract only the bits which we use to set the status word */
317                 n &= (SW_Exc_Mask);
318                 /* Set the corresponding exception bit */
319                 partial_status |= n;
320                 /* Set summary bits iff exception isn't masked */
321                 if (partial_status & ~control_word & CW_Exceptions)
322                         partial_status |= (SW_Summary | SW_Backward);
323                 if (n & (SW_Stack_Fault | EX_Precision)) {
324                         if (!(n & SW_C1))
325                                 /* This bit distinguishes over- from underflow for a stack fault,
326                                    and roundup from round-down for precision loss. */
327                                 partial_status &= ~SW_C1;
328                 }
329         }
330
331         RE_ENTRANT_CHECK_OFF;
332         if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
333 #ifdef PRINT_MESSAGES
334                 /* My message from the sponsor */
335                 printk(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
336 #endif /* PRINT_MESSAGES */
337
338                 /* Get a name string for error reporting */
339                 for (i = 0; exception_names[i].type; i++)
340                         if ((exception_names[i].type & n) ==
341                             exception_names[i].type)
342                                 break;
343
344                 if (exception_names[i].type) {
345 #ifdef PRINT_MESSAGES
346                         printk("FP Exception: %s!\n", exception_names[i].name);
347 #endif /* PRINT_MESSAGES */
348                 } else
349                         printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
350
351                 if (n == EX_INTERNAL) {
352                         printk("FPU emulator: Internal error type 0x%04x\n",
353                                int_type);
354                         FPU_printall();
355                 }
356 #ifdef PRINT_MESSAGES
357                 else
358                         FPU_printall();
359 #endif /* PRINT_MESSAGES */
360
361                 /*
362                  * The 80486 generates an interrupt on the next non-control FPU
363                  * instruction. So we need some means of flagging it.
364                  * We use the ES (Error Summary) bit for this.
365                  */
366         }
367         RE_ENTRANT_CHECK_ON;
368
369 #ifdef __DEBUG__
370         math_abort(FPU_info, SIGFPE);
371 #endif /* __DEBUG__ */
372
373 }
374
375 /* Real operation attempted on a NaN. */
376 /* Returns < 0 if the exception is unmasked */
377 int real_1op_NaN(FPU_REG *a)
378 {
379         int signalling, isNaN;
380
381         isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
382
383         /* The default result for the case of two "equal" NaNs (signs may
384            differ) is chosen to reproduce 80486 behaviour */
385         signalling = isNaN && !(a->sigh & 0x40000000);
386
387         if (!signalling) {
388                 if (!isNaN) {   /* pseudo-NaN, or other unsupported? */
389                         if (control_word & CW_Invalid) {
390                                 /* Masked response */
391                                 reg_copy(&CONST_QNaN, a);
392                         }
393                         EXCEPTION(EX_Invalid);
394                         return (!(control_word & CW_Invalid) ? FPU_Exception :
395                                 0) | TAG_Special;
396                 }
397                 return TAG_Special;
398         }
399
400         if (control_word & CW_Invalid) {
401                 /* The masked response */
402                 if (!(a->sigh & 0x80000000)) {  /* pseudo-NaN ? */
403                         reg_copy(&CONST_QNaN, a);
404                 }
405                 /* ensure a Quiet NaN */
406                 a->sigh |= 0x40000000;
407         }
408
409         EXCEPTION(EX_Invalid);
410
411         return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
412 }
413
414 /* Real operation attempted on two operands, one a NaN. */
415 /* Returns < 0 if the exception is unmasked */
416 int real_2op_NaN(FPU_REG const *b, u_char tagb,
417                  int deststnr, FPU_REG const *defaultNaN)
418 {
419         FPU_REG *dest = &st(deststnr);
420         FPU_REG const *a = dest;
421         u_char taga = FPU_gettagi(deststnr);
422         FPU_REG const *x;
423         int signalling, unsupported;
424
425         if (taga == TAG_Special)
426                 taga = FPU_Special(a);
427         if (tagb == TAG_Special)
428                 tagb = FPU_Special(b);
429
430         /* TW_NaN is also used for unsupported data types. */
431         unsupported = ((taga == TW_NaN)
432                        && !((exponent(a) == EXP_OVER)
433                             && (a->sigh & 0x80000000)))
434             || ((tagb == TW_NaN)
435                 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
436         if (unsupported) {
437                 if (control_word & CW_Invalid) {
438                         /* Masked response */
439                         FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
440                 }
441                 EXCEPTION(EX_Invalid);
442                 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
443                     TAG_Special;
444         }
445
446         if (taga == TW_NaN) {
447                 x = a;
448                 if (tagb == TW_NaN) {
449                         signalling = !(a->sigh & b->sigh & 0x40000000);
450                         if (significand(b) > significand(a))
451                                 x = b;
452                         else if (significand(b) == significand(a)) {
453                                 /* The default result for the case of two "equal" NaNs (signs may
454                                    differ) is chosen to reproduce 80486 behaviour */
455                                 x = defaultNaN;
456                         }
457                 } else {
458                         /* return the quiet version of the NaN in a */
459                         signalling = !(a->sigh & 0x40000000);
460                 }
461         } else
462 #ifdef PARANOID
463         if (tagb == TW_NaN)
464 #endif /* PARANOID */
465         {
466                 signalling = !(b->sigh & 0x40000000);
467                 x = b;
468         }
469 #ifdef PARANOID
470         else {
471                 signalling = 0;
472                 EXCEPTION(EX_INTERNAL | 0x113);
473                 x = &CONST_QNaN;
474         }
475 #endif /* PARANOID */
476
477         if ((!signalling) || (control_word & CW_Invalid)) {
478                 if (!x)
479                         x = b;
480
481                 if (!(x->sigh & 0x80000000))    /* pseudo-NaN ? */
482                         x = &CONST_QNaN;
483
484                 FPU_copy_to_regi(x, TAG_Special, deststnr);
485
486                 if (!signalling)
487                         return TAG_Special;
488
489                 /* ensure a Quiet NaN */
490                 dest->sigh |= 0x40000000;
491         }
492
493         EXCEPTION(EX_Invalid);
494
495         return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
496 }
497
498 /* Invalid arith operation on Valid registers */
499 /* Returns < 0 if the exception is unmasked */
500 asmlinkage int arith_invalid(int deststnr)
501 {
502
503         EXCEPTION(EX_Invalid);
504
505         if (control_word & CW_Invalid) {
506                 /* The masked response */
507                 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
508         }
509
510         return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
511
512 }
513
514 /* Divide a finite number by zero */
515 asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
516 {
517         FPU_REG *dest = &st(deststnr);
518         int tag = TAG_Valid;
519
520         if (control_word & CW_ZeroDiv) {
521                 /* The masked response */
522                 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
523                 setsign(dest, sign);
524                 tag = TAG_Special;
525         }
526
527         EXCEPTION(EX_ZeroDiv);
528
529         return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
530
531 }
532
533 /* This may be called often, so keep it lean */
534 int set_precision_flag(int flags)
535 {
536         if (control_word & CW_Precision) {
537                 partial_status &= ~(SW_C1 & flags);
538                 partial_status |= flags;        /* The masked response */
539                 return 0;
540         } else {
541                 EXCEPTION(flags);
542                 return 1;
543         }
544 }
545
546 /* This may be called often, so keep it lean */
547 asmlinkage void set_precision_flag_up(void)
548 {
549         if (control_word & CW_Precision)
550                 partial_status |= (SW_Precision | SW_C1);       /* The masked response */
551         else
552                 EXCEPTION(EX_Precision | SW_C1);
553 }
554
555 /* This may be called often, so keep it lean */
556 asmlinkage void set_precision_flag_down(void)
557 {
558         if (control_word & CW_Precision) {      /* The masked response */
559                 partial_status &= ~SW_C1;
560                 partial_status |= SW_Precision;
561         } else
562                 EXCEPTION(EX_Precision);
563 }
564
565 asmlinkage int denormal_operand(void)
566 {
567         if (control_word & CW_Denormal) {       /* The masked response */
568                 partial_status |= SW_Denorm_Op;
569                 return TAG_Special;
570         } else {
571                 EXCEPTION(EX_Denormal);
572                 return TAG_Special | FPU_Exception;
573         }
574 }
575
576 asmlinkage int arith_overflow(FPU_REG *dest)
577 {
578         int tag = TAG_Valid;
579
580         if (control_word & CW_Overflow) {
581                 /* The masked response */
582 /* ###### The response here depends upon the rounding mode */
583                 reg_copy(&CONST_INF, dest);
584                 tag = TAG_Special;
585         } else {
586                 /* Subtract the magic number from the exponent */
587                 addexponent(dest, (-3 * (1 << 13)));
588         }
589
590         EXCEPTION(EX_Overflow);
591         if (control_word & CW_Overflow) {
592                 /* The overflow exception is masked. */
593                 /* By definition, precision is lost.
594                    The roundup bit (C1) is also set because we have
595                    "rounded" upwards to Infinity. */
596                 EXCEPTION(EX_Precision | SW_C1);
597                 return tag;
598         }
599
600         return tag;
601
602 }
603
604 asmlinkage int arith_underflow(FPU_REG *dest)
605 {
606         int tag = TAG_Valid;
607
608         if (control_word & CW_Underflow) {
609                 /* The masked response */
610                 if (exponent16(dest) <= EXP_UNDER - 63) {
611                         reg_copy(&CONST_Z, dest);
612                         partial_status &= ~SW_C1;       /* Round down. */
613                         tag = TAG_Zero;
614                 } else {
615                         stdexp(dest);
616                 }
617         } else {
618                 /* Add the magic number to the exponent. */
619                 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
620         }
621
622         EXCEPTION(EX_Underflow);
623         if (control_word & CW_Underflow) {
624                 /* The underflow exception is masked. */
625                 EXCEPTION(EX_Precision);
626                 return tag;
627         }
628
629         return tag;
630
631 }
632
633 void FPU_stack_overflow(void)
634 {
635
636         if (control_word & CW_Invalid) {
637                 /* The masked response */
638                 top--;
639                 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
640         }
641
642         EXCEPTION(EX_StackOver);
643
644         return;
645
646 }
647
648 void FPU_stack_underflow(void)
649 {
650
651         if (control_word & CW_Invalid) {
652                 /* The masked response */
653                 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
654         }
655
656         EXCEPTION(EX_StackUnder);
657
658         return;
659
660 }
661
662 void FPU_stack_underflow_i(int i)
663 {
664
665         if (control_word & CW_Invalid) {
666                 /* The masked response */
667                 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
668         }
669
670         EXCEPTION(EX_StackUnder);
671
672         return;
673
674 }
675
676 void FPU_stack_underflow_pop(int i)
677 {
678
679         if (control_word & CW_Invalid) {
680                 /* The masked response */
681                 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
682                 FPU_pop();
683         }
684
685         EXCEPTION(EX_StackUnder);
686
687         return;
688
689 }