0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <linux/signal.h>
0022
0023 #include <linux/uaccess.h>
0024
0025 #include "fpu_emu.h"
0026 #include "fpu_system.h"
0027 #include "exception.h"
0028 #include "status_w.h"
0029 #include "control_w.h"
0030 #include "reg_constant.h"
0031 #include "version.h"
0032
0033
0034 #undef PRINT_MESSAGES
0035
0036
0037 #if 0
0038 void Un_impl(void)
0039 {
0040 u_char byte1, FPU_modrm;
0041 unsigned long address = FPU_ORIG_EIP;
0042
0043 RE_ENTRANT_CHECK_OFF;
0044
0045 printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address);
0046 if (FPU_CS == __USER_CS) {
0047 while (1) {
0048 FPU_get_user(byte1, (u_char __user *) address);
0049 if ((byte1 & 0xf8) == 0xd8)
0050 break;
0051 printk("[%02x]", byte1);
0052 address++;
0053 }
0054 printk("%02x ", byte1);
0055 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
0056
0057 if (FPU_modrm >= 0300)
0058 printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8,
0059 FPU_modrm & 7);
0060 else
0061 printk("/%d\n", (FPU_modrm >> 3) & 7);
0062 } else {
0063 printk("cs selector = %04x\n", FPU_CS);
0064 }
0065
0066 RE_ENTRANT_CHECK_ON;
0067
0068 EXCEPTION(EX_Invalid);
0069
0070 }
0071 #endif
0072
0073
0074
0075
0076
0077 void FPU_illegal(void)
0078 {
0079 math_abort(FPU_info, SIGILL);
0080 }
0081
0082 void FPU_printall(void)
0083 {
0084 int i;
0085 static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
0086 "DeNorm", "Inf", "NaN"
0087 };
0088 u_char byte1, FPU_modrm;
0089 unsigned long address = FPU_ORIG_EIP;
0090
0091 RE_ENTRANT_CHECK_OFF;
0092
0093 printk("At %p:", (void *)address);
0094 if (FPU_CS == __USER_CS) {
0095 #define MAX_PRINTED_BYTES 20
0096 for (i = 0; i < MAX_PRINTED_BYTES; i++) {
0097 FPU_get_user(byte1, (u_char __user *) address);
0098 if ((byte1 & 0xf8) == 0xd8) {
0099 printk(" %02x", byte1);
0100 break;
0101 }
0102 printk(" [%02x]", byte1);
0103 address++;
0104 }
0105 if (i == MAX_PRINTED_BYTES)
0106 printk(" [more..]\n");
0107 else {
0108 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
0109
0110 if (FPU_modrm >= 0300)
0111 printk(" %02x (%02x+%d)\n", FPU_modrm,
0112 FPU_modrm & 0xf8, FPU_modrm & 7);
0113 else
0114 printk(" /%d, mod=%d rm=%d\n",
0115 (FPU_modrm >> 3) & 7,
0116 (FPU_modrm >> 6) & 3, FPU_modrm & 7);
0117 }
0118 } else {
0119 printk("%04x\n", FPU_CS);
0120 }
0121
0122 partial_status = status_word();
0123
0124 #ifdef DEBUGGING
0125 if (partial_status & SW_Backward)
0126 printk("SW: backward compatibility\n");
0127 if (partial_status & SW_C3)
0128 printk("SW: condition bit 3\n");
0129 if (partial_status & SW_C2)
0130 printk("SW: condition bit 2\n");
0131 if (partial_status & SW_C1)
0132 printk("SW: condition bit 1\n");
0133 if (partial_status & SW_C0)
0134 printk("SW: condition bit 0\n");
0135 if (partial_status & SW_Summary)
0136 printk("SW: exception summary\n");
0137 if (partial_status & SW_Stack_Fault)
0138 printk("SW: stack fault\n");
0139 if (partial_status & SW_Precision)
0140 printk("SW: loss of precision\n");
0141 if (partial_status & SW_Underflow)
0142 printk("SW: underflow\n");
0143 if (partial_status & SW_Overflow)
0144 printk("SW: overflow\n");
0145 if (partial_status & SW_Zero_Div)
0146 printk("SW: divide by zero\n");
0147 if (partial_status & SW_Denorm_Op)
0148 printk("SW: denormalized operand\n");
0149 if (partial_status & SW_Invalid)
0150 printk("SW: invalid operation\n");
0151 #endif
0152
0153 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,
0154 (partial_status & 0x3800) >> 11,
0155 partial_status & 0x80 ? 1 : 0,
0156 partial_status & 0x40 ? 1 : 0,
0157 partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0,
0158 partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0,
0159 partial_status & SW_Precision ? 1 : 0,
0160 partial_status & SW_Underflow ? 1 : 0,
0161 partial_status & SW_Overflow ? 1 : 0,
0162 partial_status & SW_Zero_Div ? 1 : 0,
0163 partial_status & SW_Denorm_Op ? 1 : 0,
0164 partial_status & SW_Invalid ? 1 : 0);
0165
0166 printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
0167 control_word & 0x1000 ? 1 : 0,
0168 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
0169 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
0170 control_word & 0x80 ? 1 : 0,
0171 control_word & SW_Precision ? 1 : 0,
0172 control_word & SW_Underflow ? 1 : 0,
0173 control_word & SW_Overflow ? 1 : 0,
0174 control_word & SW_Zero_Div ? 1 : 0,
0175 control_word & SW_Denorm_Op ? 1 : 0,
0176 control_word & SW_Invalid ? 1 : 0);
0177
0178 for (i = 0; i < 8; i++) {
0179 FPU_REG *r = &st(i);
0180 u_char tagi = FPU_gettagi(i);
0181
0182 switch (tagi) {
0183 case TAG_Empty:
0184 continue;
0185 case TAG_Zero:
0186 case TAG_Special:
0187
0188 tagi = FPU_Special(r);
0189 fallthrough;
0190 case TAG_Valid:
0191 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
0192 getsign(r) ? '-' : '+',
0193 (long)(r->sigh >> 16),
0194 (long)(r->sigh & 0xFFFF),
0195 (long)(r->sigl >> 16),
0196 (long)(r->sigl & 0xFFFF),
0197 exponent(r) - EXP_BIAS + 1);
0198 break;
0199 default:
0200 printk("Whoops! Error in errors.c: tag%d is %d ", i,
0201 tagi);
0202 continue;
0203 }
0204 printk("%s\n", tag_desc[(int)(unsigned)tagi]);
0205 }
0206
0207 RE_ENTRANT_CHECK_ON;
0208
0209 }
0210
0211 static struct {
0212 int type;
0213 const char *name;
0214 } exception_names[] = {
0215 {
0216 EX_StackOver, "stack overflow"}, {
0217 EX_StackUnder, "stack underflow"}, {
0218 EX_Precision, "loss of precision"}, {
0219 EX_Underflow, "underflow"}, {
0220 EX_Overflow, "overflow"}, {
0221 EX_ZeroDiv, "divide by zero"}, {
0222 EX_Denormal, "denormalized operand"}, {
0223 EX_Invalid, "invalid operation"}, {
0224 EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
0225 0, NULL}
0226 };
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307 asmlinkage __visible void FPU_exception(int n)
0308 {
0309 int i, int_type;
0310
0311 int_type = 0;
0312 if (n & EX_INTERNAL) {
0313 int_type = n - EX_INTERNAL;
0314 n = EX_INTERNAL;
0315
0316 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
0317 } else {
0318
0319 n &= (SW_Exc_Mask);
0320
0321 partial_status |= n;
0322
0323 if (partial_status & ~control_word & CW_Exceptions)
0324 partial_status |= (SW_Summary | SW_Backward);
0325 if (n & (SW_Stack_Fault | EX_Precision)) {
0326 if (!(n & SW_C1))
0327
0328
0329 partial_status &= ~SW_C1;
0330 }
0331 }
0332
0333 RE_ENTRANT_CHECK_OFF;
0334 if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
0335
0336 for (i = 0; exception_names[i].type; i++)
0337 if ((exception_names[i].type & n) ==
0338 exception_names[i].type)
0339 break;
0340
0341 if (exception_names[i].type) {
0342 #ifdef PRINT_MESSAGES
0343 printk("FP Exception: %s!\n", exception_names[i].name);
0344 #endif
0345 } else
0346 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
0347
0348 if (n == EX_INTERNAL) {
0349 printk("FPU emulator: Internal error type 0x%04x\n",
0350 int_type);
0351 FPU_printall();
0352 }
0353 #ifdef PRINT_MESSAGES
0354 else
0355 FPU_printall();
0356 #endif
0357
0358
0359
0360
0361
0362
0363 }
0364 RE_ENTRANT_CHECK_ON;
0365
0366 #ifdef __DEBUG__
0367 math_abort(FPU_info, SIGFPE);
0368 #endif
0369
0370 }
0371
0372
0373
0374 int real_1op_NaN(FPU_REG *a)
0375 {
0376 int signalling, isNaN;
0377
0378 isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
0379
0380
0381
0382 signalling = isNaN && !(a->sigh & 0x40000000);
0383
0384 if (!signalling) {
0385 if (!isNaN) {
0386 if (control_word & CW_Invalid) {
0387
0388 reg_copy(&CONST_QNaN, a);
0389 }
0390 EXCEPTION(EX_Invalid);
0391 return (!(control_word & CW_Invalid) ? FPU_Exception :
0392 0) | TAG_Special;
0393 }
0394 return TAG_Special;
0395 }
0396
0397 if (control_word & CW_Invalid) {
0398
0399 if (!(a->sigh & 0x80000000)) {
0400 reg_copy(&CONST_QNaN, a);
0401 }
0402
0403 a->sigh |= 0x40000000;
0404 }
0405
0406 EXCEPTION(EX_Invalid);
0407
0408 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
0409 }
0410
0411
0412
0413 int real_2op_NaN(FPU_REG const *b, u_char tagb,
0414 int deststnr, FPU_REG const *defaultNaN)
0415 {
0416 FPU_REG *dest = &st(deststnr);
0417 FPU_REG const *a = dest;
0418 u_char taga = FPU_gettagi(deststnr);
0419 FPU_REG const *x;
0420 int signalling, unsupported;
0421
0422 if (taga == TAG_Special)
0423 taga = FPU_Special(a);
0424 if (tagb == TAG_Special)
0425 tagb = FPU_Special(b);
0426
0427
0428 unsupported = ((taga == TW_NaN)
0429 && !((exponent(a) == EXP_OVER)
0430 && (a->sigh & 0x80000000)))
0431 || ((tagb == TW_NaN)
0432 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
0433 if (unsupported) {
0434 if (control_word & CW_Invalid) {
0435
0436 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
0437 }
0438 EXCEPTION(EX_Invalid);
0439 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
0440 TAG_Special;
0441 }
0442
0443 if (taga == TW_NaN) {
0444 x = a;
0445 if (tagb == TW_NaN) {
0446 signalling = !(a->sigh & b->sigh & 0x40000000);
0447 if (significand(b) > significand(a))
0448 x = b;
0449 else if (significand(b) == significand(a)) {
0450
0451
0452 x = defaultNaN;
0453 }
0454 } else {
0455
0456 signalling = !(a->sigh & 0x40000000);
0457 }
0458 } else
0459 #ifdef PARANOID
0460 if (tagb == TW_NaN)
0461 #endif
0462 {
0463 signalling = !(b->sigh & 0x40000000);
0464 x = b;
0465 }
0466 #ifdef PARANOID
0467 else {
0468 signalling = 0;
0469 EXCEPTION(EX_INTERNAL | 0x113);
0470 x = &CONST_QNaN;
0471 }
0472 #endif
0473
0474 if ((!signalling) || (control_word & CW_Invalid)) {
0475 if (!x)
0476 x = b;
0477
0478 if (!(x->sigh & 0x80000000))
0479 x = &CONST_QNaN;
0480
0481 FPU_copy_to_regi(x, TAG_Special, deststnr);
0482
0483 if (!signalling)
0484 return TAG_Special;
0485
0486
0487 dest->sigh |= 0x40000000;
0488 }
0489
0490 EXCEPTION(EX_Invalid);
0491
0492 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
0493 }
0494
0495
0496
0497 asmlinkage __visible int arith_invalid(int deststnr)
0498 {
0499
0500 EXCEPTION(EX_Invalid);
0501
0502 if (control_word & CW_Invalid) {
0503
0504 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
0505 }
0506
0507 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
0508
0509 }
0510
0511
0512 asmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign)
0513 {
0514 FPU_REG *dest = &st(deststnr);
0515 int tag = TAG_Valid;
0516
0517 if (control_word & CW_ZeroDiv) {
0518
0519 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
0520 setsign(dest, sign);
0521 tag = TAG_Special;
0522 }
0523
0524 EXCEPTION(EX_ZeroDiv);
0525
0526 return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
0527
0528 }
0529
0530
0531 int set_precision_flag(int flags)
0532 {
0533 if (control_word & CW_Precision) {
0534 partial_status &= ~(SW_C1 & flags);
0535 partial_status |= flags;
0536 return 0;
0537 } else {
0538 EXCEPTION(flags);
0539 return 1;
0540 }
0541 }
0542
0543
0544 asmlinkage __visible void set_precision_flag_up(void)
0545 {
0546 if (control_word & CW_Precision)
0547 partial_status |= (SW_Precision | SW_C1);
0548 else
0549 EXCEPTION(EX_Precision | SW_C1);
0550 }
0551
0552
0553 asmlinkage __visible void set_precision_flag_down(void)
0554 {
0555 if (control_word & CW_Precision) {
0556 partial_status &= ~SW_C1;
0557 partial_status |= SW_Precision;
0558 } else
0559 EXCEPTION(EX_Precision);
0560 }
0561
0562 asmlinkage __visible int denormal_operand(void)
0563 {
0564 if (control_word & CW_Denormal) {
0565 partial_status |= SW_Denorm_Op;
0566 return TAG_Special;
0567 } else {
0568 EXCEPTION(EX_Denormal);
0569 return TAG_Special | FPU_Exception;
0570 }
0571 }
0572
0573 asmlinkage __visible int arith_overflow(FPU_REG *dest)
0574 {
0575 int tag = TAG_Valid;
0576
0577 if (control_word & CW_Overflow) {
0578
0579
0580 reg_copy(&CONST_INF, dest);
0581 tag = TAG_Special;
0582 } else {
0583
0584 addexponent(dest, (-3 * (1 << 13)));
0585 }
0586
0587 EXCEPTION(EX_Overflow);
0588 if (control_word & CW_Overflow) {
0589
0590
0591
0592
0593 EXCEPTION(EX_Precision | SW_C1);
0594 return tag;
0595 }
0596
0597 return tag;
0598
0599 }
0600
0601 asmlinkage __visible int arith_underflow(FPU_REG *dest)
0602 {
0603 int tag = TAG_Valid;
0604
0605 if (control_word & CW_Underflow) {
0606
0607 if (exponent16(dest) <= EXP_UNDER - 63) {
0608 reg_copy(&CONST_Z, dest);
0609 partial_status &= ~SW_C1;
0610 tag = TAG_Zero;
0611 } else {
0612 stdexp(dest);
0613 }
0614 } else {
0615
0616 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
0617 }
0618
0619 EXCEPTION(EX_Underflow);
0620 if (control_word & CW_Underflow) {
0621
0622 EXCEPTION(EX_Precision);
0623 return tag;
0624 }
0625
0626 return tag;
0627
0628 }
0629
0630 void FPU_stack_overflow(void)
0631 {
0632
0633 if (control_word & CW_Invalid) {
0634
0635 top--;
0636 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
0637 }
0638
0639 EXCEPTION(EX_StackOver);
0640
0641 return;
0642
0643 }
0644
0645 void FPU_stack_underflow(void)
0646 {
0647
0648 if (control_word & CW_Invalid) {
0649
0650 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
0651 }
0652
0653 EXCEPTION(EX_StackUnder);
0654
0655 return;
0656
0657 }
0658
0659 void FPU_stack_underflow_i(int i)
0660 {
0661
0662 if (control_word & CW_Invalid) {
0663
0664 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
0665 }
0666
0667 EXCEPTION(EX_StackUnder);
0668
0669 return;
0670
0671 }
0672
0673 void FPU_stack_underflow_pop(int i)
0674 {
0675
0676 if (control_word & CW_Invalid) {
0677
0678 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
0679 FPU_pop();
0680 }
0681
0682 EXCEPTION(EX_StackUnder);
0683
0684 return;
0685
0686 }