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 }