1 /* 2 * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator 3 * 4 * MIPS floating point support 5 * Copyright (C) 1994-2000 Algorithmics Ltd. 6 * http://www.algor.co.uk 7 * 8 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com 9 * Copyright (C) 2000 MIPS Technologies, Inc. 10 * 11 * This program is free software; you can distribute it and/or modify it 12 * under the terms of the GNU General Public License (Version 2) as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 23 * 24 * A complete emulator for MIPS coprocessor 1 instructions. This is 25 * required for #float(switch) or #float(trap), where it catches all 26 * COP1 instructions via the "CoProcessor Unusable" exception. 27 * 28 * More surprisingly it is also required for #float(ieee), to help out 29 * the hardware fpu at the boundaries of the IEEE-754 representation 30 * (denormalised values, infinities, underflow, etc). It is made 31 * quite nasty because emulation of some non-COP1 instructions is 32 * required, e.g. in branch delay slots. 33 * 34 * Note if you know that you won't have an fpu, then you'll get much 35 * better performance by compiling with -msoft-float! 36 */ 37 #include <linux/sched.h> 38 39 #include <asm/inst.h> 40 #include <asm/bootinfo.h> 41 #include <asm/cpu.h> 42 #include <asm/cpu-features.h> 43 #include <asm/processor.h> 44 #include <asm/ptrace.h> 45 #include <asm/signal.h> 46 #include <asm/mipsregs.h> 47 #include <asm/fpu_emulator.h> 48 #include <asm/uaccess.h> 49 #include <asm/branch.h> 50 51 #include "ieee754.h" 52 #include "dsemul.h" 53 54 /* Strap kernel emulator for full MIPS IV emulation */ 55 56 #ifdef __mips 57 #undef __mips 58 #endif 59 #define __mips 4 60 61 /* Function which emulates a floating point instruction. */ 62 63 static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, 64 mips_instruction); 65 66 #if __mips >= 4 && __mips != 32 67 static int fpux_emu(struct pt_regs *, 68 struct mips_fpu_struct *, mips_instruction); 69 #endif 70 71 /* Further private data for which no space exists in mips_fpu_struct */ 72 73 struct mips_fpu_emulator_stats fpuemustats; 74 75 /* Control registers */ 76 77 #define FPCREG_RID 0 /* $0 = revision id */ 78 #define FPCREG_CSR 31 /* $31 = csr */ 79 80 /* Convert Mips rounding mode (0..3) to IEEE library modes. */ 81 static const unsigned char ieee_rm[4] = { 82 [FPU_CSR_RN] = IEEE754_RN, 83 [FPU_CSR_RZ] = IEEE754_RZ, 84 [FPU_CSR_RU] = IEEE754_RU, 85 [FPU_CSR_RD] = IEEE754_RD, 86 }; 87 /* Convert IEEE library modes to Mips rounding mode (0..3). */ 88 static const unsigned char mips_rm[4] = { 89 [IEEE754_RN] = FPU_CSR_RN, 90 [IEEE754_RZ] = FPU_CSR_RZ, 91 [IEEE754_RD] = FPU_CSR_RD, 92 [IEEE754_RU] = FPU_CSR_RU, 93 }; 94 95 #if __mips >= 4 96 /* convert condition code register number to csr bit */ 97 static const unsigned int fpucondbit[8] = { 98 FPU_CSR_COND0, 99 FPU_CSR_COND1, 100 FPU_CSR_COND2, 101 FPU_CSR_COND3, 102 FPU_CSR_COND4, 103 FPU_CSR_COND5, 104 FPU_CSR_COND6, 105 FPU_CSR_COND7 106 }; 107 #endif 108 109 110 /* 111 * Redundant with logic already in kernel/branch.c, 112 * embedded in compute_return_epc. At some point, 113 * a single subroutine should be used across both 114 * modules. 115 */ 116 static int isBranchInstr(mips_instruction * i) 117 { 118 switch (MIPSInst_OPCODE(*i)) { 119 case spec_op: 120 switch (MIPSInst_FUNC(*i)) { 121 case jalr_op: 122 case jr_op: 123 return 1; 124 } 125 break; 126 127 case bcond_op: 128 switch (MIPSInst_RT(*i)) { 129 case bltz_op: 130 case bgez_op: 131 case bltzl_op: 132 case bgezl_op: 133 case bltzal_op: 134 case bgezal_op: 135 case bltzall_op: 136 case bgezall_op: 137 return 1; 138 } 139 break; 140 141 case j_op: 142 case jal_op: 143 case jalx_op: 144 case beq_op: 145 case bne_op: 146 case blez_op: 147 case bgtz_op: 148 case beql_op: 149 case bnel_op: 150 case blezl_op: 151 case bgtzl_op: 152 return 1; 153 154 case cop0_op: 155 case cop1_op: 156 case cop2_op: 157 case cop1x_op: 158 if (MIPSInst_RS(*i) == bc_op) 159 return 1; 160 break; 161 } 162 163 return 0; 164 } 165 166 /* 167 * In the Linux kernel, we support selection of FPR format on the 168 * basis of the Status.FR bit. This does imply that, if a full 32 169 * FPRs are desired, there needs to be a flip-flop that can be written 170 * to one at that bit position. In any case, O32 MIPS ABI uses 171 * only the even FPRs (Status.FR = 0). 172 */ 173 174 #define CP0_STATUS_FR_SUPPORT 175 176 #ifdef CP0_STATUS_FR_SUPPORT 177 #define FR_BIT ST0_FR 178 #else 179 #define FR_BIT 0 180 #endif 181 182 #define SIFROMREG(si,x) ((si) = \ 183 (xcp->cp0_status & FR_BIT) || !(x & 1) ? \ 184 (int)ctx->fpr[x] : \ 185 (int)(ctx->fpr[x & ~1] >> 32 )) 186 #define SITOREG(si,x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \ 187 (xcp->cp0_status & FR_BIT) || !(x & 1) ? \ 188 ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ 189 ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) 190 191 #define DIFROMREG(di,x) ((di) = \ 192 ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)]) 193 #define DITOREG(di,x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \ 194 = (di)) 195 196 #define SPFROMREG(sp,x) SIFROMREG((sp).bits,x) 197 #define SPTOREG(sp,x) SITOREG((sp).bits,x) 198 #define DPFROMREG(dp,x) DIFROMREG((dp).bits,x) 199 #define DPTOREG(dp,x) DITOREG((dp).bits,x) 200 201 /* 202 * Emulate the single floating point instruction pointed at by EPC. 203 * Two instructions if the instruction is in a branch delay slot. 204 */ 205 206 static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) 207 { 208 mips_instruction ir; 209 void * emulpc, *contpc; 210 unsigned int cond; 211 212 if (get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) { 213 fpuemustats.errors++; 214 return SIGBUS; 215 } 216 217 /* XXX NEC Vr54xx bug workaround */ 218 if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) 219 xcp->cp0_cause &= ~CAUSEF_BD; 220 221 if (xcp->cp0_cause & CAUSEF_BD) { 222 /* 223 * The instruction to be emulated is in a branch delay slot 224 * which means that we have to emulate the branch instruction 225 * BEFORE we do the cop1 instruction. 226 * 227 * This branch could be a COP1 branch, but in that case we 228 * would have had a trap for that instruction, and would not 229 * come through this route. 230 * 231 * Linux MIPS branch emulator operates on context, updating the 232 * cp0_epc. 233 */ 234 emulpc = (void *) (xcp->cp0_epc + 4); /* Snapshot emulation target */ 235 236 if (__compute_return_epc(xcp)) { 237 #ifdef CP1DBG 238 printk("failed to emulate branch at %p\n", 239 (void *) (xcp->cp0_epc)); 240 #endif 241 return SIGILL; 242 } 243 if (get_user(ir, (mips_instruction __user *) emulpc)) { 244 fpuemustats.errors++; 245 return SIGBUS; 246 } 247 /* __compute_return_epc() will have updated cp0_epc */ 248 contpc = (void *) xcp->cp0_epc; 249 /* In order not to confuse ptrace() et al, tweak context */ 250 xcp->cp0_epc = (unsigned long) emulpc - 4; 251 } else { 252 emulpc = (void *) xcp->cp0_epc; 253 contpc = (void *) (xcp->cp0_epc + 4); 254 } 255 256 emul: 257 fpuemustats.emulated++; 258 switch (MIPSInst_OPCODE(ir)) { 259 case ldc1_op:{ 260 u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 261 MIPSInst_SIMM(ir)); 262 u64 val; 263 264 fpuemustats.loads++; 265 if (get_user(val, va)) { 266 fpuemustats.errors++; 267 return SIGBUS; 268 } 269 DITOREG(val, MIPSInst_RT(ir)); 270 break; 271 } 272 273 case sdc1_op:{ 274 u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 275 MIPSInst_SIMM(ir)); 276 u64 val; 277 278 fpuemustats.stores++; 279 DIFROMREG(val, MIPSInst_RT(ir)); 280 if (put_user(val, va)) { 281 fpuemustats.errors++; 282 return SIGBUS; 283 } 284 break; 285 } 286 287 case lwc1_op:{ 288 u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 289 MIPSInst_SIMM(ir)); 290 u32 val; 291 292 fpuemustats.loads++; 293 if (get_user(val, va)) { 294 fpuemustats.errors++; 295 return SIGBUS; 296 } 297 SITOREG(val, MIPSInst_RT(ir)); 298 break; 299 } 300 301 case swc1_op:{ 302 u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 303 MIPSInst_SIMM(ir)); 304 u32 val; 305 306 fpuemustats.stores++; 307 SIFROMREG(val, MIPSInst_RT(ir)); 308 if (put_user(val, va)) { 309 fpuemustats.errors++; 310 return SIGBUS; 311 } 312 break; 313 } 314 315 case cop1_op: 316 switch (MIPSInst_RS(ir)) { 317 318 #if defined(__mips64) 319 case dmfc_op: 320 /* copregister fs -> gpr[rt] */ 321 if (MIPSInst_RT(ir) != 0) { 322 DIFROMREG(xcp->regs[MIPSInst_RT(ir)], 323 MIPSInst_RD(ir)); 324 } 325 break; 326 327 case dmtc_op: 328 /* copregister fs <- rt */ 329 DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 330 break; 331 #endif 332 333 case mfc_op: 334 /* copregister rd -> gpr[rt] */ 335 if (MIPSInst_RT(ir) != 0) { 336 SIFROMREG(xcp->regs[MIPSInst_RT(ir)], 337 MIPSInst_RD(ir)); 338 } 339 break; 340 341 case mtc_op: 342 /* copregister rd <- rt */ 343 SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 344 break; 345 346 case cfc_op:{ 347 /* cop control register rd -> gpr[rt] */ 348 u32 value; 349 350 if (ir == CP1UNDEF) { 351 return do_dsemulret(xcp); 352 } 353 if (MIPSInst_RD(ir) == FPCREG_CSR) { 354 value = ctx->fcr31; 355 value = (value & ~0x3) | mips_rm[value & 0x3]; 356 #ifdef CSRTRACE 357 printk("%p gpr[%d]<-csr=%08x\n", 358 (void *) (xcp->cp0_epc), 359 MIPSInst_RT(ir), value); 360 #endif 361 } 362 else if (MIPSInst_RD(ir) == FPCREG_RID) 363 value = 0; 364 else 365 value = 0; 366 if (MIPSInst_RT(ir)) 367 xcp->regs[MIPSInst_RT(ir)] = value; 368 break; 369 } 370 371 case ctc_op:{ 372 /* copregister rd <- rt */ 373 u32 value; 374 375 if (MIPSInst_RT(ir) == 0) 376 value = 0; 377 else 378 value = xcp->regs[MIPSInst_RT(ir)]; 379 380 /* we only have one writable control reg 381 */ 382 if (MIPSInst_RD(ir) == FPCREG_CSR) { 383 #ifdef CSRTRACE 384 printk("%p gpr[%d]->csr=%08x\n", 385 (void *) (xcp->cp0_epc), 386 MIPSInst_RT(ir), value); 387 #endif 388 value &= (FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03); 389 ctx->fcr31 &= ~(FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03); 390 /* convert to ieee library modes */ 391 ctx->fcr31 |= (value & ~0x3) | ieee_rm[value & 0x3]; 392 } 393 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 394 return SIGFPE; 395 } 396 break; 397 } 398 399 case bc_op:{ 400 int likely = 0; 401 402 if (xcp->cp0_cause & CAUSEF_BD) 403 return SIGILL; 404 405 #if __mips >= 4 406 cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2]; 407 #else 408 cond = ctx->fcr31 & FPU_CSR_COND; 409 #endif 410 switch (MIPSInst_RT(ir) & 3) { 411 case bcfl_op: 412 likely = 1; 413 case bcf_op: 414 cond = !cond; 415 break; 416 case bctl_op: 417 likely = 1; 418 case bct_op: 419 break; 420 default: 421 /* thats an illegal instruction */ 422 return SIGILL; 423 } 424 425 xcp->cp0_cause |= CAUSEF_BD; 426 if (cond) { 427 /* branch taken: emulate dslot 428 * instruction 429 */ 430 xcp->cp0_epc += 4; 431 contpc = (void *) 432 (xcp->cp0_epc + 433 (MIPSInst_SIMM(ir) << 2)); 434 435 if (get_user(ir, 436 (mips_instruction __user *) xcp->cp0_epc)) { 437 fpuemustats.errors++; 438 return SIGBUS; 439 } 440 441 switch (MIPSInst_OPCODE(ir)) { 442 case lwc1_op: 443 case swc1_op: 444 #if (__mips >= 2 || defined(__mips64)) 445 case ldc1_op: 446 case sdc1_op: 447 #endif 448 case cop1_op: 449 #if __mips >= 4 && __mips != 32 450 case cop1x_op: 451 #endif 452 /* its one of ours */ 453 goto emul; 454 #if __mips >= 4 455 case spec_op: 456 if (MIPSInst_FUNC(ir) == movc_op) 457 goto emul; 458 break; 459 #endif 460 } 461 462 /* 463 * Single step the non-cp1 464 * instruction in the dslot 465 */ 466 return mips_dsemul(xcp, ir, (unsigned long) contpc); 467 } 468 else { 469 /* branch not taken */ 470 if (likely) { 471 /* 472 * branch likely nullifies 473 * dslot if not taken 474 */ 475 xcp->cp0_epc += 4; 476 contpc += 4; 477 /* 478 * else continue & execute 479 * dslot as normal insn 480 */ 481 } 482 } 483 break; 484 } 485 486 default: 487 if (!(MIPSInst_RS(ir) & 0x10)) 488 return SIGILL; 489 { 490 int sig; 491 492 /* a real fpu computation instruction */ 493 if ((sig = fpu_emu(xcp, ctx, ir))) 494 return sig; 495 } 496 } 497 break; 498 499 #if __mips >= 4 && __mips != 32 500 case cop1x_op:{ 501 int sig; 502 503 if ((sig = fpux_emu(xcp, ctx, ir))) 504 return sig; 505 break; 506 } 507 #endif 508 509 #if __mips >= 4 510 case spec_op: 511 if (MIPSInst_FUNC(ir) != movc_op) 512 return SIGILL; 513 cond = fpucondbit[MIPSInst_RT(ir) >> 2]; 514 if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0)) 515 xcp->regs[MIPSInst_RD(ir)] = 516 xcp->regs[MIPSInst_RS(ir)]; 517 break; 518 #endif 519 520 default: 521 return SIGILL; 522 } 523 524 /* we did it !! */ 525 xcp->cp0_epc = (unsigned long) contpc; 526 xcp->cp0_cause &= ~CAUSEF_BD; 527 528 return 0; 529 } 530 531 /* 532 * Conversion table from MIPS compare ops 48-63 533 * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig); 534 */ 535 static const unsigned char cmptab[8] = { 536 0, /* cmp_0 (sig) cmp_sf */ 537 IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ 538 IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ 539 IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ 540 IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ 541 IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ 542 IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ 543 IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ 544 }; 545 546 547 #if __mips >= 4 && __mips != 32 548 549 /* 550 * Additional MIPS4 instructions 551 */ 552 553 #define DEF3OP(name, p, f1, f2, f3) \ 554 static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \ 555 ieee754##p t) \ 556 { \ 557 struct _ieee754_csr ieee754_csr_save; \ 558 s = f1 (s, t); \ 559 ieee754_csr_save = ieee754_csr; \ 560 s = f2 (s, r); \ 561 ieee754_csr_save.cx |= ieee754_csr.cx; \ 562 ieee754_csr_save.sx |= ieee754_csr.sx; \ 563 s = f3 (s); \ 564 ieee754_csr.cx |= ieee754_csr_save.cx; \ 565 ieee754_csr.sx |= ieee754_csr_save.sx; \ 566 return s; \ 567 } 568 569 static ieee754dp fpemu_dp_recip(ieee754dp d) 570 { 571 return ieee754dp_div(ieee754dp_one(0), d); 572 } 573 574 static ieee754dp fpemu_dp_rsqrt(ieee754dp d) 575 { 576 return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); 577 } 578 579 static ieee754sp fpemu_sp_recip(ieee754sp s) 580 { 581 return ieee754sp_div(ieee754sp_one(0), s); 582 } 583 584 static ieee754sp fpemu_sp_rsqrt(ieee754sp s) 585 { 586 return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); 587 } 588 589 DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add,); 590 DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub,); 591 DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); 592 DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); 593 DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add,); 594 DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,); 595 DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); 596 DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); 597 598 static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 599 mips_instruction ir) 600 { 601 unsigned rcsr = 0; /* resulting csr */ 602 603 fpuemustats.cp1xops++; 604 605 switch (MIPSInst_FMA_FFMT(ir)) { 606 case s_fmt:{ /* 0 */ 607 608 ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp); 609 ieee754sp fd, fr, fs, ft; 610 u32 __user *va; 611 u32 val; 612 613 switch (MIPSInst_FUNC(ir)) { 614 case lwxc1_op: 615 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 616 xcp->regs[MIPSInst_FT(ir)]); 617 618 fpuemustats.loads++; 619 if (get_user(val, va)) { 620 fpuemustats.errors++; 621 return SIGBUS; 622 } 623 SITOREG(val, MIPSInst_FD(ir)); 624 break; 625 626 case swxc1_op: 627 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 628 xcp->regs[MIPSInst_FT(ir)]); 629 630 fpuemustats.stores++; 631 632 SIFROMREG(val, MIPSInst_FS(ir)); 633 if (put_user(val, va)) { 634 fpuemustats.errors++; 635 return SIGBUS; 636 } 637 break; 638 639 case madd_s_op: 640 handler = fpemu_sp_madd; 641 goto scoptop; 642 case msub_s_op: 643 handler = fpemu_sp_msub; 644 goto scoptop; 645 case nmadd_s_op: 646 handler = fpemu_sp_nmadd; 647 goto scoptop; 648 case nmsub_s_op: 649 handler = fpemu_sp_nmsub; 650 goto scoptop; 651 652 scoptop: 653 SPFROMREG(fr, MIPSInst_FR(ir)); 654 SPFROMREG(fs, MIPSInst_FS(ir)); 655 SPFROMREG(ft, MIPSInst_FT(ir)); 656 fd = (*handler) (fr, fs, ft); 657 SPTOREG(fd, MIPSInst_FD(ir)); 658 659 copcsr: 660 if (ieee754_cxtest(IEEE754_INEXACT)) 661 rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 662 if (ieee754_cxtest(IEEE754_UNDERFLOW)) 663 rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 664 if (ieee754_cxtest(IEEE754_OVERFLOW)) 665 rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 666 if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) 667 rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 668 669 ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 670 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 671 /*printk ("SIGFPE: fpu csr = %08x\n", 672 ctx->fcr31); */ 673 return SIGFPE; 674 } 675 676 break; 677 678 default: 679 return SIGILL; 680 } 681 break; 682 } 683 684 case d_fmt:{ /* 1 */ 685 ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp); 686 ieee754dp fd, fr, fs, ft; 687 u64 __user *va; 688 u64 val; 689 690 switch (MIPSInst_FUNC(ir)) { 691 case ldxc1_op: 692 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 693 xcp->regs[MIPSInst_FT(ir)]); 694 695 fpuemustats.loads++; 696 if (get_user(val, va)) { 697 fpuemustats.errors++; 698 return SIGBUS; 699 } 700 DITOREG(val, MIPSInst_FD(ir)); 701 break; 702 703 case sdxc1_op: 704 va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 705 xcp->regs[MIPSInst_FT(ir)]); 706 707 fpuemustats.stores++; 708 DIFROMREG(val, MIPSInst_FS(ir)); 709 if (put_user(val, va)) { 710 fpuemustats.errors++; 711 return SIGBUS; 712 } 713 break; 714 715 case madd_d_op: 716 handler = fpemu_dp_madd; 717 goto dcoptop; 718 case msub_d_op: 719 handler = fpemu_dp_msub; 720 goto dcoptop; 721 case nmadd_d_op: 722 handler = fpemu_dp_nmadd; 723 goto dcoptop; 724 case nmsub_d_op: 725 handler = fpemu_dp_nmsub; 726 goto dcoptop; 727 728 dcoptop: 729 DPFROMREG(fr, MIPSInst_FR(ir)); 730 DPFROMREG(fs, MIPSInst_FS(ir)); 731 DPFROMREG(ft, MIPSInst_FT(ir)); 732 fd = (*handler) (fr, fs, ft); 733 DPTOREG(fd, MIPSInst_FD(ir)); 734 goto copcsr; 735 736 default: 737 return SIGILL; 738 } 739 break; 740 } 741 742 case 0x7: /* 7 */ 743 if (MIPSInst_FUNC(ir) != pfetch_op) { 744 return SIGILL; 745 } 746 /* ignore prefx operation */ 747 break; 748 749 default: 750 return SIGILL; 751 } 752 753 return 0; 754 } 755 #endif 756 757 758 759 /* 760 * Emulate a single COP1 arithmetic instruction. 761 */ 762 static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 763 mips_instruction ir) 764 { 765 int rfmt; /* resulting format */ 766 unsigned rcsr = 0; /* resulting csr */ 767 unsigned cond; 768 union { 769 ieee754dp d; 770 ieee754sp s; 771 int w; 772 #ifdef __mips64 773 s64 l; 774 #endif 775 } rv; /* resulting value */ 776 777 fpuemustats.cp1ops++; 778 switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { 779 case s_fmt:{ /* 0 */ 780 union { 781 ieee754sp(*b) (ieee754sp, ieee754sp); 782 ieee754sp(*u) (ieee754sp); 783 } handler; 784 785 switch (MIPSInst_FUNC(ir)) { 786 /* binary ops */ 787 case fadd_op: 788 handler.b = ieee754sp_add; 789 goto scopbop; 790 case fsub_op: 791 handler.b = ieee754sp_sub; 792 goto scopbop; 793 case fmul_op: 794 handler.b = ieee754sp_mul; 795 goto scopbop; 796 case fdiv_op: 797 handler.b = ieee754sp_div; 798 goto scopbop; 799 800 /* unary ops */ 801 #if __mips >= 2 || defined(__mips64) 802 case fsqrt_op: 803 handler.u = ieee754sp_sqrt; 804 goto scopuop; 805 #endif 806 #if __mips >= 4 && __mips != 32 807 case frsqrt_op: 808 handler.u = fpemu_sp_rsqrt; 809 goto scopuop; 810 case frecip_op: 811 handler.u = fpemu_sp_recip; 812 goto scopuop; 813 #endif 814 #if __mips >= 4 815 case fmovc_op: 816 cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 817 if (((ctx->fcr31 & cond) != 0) != 818 ((MIPSInst_FT(ir) & 1) != 0)) 819 return 0; 820 SPFROMREG(rv.s, MIPSInst_FS(ir)); 821 break; 822 case fmovz_op: 823 if (xcp->regs[MIPSInst_FT(ir)] != 0) 824 return 0; 825 SPFROMREG(rv.s, MIPSInst_FS(ir)); 826 break; 827 case fmovn_op: 828 if (xcp->regs[MIPSInst_FT(ir)] == 0) 829 return 0; 830 SPFROMREG(rv.s, MIPSInst_FS(ir)); 831 break; 832 #endif 833 case fabs_op: 834 handler.u = ieee754sp_abs; 835 goto scopuop; 836 case fneg_op: 837 handler.u = ieee754sp_neg; 838 goto scopuop; 839 case fmov_op: 840 /* an easy one */ 841 SPFROMREG(rv.s, MIPSInst_FS(ir)); 842 goto copcsr; 843 844 /* binary op on handler */ 845 scopbop: 846 { 847 ieee754sp fs, ft; 848 849 SPFROMREG(fs, MIPSInst_FS(ir)); 850 SPFROMREG(ft, MIPSInst_FT(ir)); 851 852 rv.s = (*handler.b) (fs, ft); 853 goto copcsr; 854 } 855 scopuop: 856 { 857 ieee754sp fs; 858 859 SPFROMREG(fs, MIPSInst_FS(ir)); 860 rv.s = (*handler.u) (fs); 861 goto copcsr; 862 } 863 copcsr: 864 if (ieee754_cxtest(IEEE754_INEXACT)) 865 rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 866 if (ieee754_cxtest(IEEE754_UNDERFLOW)) 867 rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 868 if (ieee754_cxtest(IEEE754_OVERFLOW)) 869 rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 870 if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) 871 rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; 872 if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) 873 rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 874 break; 875 876 /* unary conv ops */ 877 case fcvts_op: 878 return SIGILL; /* not defined */ 879 case fcvtd_op:{ 880 ieee754sp fs; 881 882 SPFROMREG(fs, MIPSInst_FS(ir)); 883 rv.d = ieee754dp_fsp(fs); 884 rfmt = d_fmt; 885 goto copcsr; 886 } 887 case fcvtw_op:{ 888 ieee754sp fs; 889 890 SPFROMREG(fs, MIPSInst_FS(ir)); 891 rv.w = ieee754sp_tint(fs); 892 rfmt = w_fmt; 893 goto copcsr; 894 } 895 896 #if __mips >= 2 || defined(__mips64) 897 case fround_op: 898 case ftrunc_op: 899 case fceil_op: 900 case ffloor_op:{ 901 unsigned int oldrm = ieee754_csr.rm; 902 ieee754sp fs; 903 904 SPFROMREG(fs, MIPSInst_FS(ir)); 905 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; 906 rv.w = ieee754sp_tint(fs); 907 ieee754_csr.rm = oldrm; 908 rfmt = w_fmt; 909 goto copcsr; 910 } 911 #endif /* __mips >= 2 */ 912 913 #if defined(__mips64) 914 case fcvtl_op:{ 915 ieee754sp fs; 916 917 SPFROMREG(fs, MIPSInst_FS(ir)); 918 rv.l = ieee754sp_tlong(fs); 919 rfmt = l_fmt; 920 goto copcsr; 921 } 922 923 case froundl_op: 924 case ftruncl_op: 925 case fceill_op: 926 case ffloorl_op:{ 927 unsigned int oldrm = ieee754_csr.rm; 928 ieee754sp fs; 929 930 SPFROMREG(fs, MIPSInst_FS(ir)); 931 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; 932 rv.l = ieee754sp_tlong(fs); 933 ieee754_csr.rm = oldrm; 934 rfmt = l_fmt; 935 goto copcsr; 936 } 937 #endif /* defined(__mips64) */ 938 939 default: 940 if (MIPSInst_FUNC(ir) >= fcmp_op) { 941 unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 942 ieee754sp fs, ft; 943 944 SPFROMREG(fs, MIPSInst_FS(ir)); 945 SPFROMREG(ft, MIPSInst_FT(ir)); 946 rv.w = ieee754sp_cmp(fs, ft, 947 cmptab[cmpop & 0x7], cmpop & 0x8); 948 rfmt = -1; 949 if ((cmpop & 0x8) && ieee754_cxtest 950 (IEEE754_INVALID_OPERATION)) 951 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 952 else 953 goto copcsr; 954 955 } 956 else { 957 return SIGILL; 958 } 959 break; 960 } 961 break; 962 } 963 964 case d_fmt:{ 965 union { 966 ieee754dp(*b) (ieee754dp, ieee754dp); 967 ieee754dp(*u) (ieee754dp); 968 } handler; 969 970 switch (MIPSInst_FUNC(ir)) { 971 /* binary ops */ 972 case fadd_op: 973 handler.b = ieee754dp_add; 974 goto dcopbop; 975 case fsub_op: 976 handler.b = ieee754dp_sub; 977 goto dcopbop; 978 case fmul_op: 979 handler.b = ieee754dp_mul; 980 goto dcopbop; 981 case fdiv_op: 982 handler.b = ieee754dp_div; 983 goto dcopbop; 984 985 /* unary ops */ 986 #if __mips >= 2 || defined(__mips64) 987 case fsqrt_op: 988 handler.u = ieee754dp_sqrt; 989 goto dcopuop; 990 #endif 991 #if __mips >= 4 && __mips != 32 992 case frsqrt_op: 993 handler.u = fpemu_dp_rsqrt; 994 goto dcopuop; 995 case frecip_op: 996 handler.u = fpemu_dp_recip; 997 goto dcopuop; 998 #endif 999 #if __mips >= 4 1000 case fmovc_op: 1001 cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 1002 if (((ctx->fcr31 & cond) != 0) != 1003 ((MIPSInst_FT(ir) & 1) != 0)) 1004 return 0; 1005 DPFROMREG(rv.d, MIPSInst_FS(ir)); 1006 break; 1007 case fmovz_op: 1008 if (xcp->regs[MIPSInst_FT(ir)] != 0) 1009 return 0; 1010 DPFROMREG(rv.d, MIPSInst_FS(ir)); 1011 break; 1012 case fmovn_op: 1013 if (xcp->regs[MIPSInst_FT(ir)] == 0) 1014 return 0; 1015 DPFROMREG(rv.d, MIPSInst_FS(ir)); 1016 break; 1017 #endif 1018 case fabs_op: 1019 handler.u = ieee754dp_abs; 1020 goto dcopuop; 1021 1022 case fneg_op: 1023 handler.u = ieee754dp_neg; 1024 goto dcopuop; 1025 1026 case fmov_op: 1027 /* an easy one */ 1028 DPFROMREG(rv.d, MIPSInst_FS(ir)); 1029 goto copcsr; 1030 1031 /* binary op on handler */ 1032 dcopbop:{ 1033 ieee754dp fs, ft; 1034 1035 DPFROMREG(fs, MIPSInst_FS(ir)); 1036 DPFROMREG(ft, MIPSInst_FT(ir)); 1037 1038 rv.d = (*handler.b) (fs, ft); 1039 goto copcsr; 1040 } 1041 dcopuop:{ 1042 ieee754dp fs; 1043 1044 DPFROMREG(fs, MIPSInst_FS(ir)); 1045 rv.d = (*handler.u) (fs); 1046 goto copcsr; 1047 } 1048 1049 /* unary conv ops */ 1050 case fcvts_op:{ 1051 ieee754dp fs; 1052 1053 DPFROMREG(fs, MIPSInst_FS(ir)); 1054 rv.s = ieee754sp_fdp(fs); 1055 rfmt = s_fmt; 1056 goto copcsr; 1057 } 1058 case fcvtd_op: 1059 return SIGILL; /* not defined */ 1060 1061 case fcvtw_op:{ 1062 ieee754dp fs; 1063 1064 DPFROMREG(fs, MIPSInst_FS(ir)); 1065 rv.w = ieee754dp_tint(fs); /* wrong */ 1066 rfmt = w_fmt; 1067 goto copcsr; 1068 } 1069 1070 #if __mips >= 2 || defined(__mips64) 1071 case fround_op: 1072 case ftrunc_op: 1073 case fceil_op: 1074 case ffloor_op:{ 1075 unsigned int oldrm = ieee754_csr.rm; 1076 ieee754dp fs; 1077 1078 DPFROMREG(fs, MIPSInst_FS(ir)); 1079 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; 1080 rv.w = ieee754dp_tint(fs); 1081 ieee754_csr.rm = oldrm; 1082 rfmt = w_fmt; 1083 goto copcsr; 1084 } 1085 #endif 1086 1087 #if defined(__mips64) 1088 case fcvtl_op:{ 1089 ieee754dp fs; 1090 1091 DPFROMREG(fs, MIPSInst_FS(ir)); 1092 rv.l = ieee754dp_tlong(fs); 1093 rfmt = l_fmt; 1094 goto copcsr; 1095 } 1096 1097 case froundl_op: 1098 case ftruncl_op: 1099 case fceill_op: 1100 case ffloorl_op:{ 1101 unsigned int oldrm = ieee754_csr.rm; 1102 ieee754dp fs; 1103 1104 DPFROMREG(fs, MIPSInst_FS(ir)); 1105 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3]; 1106 rv.l = ieee754dp_tlong(fs); 1107 ieee754_csr.rm = oldrm; 1108 rfmt = l_fmt; 1109 goto copcsr; 1110 } 1111 #endif /* __mips >= 3 */ 1112 1113 default: 1114 if (MIPSInst_FUNC(ir) >= fcmp_op) { 1115 unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 1116 ieee754dp fs, ft; 1117 1118 DPFROMREG(fs, MIPSInst_FS(ir)); 1119 DPFROMREG(ft, MIPSInst_FT(ir)); 1120 rv.w = ieee754dp_cmp(fs, ft, 1121 cmptab[cmpop & 0x7], cmpop & 0x8); 1122 rfmt = -1; 1123 if ((cmpop & 0x8) 1124 && 1125 ieee754_cxtest 1126 (IEEE754_INVALID_OPERATION)) 1127 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 1128 else 1129 goto copcsr; 1130 1131 } 1132 else { 1133 return SIGILL; 1134 } 1135 break; 1136 } 1137 break; 1138 } 1139 1140 case w_fmt:{ 1141 ieee754sp fs; 1142 1143 switch (MIPSInst_FUNC(ir)) { 1144 case fcvts_op: 1145 /* convert word to single precision real */ 1146 SPFROMREG(fs, MIPSInst_FS(ir)); 1147 rv.s = ieee754sp_fint(fs.bits); 1148 rfmt = s_fmt; 1149 goto copcsr; 1150 case fcvtd_op: 1151 /* convert word to double precision real */ 1152 SPFROMREG(fs, MIPSInst_FS(ir)); 1153 rv.d = ieee754dp_fint(fs.bits); 1154 rfmt = d_fmt; 1155 goto copcsr; 1156 default: 1157 return SIGILL; 1158 } 1159 break; 1160 } 1161 1162 #if defined(__mips64) 1163 case l_fmt:{ 1164 switch (MIPSInst_FUNC(ir)) { 1165 case fcvts_op: 1166 /* convert long to single precision real */ 1167 rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]); 1168 rfmt = s_fmt; 1169 goto copcsr; 1170 case fcvtd_op: 1171 /* convert long to double precision real */ 1172 rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]); 1173 rfmt = d_fmt; 1174 goto copcsr; 1175 default: 1176 return SIGILL; 1177 } 1178 break; 1179 } 1180 #endif 1181 1182 default: 1183 return SIGILL; 1184 } 1185 1186 /* 1187 * Update the fpu CSR register for this operation. 1188 * If an exception is required, generate a tidy SIGFPE exception, 1189 * without updating the result register. 1190 * Note: cause exception bits do not accumulate, they are rewritten 1191 * for each op; only the flag/sticky bits accumulate. 1192 */ 1193 ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 1194 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 1195 /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ 1196 return SIGFPE; 1197 } 1198 1199 /* 1200 * Now we can safely write the result back to the register file. 1201 */ 1202 switch (rfmt) { 1203 case -1:{ 1204 #if __mips >= 4 1205 cond = fpucondbit[MIPSInst_FD(ir) >> 2]; 1206 #else 1207 cond = FPU_CSR_COND; 1208 #endif 1209 if (rv.w) 1210 ctx->fcr31 |= cond; 1211 else 1212 ctx->fcr31 &= ~cond; 1213 break; 1214 } 1215 case d_fmt: 1216 DPTOREG(rv.d, MIPSInst_FD(ir)); 1217 break; 1218 case s_fmt: 1219 SPTOREG(rv.s, MIPSInst_FD(ir)); 1220 break; 1221 case w_fmt: 1222 SITOREG(rv.w, MIPSInst_FD(ir)); 1223 break; 1224 #if defined(__mips64) 1225 case l_fmt: 1226 DITOREG(rv.l, MIPSInst_FD(ir)); 1227 break; 1228 #endif 1229 default: 1230 return SIGILL; 1231 } 1232 1233 return 0; 1234 } 1235 1236 int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx) 1237 { 1238 unsigned long oldepc, prevepc; 1239 mips_instruction insn; 1240 int sig = 0; 1241 1242 oldepc = xcp->cp0_epc; 1243 do { 1244 prevepc = xcp->cp0_epc; 1245 1246 if (get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) { 1247 fpuemustats.errors++; 1248 return SIGBUS; 1249 } 1250 if (insn == 0) 1251 xcp->cp0_epc += 4; /* skip nops */ 1252 else { 1253 /* 1254 * The 'ieee754_csr' is an alias of 1255 * ctx->fcr31. No need to copy ctx->fcr31 to 1256 * ieee754_csr. But ieee754_csr.rm is ieee 1257 * library modes. (not mips rounding mode) 1258 */ 1259 /* convert to ieee library modes */ 1260 ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; 1261 sig = cop1Emulate(xcp, ctx); 1262 /* revert to mips rounding mode */ 1263 ieee754_csr.rm = mips_rm[ieee754_csr.rm]; 1264 } 1265 1266 if (cpu_has_fpu) 1267 break; 1268 if (sig) 1269 break; 1270 1271 cond_resched(); 1272 } while (xcp->cp0_epc > prevepc); 1273 1274 /* SIGILL indicates a non-fpu instruction */ 1275 if (sig == SIGILL && xcp->cp0_epc != oldepc) 1276 /* but if epc has advanced, then ignore it */ 1277 sig = 0; 1278 1279 return sig; 1280 } 1281