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