~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/errors.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*---------------------------------------------------------------------------+
  3  |  errors.c                                                                 |
  4  |                                                                           |
  5  |  The error handling functions for wm-FPU-emu                              |
  6  |                                                                           |
  7  | Copyright (C) 1992,1993,1994,1996                                         |
  8  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  9  |                  E-mail   billm@jacobi.maths.monash.edu.au                |
 10  |                                                                           |
 11  |                                                                           |
 12  +---------------------------------------------------------------------------*/
 13 
 14 /*---------------------------------------------------------------------------+
 15  | Note:                                                                     |
 16  |    The file contains code which accesses user memory.                     |
 17  |    Emulator static data may change when user memory is accessed, due to   |
 18  |    other processes using the emulator while swapping is in progress.      |
 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         /* No need to check access_ok(), we have previously fetched these bytes. */
 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 /*  0  */
 72 
 73 /*
 74    Called for opcodes which are illegal and which are known to result in a
 75    SIGILL with a real 80486.
 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         /* No need to check access_ok(), we have previously fetched these bytes. */
 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 /* DEBUGGING */
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,    /* busy */
154                (partial_status & 0x3800) >> 11, /* stack top pointer */
155                partial_status & 0x80 ? 1 : 0,   /* Error summary status */
156                partial_status & 0x40 ? 1 : 0,   /* Stack flag */
157                partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0,  /* cc */
158                partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0,  /* cc */
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                         /* Update tagi for the printk below */
188                         tagi = FPU_Special(r);
189                         fallthrough;
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  EX_INTERNAL is always given with a code which indicates where the
230  error was detected.
231 
232  Internal error types:
233        0x14   in fpu_etc.c
234        0x1nn  in a *.c file:
235               0x101  in reg_add_sub.c
236               0x102  in reg_mul.c
237               0x104  in poly_atan.c
238               0x105  in reg_mul.c
239               0x107  in fpu_trig.c
240               0x108  in reg_compare.c
241               0x109  in reg_compare.c
242               0x110  in reg_add_sub.c
243               0x111  in fpe_entry.c
244               0x112  in fpu_trig.c
245               0x113  in errors.c
246               0x115  in fpu_trig.c
247               0x116  in fpu_trig.c
248               0x117  in fpu_trig.c
249               0x118  in fpu_trig.c
250               0x119  in fpu_trig.c
251               0x120  in poly_atan.c
252               0x121  in reg_compare.c
253               0x122  in reg_compare.c
254               0x123  in reg_compare.c
255               0x125  in fpu_trig.c
256               0x126  in fpu_entry.c
257               0x127  in poly_2xm1.c
258               0x128  in fpu_entry.c
259               0x129  in fpu_entry.c
260               0x130  in get_address.c
261               0x131  in get_address.c
262               0x132  in get_address.c
263               0x133  in get_address.c
264               0x140  in load_store.c
265               0x141  in load_store.c
266               0x150  in poly_sin.c
267               0x151  in poly_sin.c
268               0x160  in reg_ld_str.c
269               0x161  in reg_ld_str.c
270               0x162  in reg_ld_str.c
271               0x163  in reg_ld_str.c
272               0x164  in reg_ld_str.c
273               0x170  in fpu_tags.c
274               0x171  in fpu_tags.c
275               0x172  in fpu_tags.c
276               0x180  in reg_convert.c
277        0x2nn  in an *.S file:
278               0x201  in reg_u_add.S
279               0x202  in reg_u_div.S
280               0x203  in reg_u_div.S
281               0x204  in reg_u_div.S
282               0x205  in reg_u_mul.S
283               0x206  in reg_u_sub.S
284               0x207  in wm_sqrt.S
285               0x208  in reg_div.S
286               0x209  in reg_u_sub.S
287               0x210  in reg_u_sub.S
288               0x211  in reg_u_sub.S
289               0x212  in reg_u_sub.S
290               0x213  in wm_sqrt.S
291               0x214  in wm_sqrt.S
292               0x215  in wm_sqrt.S
293               0x220  in reg_norm.S
294               0x221  in reg_norm.S
295               0x230  in reg_round.S
296               0x231  in reg_round.S
297               0x232  in reg_round.S
298               0x233  in reg_round.S
299               0x234  in reg_round.S
300               0x235  in reg_round.S
301               0x236  in reg_round.S
302               0x240  in div_Xsig.S
303               0x241  in div_Xsig.S
304               0x242  in div_Xsig.S
305  */
306 
307 asmlinkage __visible void FPU_exception(int n)
308 {
309         int i, int_type;
310 
311         int_type = 0;           /* Needed only to stop compiler warnings */
312         if (n & EX_INTERNAL) {
313                 int_type = n - EX_INTERNAL;
314                 n = EX_INTERNAL;
315                 /* Set lots of exception bits! */
316                 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
317         } else {
318                 /* Extract only the bits which we use to set the status word */
319                 n &= (SW_Exc_Mask);
320                 /* Set the corresponding exception bit */
321                 partial_status |= n;
322                 /* Set summary bits iff exception isn't masked */
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                                 /* This bit distinguishes over- from underflow for a stack fault,
328                                    and roundup from round-down for precision loss. */
329                                 partial_status &= ~SW_C1;
330                 }
331         }
332 
333         RE_ENTRANT_CHECK_OFF;
334         if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
335                 /* Get a name string for error reporting */
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 /* PRINT_MESSAGES */
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 /* PRINT_MESSAGES */
357 
358                 /*
359                  * The 80486 generates an interrupt on the next non-control FPU
360                  * instruction. So we need some means of flagging it.
361                  * We use the ES (Error Summary) bit for this.
362                  */
363         }
364         RE_ENTRANT_CHECK_ON;
365 
366 #ifdef __DEBUG__
367         math_abort(FPU_info, SIGFPE);
368 #endif /* __DEBUG__ */
369 
370 }
371 
372 /* Real operation attempted on a NaN. */
373 /* Returns < 0 if the exception is unmasked */
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         /* The default result for the case of two "equal" NaNs (signs may
381            differ) is chosen to reproduce 80486 behaviour */
382         signalling = isNaN && !(a->sigh & 0x40000000);
383 
384         if (!signalling) {
385                 if (!isNaN) {   /* pseudo-NaN, or other unsupported? */
386                         if (control_word & CW_Invalid) {
387                                 /* Masked response */
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                 /* The masked response */
399                 if (!(a->sigh & 0x80000000)) {  /* pseudo-NaN ? */
400                         reg_copy(&CONST_QNaN, a);
401                 }
402                 /* ensure a Quiet NaN */
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 /* Real operation attempted on two operands, one a NaN. */
412 /* Returns < 0 if the exception is unmasked */
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         /* TW_NaN is also used for unsupported data types. */
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                         /* Masked response */
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                                 /* The default result for the case of two "equal" NaNs (signs may
451                                    differ) is chosen to reproduce 80486 behaviour */
452                                 x = defaultNaN;
453                         }
454                 } else {
455                         /* return the quiet version of the NaN in a */
456                         signalling = !(a->sigh & 0x40000000);
457                 }
458         } else
459 #ifdef PARANOID
460         if (tagb == TW_NaN)
461 #endif /* PARANOID */
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 /* PARANOID */
473 
474         if ((!signalling) || (control_word & CW_Invalid)) {
475                 if (!x)
476                         x = b;
477 
478                 if (!(x->sigh & 0x80000000))    /* pseudo-NaN ? */
479                         x = &CONST_QNaN;
480 
481                 FPU_copy_to_regi(x, TAG_Special, deststnr);
482 
483                 if (!signalling)
484                         return TAG_Special;
485 
486                 /* ensure a Quiet NaN */
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 /* Invalid arith operation on Valid registers */
496 /* Returns < 0 if the exception is unmasked */
497 asmlinkage __visible int arith_invalid(int deststnr)
498 {
499 
500         EXCEPTION(EX_Invalid);
501 
502         if (control_word & CW_Invalid) {
503                 /* The masked response */
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 /* Divide a finite number by zero */
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                 /* The masked response */
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 /* This may be called often, so keep it lean */
531 int set_precision_flag(int flags)
532 {
533         if (control_word & CW_Precision) {
534                 partial_status &= ~(SW_C1 & flags);
535                 partial_status |= flags;        /* The masked response */
536                 return 0;
537         } else {
538                 EXCEPTION(flags);
539                 return 1;
540         }
541 }
542 
543 /* This may be called often, so keep it lean */
544 asmlinkage __visible void set_precision_flag_up(void)
545 {
546         if (control_word & CW_Precision)
547                 partial_status |= (SW_Precision | SW_C1);       /* The masked response */
548         else
549                 EXCEPTION(EX_Precision | SW_C1);
550 }
551 
552 /* This may be called often, so keep it lean */
553 asmlinkage __visible void set_precision_flag_down(void)
554 {
555         if (control_word & CW_Precision) {      /* The masked response */
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) {       /* The masked response */
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                 /* The masked response */
579 /* ###### The response here depends upon the rounding mode */
580                 reg_copy(&CONST_INF, dest);
581                 tag = TAG_Special;
582         } else {
583                 /* Subtract the magic number from the exponent */
584                 addexponent(dest, (-3 * (1 << 13)));
585         }
586 
587         EXCEPTION(EX_Overflow);
588         if (control_word & CW_Overflow) {
589                 /* The overflow exception is masked. */
590                 /* By definition, precision is lost.
591                    The roundup bit (C1) is also set because we have
592                    "rounded" upwards to Infinity. */
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                 /* The masked response */
607                 if (exponent16(dest) <= EXP_UNDER - 63) {
608                         reg_copy(&CONST_Z, dest);
609                         partial_status &= ~SW_C1;       /* Round down. */
610                         tag = TAG_Zero;
611                 } else {
612                         stdexp(dest);
613                 }
614         } else {
615                 /* Add the magic number to the exponent. */
616                 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
617         }
618 
619         EXCEPTION(EX_Underflow);
620         if (control_word & CW_Underflow) {
621                 /* The underflow exception is masked. */
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                 /* The masked response */
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                 /* The masked response */
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                 /* The masked response */
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                 /* The masked response */
678                 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
679                 FPU_pop();
680         }
681 
682         EXCEPTION(EX_StackUnder);
683 
684         return;
685 
686 }
687 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php