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