11da177e4SLinus Torvalds /* 23f7cac41SRalf Baechle * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * MIPS floating point support 51da177e4SLinus Torvalds * Copyright (C) 1994-2000 Algorithmics Ltd. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com 81da177e4SLinus Torvalds * Copyright (C) 2000 MIPS Technologies, Inc. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * This program is free software; you can distribute it and/or modify it 111da177e4SLinus Torvalds * under the terms of the GNU General Public License (Version 2) as 121da177e4SLinus Torvalds * published by the Free Software Foundation. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * This program is distributed in the hope it will be useful, but WITHOUT 151da177e4SLinus Torvalds * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 161da177e4SLinus Torvalds * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 171da177e4SLinus Torvalds * for more details. 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License along 201da177e4SLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 213f7cac41SRalf Baechle * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * A complete emulator for MIPS coprocessor 1 instructions. This is 241da177e4SLinus Torvalds * required for #float(switch) or #float(trap), where it catches all 251da177e4SLinus Torvalds * COP1 instructions via the "CoProcessor Unusable" exception. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * More surprisingly it is also required for #float(ieee), to help out 283f7cac41SRalf Baechle * the hardware FPU at the boundaries of the IEEE-754 representation 291da177e4SLinus Torvalds * (denormalised values, infinities, underflow, etc). It is made 301da177e4SLinus Torvalds * quite nasty because emulation of some non-COP1 instructions is 311da177e4SLinus Torvalds * required, e.g. in branch delay slots. 321da177e4SLinus Torvalds * 333f7cac41SRalf Baechle * Note if you know that you won't have an FPU, then you'll get much 341da177e4SLinus Torvalds * better performance by compiling with -msoft-float! 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds #include <linux/sched.h> 3783fd38caSAtsushi Nemoto #include <linux/debugfs.h> 3808a07904SRalf Baechle #include <linux/kconfig.h> 3985c51c51SRalf Baechle #include <linux/percpu-defs.h> 407f788d2dSDeng-Cheng Zhu #include <linux/perf_event.h> 411da177e4SLinus Torvalds 42cd8ee345SRalf Baechle #include <asm/branch.h> 431da177e4SLinus Torvalds #include <asm/inst.h> 441da177e4SLinus Torvalds #include <asm/ptrace.h> 451da177e4SLinus Torvalds #include <asm/signal.h> 46cd8ee345SRalf Baechle #include <asm/uaccess.h> 47cd8ee345SRalf Baechle 48f6843626SMaciej W. Rozycki #include <asm/cpu-info.h> 49cd8ee345SRalf Baechle #include <asm/processor.h> 501da177e4SLinus Torvalds #include <asm/fpu_emulator.h> 51102cedc3SLeonid Yegoshin #include <asm/fpu.h> 52b0a668fbSLeonid Yegoshin #include <asm/mips-r2-to-r6-emul.h> 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds #include "ieee754.h" 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* Function which emulates a floating point instruction. */ 571da177e4SLinus Torvalds 58eae89076SAtsushi Nemoto static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, 591da177e4SLinus Torvalds mips_instruction); 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static int fpux_emu(struct pt_regs *, 62515b029dSDavid Daney struct mips_fpu_struct *, mips_instruction, void *__user *); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* Control registers */ 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds #define FPCREG_RID 0 /* $0 = revision id */ 67c491cfa2SMaciej W. Rozycki #define FPCREG_FCCR 25 /* $25 = fccr */ 68c491cfa2SMaciej W. Rozycki #define FPCREG_FEXR 26 /* $26 = fexr */ 69c491cfa2SMaciej W. Rozycki #define FPCREG_FENR 28 /* $28 = fenr */ 701da177e4SLinus Torvalds #define FPCREG_CSR 31 /* $31 = csr */ 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* convert condition code register number to csr bit */ 73b0a668fbSLeonid Yegoshin const unsigned int fpucondbit[8] = { 74c491cfa2SMaciej W. Rozycki FPU_CSR_COND, 751da177e4SLinus Torvalds FPU_CSR_COND1, 761da177e4SLinus Torvalds FPU_CSR_COND2, 771da177e4SLinus Torvalds FPU_CSR_COND3, 781da177e4SLinus Torvalds FPU_CSR_COND4, 791da177e4SLinus Torvalds FPU_CSR_COND5, 801da177e4SLinus Torvalds FPU_CSR_COND6, 811da177e4SLinus Torvalds FPU_CSR_COND7 821da177e4SLinus Torvalds }; 831da177e4SLinus Torvalds 84102cedc3SLeonid Yegoshin /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ 85102cedc3SLeonid Yegoshin static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; 86102cedc3SLeonid Yegoshin static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; 87102cedc3SLeonid Yegoshin static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0}; 88102cedc3SLeonid Yegoshin static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0}; 89102cedc3SLeonid Yegoshin 90102cedc3SLeonid Yegoshin /* 91102cedc3SLeonid Yegoshin * This functions translates a 32-bit microMIPS instruction 92102cedc3SLeonid Yegoshin * into a 32-bit MIPS32 instruction. Returns 0 on success 93102cedc3SLeonid Yegoshin * and SIGILL otherwise. 94102cedc3SLeonid Yegoshin */ 95102cedc3SLeonid Yegoshin static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) 96102cedc3SLeonid Yegoshin { 97102cedc3SLeonid Yegoshin union mips_instruction insn = *insn_ptr; 98102cedc3SLeonid Yegoshin union mips_instruction mips32_insn = insn; 99102cedc3SLeonid Yegoshin int func, fmt, op; 100102cedc3SLeonid Yegoshin 101102cedc3SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 102102cedc3SLeonid Yegoshin case mm_ldc132_op: 103102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = ldc1_op; 104102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 105102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 106102cedc3SLeonid Yegoshin break; 107102cedc3SLeonid Yegoshin case mm_lwc132_op: 108102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = lwc1_op; 109102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 110102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 111102cedc3SLeonid Yegoshin break; 112102cedc3SLeonid Yegoshin case mm_sdc132_op: 113102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = sdc1_op; 114102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 115102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 116102cedc3SLeonid Yegoshin break; 117102cedc3SLeonid Yegoshin case mm_swc132_op: 118102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = swc1_op; 119102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 120102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 121102cedc3SLeonid Yegoshin break; 122102cedc3SLeonid Yegoshin case mm_pool32i_op: 123102cedc3SLeonid Yegoshin /* NOTE: offset is << by 1 if in microMIPS mode. */ 124102cedc3SLeonid Yegoshin if ((insn.mm_i_format.rt == mm_bc1f_op) || 125102cedc3SLeonid Yegoshin (insn.mm_i_format.rt == mm_bc1t_op)) { 126102cedc3SLeonid Yegoshin mips32_insn.fb_format.opcode = cop1_op; 127102cedc3SLeonid Yegoshin mips32_insn.fb_format.bc = bc_op; 128102cedc3SLeonid Yegoshin mips32_insn.fb_format.flag = 129102cedc3SLeonid Yegoshin (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0; 130102cedc3SLeonid Yegoshin } else 131102cedc3SLeonid Yegoshin return SIGILL; 132102cedc3SLeonid Yegoshin break; 133102cedc3SLeonid Yegoshin case mm_pool32f_op: 134102cedc3SLeonid Yegoshin switch (insn.mm_fp0_format.func) { 135102cedc3SLeonid Yegoshin case mm_32f_01_op: 136102cedc3SLeonid Yegoshin case mm_32f_11_op: 137102cedc3SLeonid Yegoshin case mm_32f_02_op: 138102cedc3SLeonid Yegoshin case mm_32f_12_op: 139102cedc3SLeonid Yegoshin case mm_32f_41_op: 140102cedc3SLeonid Yegoshin case mm_32f_51_op: 141102cedc3SLeonid Yegoshin case mm_32f_42_op: 142102cedc3SLeonid Yegoshin case mm_32f_52_op: 143102cedc3SLeonid Yegoshin op = insn.mm_fp0_format.func; 144102cedc3SLeonid Yegoshin if (op == mm_32f_01_op) 145102cedc3SLeonid Yegoshin func = madd_s_op; 146102cedc3SLeonid Yegoshin else if (op == mm_32f_11_op) 147102cedc3SLeonid Yegoshin func = madd_d_op; 148102cedc3SLeonid Yegoshin else if (op == mm_32f_02_op) 149102cedc3SLeonid Yegoshin func = nmadd_s_op; 150102cedc3SLeonid Yegoshin else if (op == mm_32f_12_op) 151102cedc3SLeonid Yegoshin func = nmadd_d_op; 152102cedc3SLeonid Yegoshin else if (op == mm_32f_41_op) 153102cedc3SLeonid Yegoshin func = msub_s_op; 154102cedc3SLeonid Yegoshin else if (op == mm_32f_51_op) 155102cedc3SLeonid Yegoshin func = msub_d_op; 156102cedc3SLeonid Yegoshin else if (op == mm_32f_42_op) 157102cedc3SLeonid Yegoshin func = nmsub_s_op; 158102cedc3SLeonid Yegoshin else 159102cedc3SLeonid Yegoshin func = nmsub_d_op; 160102cedc3SLeonid Yegoshin mips32_insn.fp6_format.opcode = cop1x_op; 161102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr; 162102cedc3SLeonid Yegoshin mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft; 163102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs; 164102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd; 165102cedc3SLeonid Yegoshin mips32_insn.fp6_format.func = func; 166102cedc3SLeonid Yegoshin break; 167102cedc3SLeonid Yegoshin case mm_32f_10_op: 168102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 169102cedc3SLeonid Yegoshin op = insn.mm_fp5_format.op & 0x7; 170102cedc3SLeonid Yegoshin if (op == mm_ldxc1_op) 171102cedc3SLeonid Yegoshin func = ldxc1_op; 172102cedc3SLeonid Yegoshin else if (op == mm_sdxc1_op) 173102cedc3SLeonid Yegoshin func = sdxc1_op; 174102cedc3SLeonid Yegoshin else if (op == mm_lwxc1_op) 175102cedc3SLeonid Yegoshin func = lwxc1_op; 176102cedc3SLeonid Yegoshin else if (op == mm_swxc1_op) 177102cedc3SLeonid Yegoshin func = swxc1_op; 178102cedc3SLeonid Yegoshin 179102cedc3SLeonid Yegoshin if (func != -1) { 180102cedc3SLeonid Yegoshin mips32_insn.r_format.opcode = cop1x_op; 181102cedc3SLeonid Yegoshin mips32_insn.r_format.rs = 182102cedc3SLeonid Yegoshin insn.mm_fp5_format.base; 183102cedc3SLeonid Yegoshin mips32_insn.r_format.rt = 184102cedc3SLeonid Yegoshin insn.mm_fp5_format.index; 185102cedc3SLeonid Yegoshin mips32_insn.r_format.rd = 0; 186102cedc3SLeonid Yegoshin mips32_insn.r_format.re = insn.mm_fp5_format.fd; 187102cedc3SLeonid Yegoshin mips32_insn.r_format.func = func; 188102cedc3SLeonid Yegoshin } else 189102cedc3SLeonid Yegoshin return SIGILL; 190102cedc3SLeonid Yegoshin break; 191102cedc3SLeonid Yegoshin case mm_32f_40_op: 192102cedc3SLeonid Yegoshin op = -1; /* Invalid */ 193102cedc3SLeonid Yegoshin if (insn.mm_fp2_format.op == mm_fmovt_op) 194102cedc3SLeonid Yegoshin op = 1; 195102cedc3SLeonid Yegoshin else if (insn.mm_fp2_format.op == mm_fmovf_op) 196102cedc3SLeonid Yegoshin op = 0; 197102cedc3SLeonid Yegoshin if (op != -1) { 198102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 199102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 200102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp2_format.fmt]; 201102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 202102cedc3SLeonid Yegoshin (insn.mm_fp2_format.cc<<2) + op; 203102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 204102cedc3SLeonid Yegoshin insn.mm_fp2_format.fs; 205102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 206102cedc3SLeonid Yegoshin insn.mm_fp2_format.fd; 207102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = fmovc_op; 208102cedc3SLeonid Yegoshin } else 209102cedc3SLeonid Yegoshin return SIGILL; 210102cedc3SLeonid Yegoshin break; 211102cedc3SLeonid Yegoshin case mm_32f_60_op: 212102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 213102cedc3SLeonid Yegoshin if (insn.mm_fp0_format.op == mm_fadd_op) 214102cedc3SLeonid Yegoshin func = fadd_op; 215102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fsub_op) 216102cedc3SLeonid Yegoshin func = fsub_op; 217102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fmul_op) 218102cedc3SLeonid Yegoshin func = fmul_op; 219102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fdiv_op) 220102cedc3SLeonid Yegoshin func = fdiv_op; 221102cedc3SLeonid Yegoshin if (func != -1) { 222102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 223102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 224102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp0_format.fmt]; 225102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 226102cedc3SLeonid Yegoshin insn.mm_fp0_format.ft; 227102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 228102cedc3SLeonid Yegoshin insn.mm_fp0_format.fs; 229102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 230102cedc3SLeonid Yegoshin insn.mm_fp0_format.fd; 231102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 232102cedc3SLeonid Yegoshin } else 233102cedc3SLeonid Yegoshin return SIGILL; 234102cedc3SLeonid Yegoshin break; 235102cedc3SLeonid Yegoshin case mm_32f_70_op: 236102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 237102cedc3SLeonid Yegoshin if (insn.mm_fp0_format.op == mm_fmovn_op) 238102cedc3SLeonid Yegoshin func = fmovn_op; 239102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fmovz_op) 240102cedc3SLeonid Yegoshin func = fmovz_op; 241102cedc3SLeonid Yegoshin if (func != -1) { 242102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 243102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 244102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp0_format.fmt]; 245102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 246102cedc3SLeonid Yegoshin insn.mm_fp0_format.ft; 247102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 248102cedc3SLeonid Yegoshin insn.mm_fp0_format.fs; 249102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 250102cedc3SLeonid Yegoshin insn.mm_fp0_format.fd; 251102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 252102cedc3SLeonid Yegoshin } else 253102cedc3SLeonid Yegoshin return SIGILL; 254102cedc3SLeonid Yegoshin break; 255102cedc3SLeonid Yegoshin case mm_32f_73_op: /* POOL32FXF */ 256102cedc3SLeonid Yegoshin switch (insn.mm_fp1_format.op) { 257102cedc3SLeonid Yegoshin case mm_movf0_op: 258102cedc3SLeonid Yegoshin case mm_movf1_op: 259102cedc3SLeonid Yegoshin case mm_movt0_op: 260102cedc3SLeonid Yegoshin case mm_movt1_op: 261102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 262102cedc3SLeonid Yegoshin mm_movf0_op) 263102cedc3SLeonid Yegoshin op = 0; 264102cedc3SLeonid Yegoshin else 265102cedc3SLeonid Yegoshin op = 1; 266102cedc3SLeonid Yegoshin mips32_insn.r_format.opcode = spec_op; 267102cedc3SLeonid Yegoshin mips32_insn.r_format.rs = insn.mm_fp4_format.fs; 268102cedc3SLeonid Yegoshin mips32_insn.r_format.rt = 269102cedc3SLeonid Yegoshin (insn.mm_fp4_format.cc << 2) + op; 270102cedc3SLeonid Yegoshin mips32_insn.r_format.rd = insn.mm_fp4_format.rt; 271102cedc3SLeonid Yegoshin mips32_insn.r_format.re = 0; 272102cedc3SLeonid Yegoshin mips32_insn.r_format.func = movc_op; 273102cedc3SLeonid Yegoshin break; 274102cedc3SLeonid Yegoshin case mm_fcvtd0_op: 275102cedc3SLeonid Yegoshin case mm_fcvtd1_op: 276102cedc3SLeonid Yegoshin case mm_fcvts0_op: 277102cedc3SLeonid Yegoshin case mm_fcvts1_op: 278102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 279102cedc3SLeonid Yegoshin mm_fcvtd0_op) { 280102cedc3SLeonid Yegoshin func = fcvtd_op; 281102cedc3SLeonid Yegoshin fmt = swl_format[insn.mm_fp3_format.fmt]; 282102cedc3SLeonid Yegoshin } else { 283102cedc3SLeonid Yegoshin func = fcvts_op; 284102cedc3SLeonid Yegoshin fmt = dwl_format[insn.mm_fp3_format.fmt]; 285102cedc3SLeonid Yegoshin } 286102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 287102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = fmt; 288102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 289102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 290102cedc3SLeonid Yegoshin insn.mm_fp3_format.fs; 291102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 292102cedc3SLeonid Yegoshin insn.mm_fp3_format.rt; 293102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 294102cedc3SLeonid Yegoshin break; 295102cedc3SLeonid Yegoshin case mm_fmov0_op: 296102cedc3SLeonid Yegoshin case mm_fmov1_op: 297102cedc3SLeonid Yegoshin case mm_fabs0_op: 298102cedc3SLeonid Yegoshin case mm_fabs1_op: 299102cedc3SLeonid Yegoshin case mm_fneg0_op: 300102cedc3SLeonid Yegoshin case mm_fneg1_op: 301102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 302102cedc3SLeonid Yegoshin mm_fmov0_op) 303102cedc3SLeonid Yegoshin func = fmov_op; 304102cedc3SLeonid Yegoshin else if ((insn.mm_fp1_format.op & 0x7f) == 305102cedc3SLeonid Yegoshin mm_fabs0_op) 306102cedc3SLeonid Yegoshin func = fabs_op; 307102cedc3SLeonid Yegoshin else 308102cedc3SLeonid Yegoshin func = fneg_op; 309102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 310102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 311102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp3_format.fmt]; 312102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 313102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 314102cedc3SLeonid Yegoshin insn.mm_fp3_format.fs; 315102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 316102cedc3SLeonid Yegoshin insn.mm_fp3_format.rt; 317102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 318102cedc3SLeonid Yegoshin break; 319102cedc3SLeonid Yegoshin case mm_ffloorl_op: 320102cedc3SLeonid Yegoshin case mm_ffloorw_op: 321102cedc3SLeonid Yegoshin case mm_fceill_op: 322102cedc3SLeonid Yegoshin case mm_fceilw_op: 323102cedc3SLeonid Yegoshin case mm_ftruncl_op: 324102cedc3SLeonid Yegoshin case mm_ftruncw_op: 325102cedc3SLeonid Yegoshin case mm_froundl_op: 326102cedc3SLeonid Yegoshin case mm_froundw_op: 327102cedc3SLeonid Yegoshin case mm_fcvtl_op: 328102cedc3SLeonid Yegoshin case mm_fcvtw_op: 329102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_ffloorl_op) 330102cedc3SLeonid Yegoshin func = ffloorl_op; 331102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ffloorw_op) 332102cedc3SLeonid Yegoshin func = ffloor_op; 333102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fceill_op) 334102cedc3SLeonid Yegoshin func = fceill_op; 335102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fceilw_op) 336102cedc3SLeonid Yegoshin func = fceil_op; 337102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ftruncl_op) 338102cedc3SLeonid Yegoshin func = ftruncl_op; 339102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ftruncw_op) 340102cedc3SLeonid Yegoshin func = ftrunc_op; 341102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_froundl_op) 342102cedc3SLeonid Yegoshin func = froundl_op; 343102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_froundw_op) 344102cedc3SLeonid Yegoshin func = fround_op; 345102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fcvtl_op) 346102cedc3SLeonid Yegoshin func = fcvtl_op; 347102cedc3SLeonid Yegoshin else 348102cedc3SLeonid Yegoshin func = fcvtw_op; 349102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 350102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 351102cedc3SLeonid Yegoshin sd_format[insn.mm_fp1_format.fmt]; 352102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 353102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 354102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 355102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 356102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 357102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 358102cedc3SLeonid Yegoshin break; 359102cedc3SLeonid Yegoshin case mm_frsqrt_op: 360102cedc3SLeonid Yegoshin case mm_fsqrt_op: 361102cedc3SLeonid Yegoshin case mm_frecip_op: 362102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_frsqrt_op) 363102cedc3SLeonid Yegoshin func = frsqrt_op; 364102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fsqrt_op) 365102cedc3SLeonid Yegoshin func = fsqrt_op; 366102cedc3SLeonid Yegoshin else 367102cedc3SLeonid Yegoshin func = frecip_op; 368102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 369102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 370102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp1_format.fmt]; 371102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 372102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 373102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 374102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 375102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 376102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 377102cedc3SLeonid Yegoshin break; 378102cedc3SLeonid Yegoshin case mm_mfc1_op: 379102cedc3SLeonid Yegoshin case mm_mtc1_op: 380102cedc3SLeonid Yegoshin case mm_cfc1_op: 381102cedc3SLeonid Yegoshin case mm_ctc1_op: 3829355e59cSSteven J. Hill case mm_mfhc1_op: 3839355e59cSSteven J. Hill case mm_mthc1_op: 384102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_mfc1_op) 385102cedc3SLeonid Yegoshin op = mfc_op; 386102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_mtc1_op) 387102cedc3SLeonid Yegoshin op = mtc_op; 388102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_cfc1_op) 389102cedc3SLeonid Yegoshin op = cfc_op; 3909355e59cSSteven J. Hill else if (insn.mm_fp1_format.op == mm_ctc1_op) 391102cedc3SLeonid Yegoshin op = ctc_op; 3929355e59cSSteven J. Hill else if (insn.mm_fp1_format.op == mm_mfhc1_op) 3939355e59cSSteven J. Hill op = mfhc_op; 3949355e59cSSteven J. Hill else 3959355e59cSSteven J. Hill op = mthc_op; 396102cedc3SLeonid Yegoshin mips32_insn.fp1_format.opcode = cop1_op; 397102cedc3SLeonid Yegoshin mips32_insn.fp1_format.op = op; 398102cedc3SLeonid Yegoshin mips32_insn.fp1_format.rt = 399102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 400102cedc3SLeonid Yegoshin mips32_insn.fp1_format.fs = 401102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 402102cedc3SLeonid Yegoshin mips32_insn.fp1_format.fd = 0; 403102cedc3SLeonid Yegoshin mips32_insn.fp1_format.func = 0; 404102cedc3SLeonid Yegoshin break; 405102cedc3SLeonid Yegoshin default: 406102cedc3SLeonid Yegoshin return SIGILL; 407102cedc3SLeonid Yegoshin } 408102cedc3SLeonid Yegoshin break; 409102cedc3SLeonid Yegoshin case mm_32f_74_op: /* c.cond.fmt */ 410102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 411102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 412102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp4_format.fmt]; 413102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt; 414102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs; 415102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2; 416102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = 417102cedc3SLeonid Yegoshin insn.mm_fp4_format.cond | MM_MIPS32_COND_FC; 418102cedc3SLeonid Yegoshin break; 419102cedc3SLeonid Yegoshin default: 420102cedc3SLeonid Yegoshin return SIGILL; 421102cedc3SLeonid Yegoshin } 422102cedc3SLeonid Yegoshin break; 423102cedc3SLeonid Yegoshin default: 424102cedc3SLeonid Yegoshin return SIGILL; 425102cedc3SLeonid Yegoshin } 426102cedc3SLeonid Yegoshin 427102cedc3SLeonid Yegoshin *insn_ptr = mips32_insn; 428102cedc3SLeonid Yegoshin return 0; 429102cedc3SLeonid Yegoshin } 430102cedc3SLeonid Yegoshin 4311da177e4SLinus Torvalds /* 4321da177e4SLinus Torvalds * Redundant with logic already in kernel/branch.c, 4331da177e4SLinus Torvalds * embedded in compute_return_epc. At some point, 4341da177e4SLinus Torvalds * a single subroutine should be used across both 4351da177e4SLinus Torvalds * modules. 4361da177e4SLinus Torvalds */ 437102cedc3SLeonid Yegoshin static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, 438102cedc3SLeonid Yegoshin unsigned long *contpc) 4391da177e4SLinus Torvalds { 440102cedc3SLeonid Yegoshin union mips_instruction insn = (union mips_instruction)dec_insn.insn; 441102cedc3SLeonid Yegoshin unsigned int fcr31; 442102cedc3SLeonid Yegoshin unsigned int bit = 0; 443102cedc3SLeonid Yegoshin 444102cedc3SLeonid Yegoshin switch (insn.i_format.opcode) { 4451da177e4SLinus Torvalds case spec_op: 446102cedc3SLeonid Yegoshin switch (insn.r_format.func) { 4471da177e4SLinus Torvalds case jalr_op: 448102cedc3SLeonid Yegoshin regs->regs[insn.r_format.rd] = 449102cedc3SLeonid Yegoshin regs->cp0_epc + dec_insn.pc_inc + 450102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 451102cedc3SLeonid Yegoshin /* Fall through */ 4521da177e4SLinus Torvalds case jr_op: 4535f9f41c4SMarkos Chandras /* For R6, JR already emulated in jalr_op */ 454143fefc8SMarkos Chandras if (NO_R6EMU && insn.r_format.func == jr_op) 4555f9f41c4SMarkos Chandras break; 456102cedc3SLeonid Yegoshin *contpc = regs->regs[insn.r_format.rs]; 4571da177e4SLinus Torvalds return 1; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds break; 4601da177e4SLinus Torvalds case bcond_op: 461102cedc3SLeonid Yegoshin switch (insn.i_format.rt) { 4621da177e4SLinus Torvalds case bltzal_op: 4631da177e4SLinus Torvalds case bltzall_op: 464319824eaSMarkos Chandras if (NO_R6EMU && (insn.i_format.rs || 465319824eaSMarkos Chandras insn.i_format.rt == bltzall_op)) 466319824eaSMarkos Chandras break; 467319824eaSMarkos Chandras 468102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 469102cedc3SLeonid Yegoshin dec_insn.pc_inc + 470102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 471102cedc3SLeonid Yegoshin /* Fall through */ 472102cedc3SLeonid Yegoshin case bltzl_op: 473319824eaSMarkos Chandras if (NO_R6EMU) 474319824eaSMarkos Chandras break; 475319824eaSMarkos Chandras case bltz_op: 476102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] < 0) 477102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 478102cedc3SLeonid Yegoshin dec_insn.pc_inc + 479102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 480102cedc3SLeonid Yegoshin else 481102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 482102cedc3SLeonid Yegoshin dec_insn.pc_inc + 483102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 4841da177e4SLinus Torvalds return 1; 485102cedc3SLeonid Yegoshin case bgezal_op: 486102cedc3SLeonid Yegoshin case bgezall_op: 487319824eaSMarkos Chandras if (NO_R6EMU && (insn.i_format.rs || 488319824eaSMarkos Chandras insn.i_format.rt == bgezall_op)) 489319824eaSMarkos Chandras break; 490319824eaSMarkos Chandras 491102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 492102cedc3SLeonid Yegoshin dec_insn.pc_inc + 493102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 494102cedc3SLeonid Yegoshin /* Fall through */ 495102cedc3SLeonid Yegoshin case bgezl_op: 496319824eaSMarkos Chandras if (NO_R6EMU) 497319824eaSMarkos Chandras break; 498319824eaSMarkos Chandras case bgez_op: 499102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] >= 0) 500102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 501102cedc3SLeonid Yegoshin dec_insn.pc_inc + 502102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 503102cedc3SLeonid Yegoshin else 504102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 505102cedc3SLeonid Yegoshin dec_insn.pc_inc + 506102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 507102cedc3SLeonid Yegoshin return 1; 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds break; 5101da177e4SLinus Torvalds case jalx_op: 511102cedc3SLeonid Yegoshin set_isa16_mode(bit); 512102cedc3SLeonid Yegoshin case jal_op: 513102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 514102cedc3SLeonid Yegoshin dec_insn.pc_inc + 515102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 516102cedc3SLeonid Yegoshin /* Fall through */ 517102cedc3SLeonid Yegoshin case j_op: 518102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + dec_insn.pc_inc; 519102cedc3SLeonid Yegoshin *contpc >>= 28; 520102cedc3SLeonid Yegoshin *contpc <<= 28; 521102cedc3SLeonid Yegoshin *contpc |= (insn.j_format.target << 2); 522102cedc3SLeonid Yegoshin /* Set microMIPS mode bit: XOR for jalx. */ 523102cedc3SLeonid Yegoshin *contpc ^= bit; 5241da177e4SLinus Torvalds return 1; 525102cedc3SLeonid Yegoshin case beql_op: 526319824eaSMarkos Chandras if (NO_R6EMU) 527319824eaSMarkos Chandras break; 528319824eaSMarkos Chandras case beq_op: 529102cedc3SLeonid Yegoshin if (regs->regs[insn.i_format.rs] == 530102cedc3SLeonid Yegoshin regs->regs[insn.i_format.rt]) 531102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 532102cedc3SLeonid Yegoshin dec_insn.pc_inc + 533102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 534102cedc3SLeonid Yegoshin else 535102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 536102cedc3SLeonid Yegoshin dec_insn.pc_inc + 537102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 538102cedc3SLeonid Yegoshin return 1; 539102cedc3SLeonid Yegoshin case bnel_op: 540319824eaSMarkos Chandras if (NO_R6EMU) 541319824eaSMarkos Chandras break; 542319824eaSMarkos Chandras case bne_op: 543102cedc3SLeonid Yegoshin if (regs->regs[insn.i_format.rs] != 544102cedc3SLeonid Yegoshin regs->regs[insn.i_format.rt]) 545102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 546102cedc3SLeonid Yegoshin dec_insn.pc_inc + 547102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 548102cedc3SLeonid Yegoshin else 549102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 550102cedc3SLeonid Yegoshin dec_insn.pc_inc + 551102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 552102cedc3SLeonid Yegoshin return 1; 553102cedc3SLeonid Yegoshin case blezl_op: 554e9d92d22SMarkos Chandras if (!insn.i_format.rt && NO_R6EMU) 555319824eaSMarkos Chandras break; 556319824eaSMarkos Chandras case blez_op: 557a8ff66f5SMarkos Chandras 558a8ff66f5SMarkos Chandras /* 559a8ff66f5SMarkos Chandras * Compact branches for R6 for the 560a8ff66f5SMarkos Chandras * blez and blezl opcodes. 561a8ff66f5SMarkos Chandras * BLEZ | rs = 0 | rt != 0 == BLEZALC 562a8ff66f5SMarkos Chandras * BLEZ | rs = rt != 0 == BGEZALC 563a8ff66f5SMarkos Chandras * BLEZ | rs != 0 | rt != 0 == BGEUC 564a8ff66f5SMarkos Chandras * BLEZL | rs = 0 | rt != 0 == BLEZC 565a8ff66f5SMarkos Chandras * BLEZL | rs = rt != 0 == BGEZC 566a8ff66f5SMarkos Chandras * BLEZL | rs != 0 | rt != 0 == BGEC 567a8ff66f5SMarkos Chandras * 568a8ff66f5SMarkos Chandras * For real BLEZ{,L}, rt is always 0. 569a8ff66f5SMarkos Chandras */ 570a8ff66f5SMarkos Chandras if (cpu_has_mips_r6 && insn.i_format.rt) { 571a8ff66f5SMarkos Chandras if ((insn.i_format.opcode == blez_op) && 572a8ff66f5SMarkos Chandras ((!insn.i_format.rs && insn.i_format.rt) || 573a8ff66f5SMarkos Chandras (insn.i_format.rs == insn.i_format.rt))) 574a8ff66f5SMarkos Chandras regs->regs[31] = regs->cp0_epc + 575a8ff66f5SMarkos Chandras dec_insn.pc_inc; 576a8ff66f5SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 577a8ff66f5SMarkos Chandras dec_insn.next_pc_inc; 578a8ff66f5SMarkos Chandras 579a8ff66f5SMarkos Chandras return 1; 580a8ff66f5SMarkos Chandras } 581102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] <= 0) 582102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 583102cedc3SLeonid Yegoshin dec_insn.pc_inc + 584102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 585102cedc3SLeonid Yegoshin else 586102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 587102cedc3SLeonid Yegoshin dec_insn.pc_inc + 588102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 589102cedc3SLeonid Yegoshin return 1; 590102cedc3SLeonid Yegoshin case bgtzl_op: 591e9d92d22SMarkos Chandras if (!insn.i_format.rt && NO_R6EMU) 592319824eaSMarkos Chandras break; 593319824eaSMarkos Chandras case bgtz_op: 594f1b44067SMarkos Chandras /* 595f1b44067SMarkos Chandras * Compact branches for R6 for the 596f1b44067SMarkos Chandras * bgtz and bgtzl opcodes. 597f1b44067SMarkos Chandras * BGTZ | rs = 0 | rt != 0 == BGTZALC 598f1b44067SMarkos Chandras * BGTZ | rs = rt != 0 == BLTZALC 599f1b44067SMarkos Chandras * BGTZ | rs != 0 | rt != 0 == BLTUC 600f1b44067SMarkos Chandras * BGTZL | rs = 0 | rt != 0 == BGTZC 601f1b44067SMarkos Chandras * BGTZL | rs = rt != 0 == BLTZC 602f1b44067SMarkos Chandras * BGTZL | rs != 0 | rt != 0 == BLTC 603f1b44067SMarkos Chandras * 604f1b44067SMarkos Chandras * *ZALC varint for BGTZ &&& rt != 0 605f1b44067SMarkos Chandras * For real GTZ{,L}, rt is always 0. 606f1b44067SMarkos Chandras */ 607f1b44067SMarkos Chandras if (cpu_has_mips_r6 && insn.i_format.rt) { 608f1b44067SMarkos Chandras if ((insn.i_format.opcode == blez_op) && 609f1b44067SMarkos Chandras ((!insn.i_format.rs && insn.i_format.rt) || 610f1b44067SMarkos Chandras (insn.i_format.rs == insn.i_format.rt))) 611f1b44067SMarkos Chandras regs->regs[31] = regs->cp0_epc + 612f1b44067SMarkos Chandras dec_insn.pc_inc; 613f1b44067SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 614f1b44067SMarkos Chandras dec_insn.next_pc_inc; 615f1b44067SMarkos Chandras 616f1b44067SMarkos Chandras return 1; 617f1b44067SMarkos Chandras } 618f1b44067SMarkos Chandras 619102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] > 0) 620102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 621102cedc3SLeonid Yegoshin dec_insn.pc_inc + 622102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 623102cedc3SLeonid Yegoshin else 624102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 625102cedc3SLeonid Yegoshin dec_insn.pc_inc + 626102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 627102cedc3SLeonid Yegoshin return 1; 628c893ce38SMarkos Chandras case cbcond0_op: 62910d962d5SMarkos Chandras case cbcond1_op: 630c893ce38SMarkos Chandras if (!cpu_has_mips_r6) 631c893ce38SMarkos Chandras break; 632c893ce38SMarkos Chandras if (insn.i_format.rt && !insn.i_format.rs) 633c893ce38SMarkos Chandras regs->regs[31] = regs->cp0_epc + 4; 634c893ce38SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 635c893ce38SMarkos Chandras dec_insn.next_pc_inc; 636c893ce38SMarkos Chandras 637c893ce38SMarkos Chandras return 1; 638c26d4219SDavid Daney #ifdef CONFIG_CPU_CAVIUM_OCTEON 639c26d4219SDavid Daney case lwc2_op: /* This is bbit0 on Octeon */ 640c26d4219SDavid Daney if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0) 641c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 642c26d4219SDavid Daney else 643c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 644c26d4219SDavid Daney return 1; 645c26d4219SDavid Daney case ldc2_op: /* This is bbit032 on Octeon */ 646c26d4219SDavid Daney if ((regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) == 0) 647c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 648c26d4219SDavid Daney else 649c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 650c26d4219SDavid Daney return 1; 651c26d4219SDavid Daney case swc2_op: /* This is bbit1 on Octeon */ 652c26d4219SDavid Daney if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) 653c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 654c26d4219SDavid Daney else 655c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 656c26d4219SDavid Daney return 1; 657c26d4219SDavid Daney case sdc2_op: /* This is bbit132 on Octeon */ 658c26d4219SDavid Daney if (regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) 659c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 660c26d4219SDavid Daney else 661c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 662c26d4219SDavid Daney return 1; 6638467ca01SMarkos Chandras #else 6648467ca01SMarkos Chandras case bc6_op: 6658467ca01SMarkos Chandras /* 6668467ca01SMarkos Chandras * Only valid for MIPS R6 but we can still end up 6678467ca01SMarkos Chandras * here from a broken userland so just tell emulator 6688467ca01SMarkos Chandras * this is not a branch and let it break later on. 6698467ca01SMarkos Chandras */ 6708467ca01SMarkos Chandras if (!cpu_has_mips_r6) 6718467ca01SMarkos Chandras break; 6728467ca01SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 6738467ca01SMarkos Chandras dec_insn.next_pc_inc; 6748467ca01SMarkos Chandras 6758467ca01SMarkos Chandras return 1; 67684fef630SMarkos Chandras case balc6_op: 67784fef630SMarkos Chandras if (!cpu_has_mips_r6) 67884fef630SMarkos Chandras break; 67984fef630SMarkos Chandras regs->regs[31] = regs->cp0_epc + 4; 68084fef630SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 68184fef630SMarkos Chandras dec_insn.next_pc_inc; 68284fef630SMarkos Chandras 68384fef630SMarkos Chandras return 1; 68469b9a2fdSMarkos Chandras case beqzcjic_op: 68569b9a2fdSMarkos Chandras if (!cpu_has_mips_r6) 68669b9a2fdSMarkos Chandras break; 68769b9a2fdSMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 68869b9a2fdSMarkos Chandras dec_insn.next_pc_inc; 68969b9a2fdSMarkos Chandras 69069b9a2fdSMarkos Chandras return 1; 69128d6f93dSMarkos Chandras case bnezcjialc_op: 69228d6f93dSMarkos Chandras if (!cpu_has_mips_r6) 69328d6f93dSMarkos Chandras break; 69428d6f93dSMarkos Chandras if (!insn.i_format.rs) 69528d6f93dSMarkos Chandras regs->regs[31] = regs->cp0_epc + 4; 69628d6f93dSMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 69728d6f93dSMarkos Chandras dec_insn.next_pc_inc; 69828d6f93dSMarkos Chandras 69928d6f93dSMarkos Chandras return 1; 700c26d4219SDavid Daney #endif 7011da177e4SLinus Torvalds case cop0_op: 7021da177e4SLinus Torvalds case cop1_op: 703c8a34581SMarkos Chandras /* Need to check for R6 bc1nez and bc1eqz branches */ 704c8a34581SMarkos Chandras if (cpu_has_mips_r6 && 705c8a34581SMarkos Chandras ((insn.i_format.rs == bc1eqz_op) || 706c8a34581SMarkos Chandras (insn.i_format.rs == bc1nez_op))) { 707c8a34581SMarkos Chandras bit = 0; 708c8a34581SMarkos Chandras switch (insn.i_format.rs) { 709c8a34581SMarkos Chandras case bc1eqz_op: 710c8a34581SMarkos Chandras if (get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1) 711c8a34581SMarkos Chandras bit = 1; 712c8a34581SMarkos Chandras break; 713c8a34581SMarkos Chandras case bc1nez_op: 714c8a34581SMarkos Chandras if (!(get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1)) 715c8a34581SMarkos Chandras bit = 1; 716c8a34581SMarkos Chandras break; 717c8a34581SMarkos Chandras } 718c8a34581SMarkos Chandras if (bit) 719c8a34581SMarkos Chandras *contpc = regs->cp0_epc + 720c8a34581SMarkos Chandras dec_insn.pc_inc + 721c8a34581SMarkos Chandras (insn.i_format.simmediate << 2); 722c8a34581SMarkos Chandras else 723c8a34581SMarkos Chandras *contpc = regs->cp0_epc + 724c8a34581SMarkos Chandras dec_insn.pc_inc + 725c8a34581SMarkos Chandras dec_insn.next_pc_inc; 726c8a34581SMarkos Chandras 727c8a34581SMarkos Chandras return 1; 728c8a34581SMarkos Chandras } 729c8a34581SMarkos Chandras /* R2/R6 compatible cop1 instruction. Fall through */ 7301da177e4SLinus Torvalds case cop2_op: 7311da177e4SLinus Torvalds case cop1x_op: 732102cedc3SLeonid Yegoshin if (insn.i_format.rs == bc_op) { 733102cedc3SLeonid Yegoshin preempt_disable(); 734102cedc3SLeonid Yegoshin if (is_fpu_owner()) 735842dfc11SManuel Lauss fcr31 = read_32bit_cp1_register(CP1_STATUS); 736102cedc3SLeonid Yegoshin else 737102cedc3SLeonid Yegoshin fcr31 = current->thread.fpu.fcr31; 738102cedc3SLeonid Yegoshin preempt_enable(); 739102cedc3SLeonid Yegoshin 740102cedc3SLeonid Yegoshin bit = (insn.i_format.rt >> 2); 741102cedc3SLeonid Yegoshin bit += (bit != 0); 742102cedc3SLeonid Yegoshin bit += 23; 743102cedc3SLeonid Yegoshin switch (insn.i_format.rt & 3) { 744102cedc3SLeonid Yegoshin case 0: /* bc1f */ 745102cedc3SLeonid Yegoshin case 2: /* bc1fl */ 746102cedc3SLeonid Yegoshin if (~fcr31 & (1 << bit)) 747102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 748102cedc3SLeonid Yegoshin dec_insn.pc_inc + 749102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 750102cedc3SLeonid Yegoshin else 751102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 752102cedc3SLeonid Yegoshin dec_insn.pc_inc + 753102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 754102cedc3SLeonid Yegoshin return 1; 755102cedc3SLeonid Yegoshin case 1: /* bc1t */ 756102cedc3SLeonid Yegoshin case 3: /* bc1tl */ 757102cedc3SLeonid Yegoshin if (fcr31 & (1 << bit)) 758102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 759102cedc3SLeonid Yegoshin dec_insn.pc_inc + 760102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 761102cedc3SLeonid Yegoshin else 762102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 763102cedc3SLeonid Yegoshin dec_insn.pc_inc + 764102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 7651da177e4SLinus Torvalds return 1; 7661da177e4SLinus Torvalds } 767102cedc3SLeonid Yegoshin } 768102cedc3SLeonid Yegoshin break; 769102cedc3SLeonid Yegoshin } 7701da177e4SLinus Torvalds return 0; 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds /* 7741da177e4SLinus Torvalds * In the Linux kernel, we support selection of FPR format on the 775da0bac33SDavid Daney * basis of the Status.FR bit. If an FPU is not present, the FR bit 776da0bac33SDavid Daney * is hardwired to zero, which would imply a 32-bit FPU even for 777597ce172SPaul Burton * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS. 77851d943f0SRalf Baechle * FPU emu is slow and bulky and optimizing this function offers fairly 77951d943f0SRalf Baechle * sizeable benefits so we try to be clever and make this function return 78051d943f0SRalf Baechle * a constant whenever possible, that is on 64-bit kernels without O32 781597ce172SPaul Burton * compatibility enabled and on 32-bit without 64-bit FPU support. 7821da177e4SLinus Torvalds */ 783da0bac33SDavid Daney static inline int cop1_64bit(struct pt_regs *xcp) 784da0bac33SDavid Daney { 78508a07904SRalf Baechle if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) 78651d943f0SRalf Baechle return 1; 78708a07904SRalf Baechle else if (config_enabled(CONFIG_32BIT) && 78808a07904SRalf Baechle !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) 789da0bac33SDavid Daney return 0; 79008a07904SRalf Baechle 791597ce172SPaul Burton return !test_thread_flag(TIF_32BIT_FPREGS); 792da0bac33SDavid Daney } 7931da177e4SLinus Torvalds 7944227a2d4SPaul Burton static inline bool hybrid_fprs(void) 7954227a2d4SPaul Burton { 7964227a2d4SPaul Burton return test_thread_flag(TIF_HYBRID_FPREGS); 7974227a2d4SPaul Burton } 7984227a2d4SPaul Burton 79947fa0c02SRalf Baechle #define SIFROMREG(si, x) \ 80047fa0c02SRalf Baechle do { \ 8014227a2d4SPaul Burton if (cop1_64bit(xcp) && !hybrid_fprs()) \ 802c8c0da6bSPaul Burton (si) = (int)get_fpr32(&ctx->fpr[x], 0); \ 803bbd426f5SPaul Burton else \ 804c8c0da6bSPaul Burton (si) = (int)get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ 805bbd426f5SPaul Burton } while (0) 806da0bac33SDavid Daney 80747fa0c02SRalf Baechle #define SITOREG(si, x) \ 80847fa0c02SRalf Baechle do { \ 8094227a2d4SPaul Burton if (cop1_64bit(xcp) && !hybrid_fprs()) { \ 810ef1c47afSPaul Burton unsigned i; \ 811bbd426f5SPaul Burton set_fpr32(&ctx->fpr[x], 0, si); \ 812ef1c47afSPaul Burton for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ 813ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], i, 0); \ 814ef1c47afSPaul Burton } else { \ 815bbd426f5SPaul Burton set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \ 816ef1c47afSPaul Burton } \ 817bbd426f5SPaul Burton } while (0) 8181da177e4SLinus Torvalds 819c8c0da6bSPaul Burton #define SIFROMHREG(si, x) ((si) = (int)get_fpr32(&ctx->fpr[x], 1)) 820ef1c47afSPaul Burton 82147fa0c02SRalf Baechle #define SITOHREG(si, x) \ 82247fa0c02SRalf Baechle do { \ 823ef1c47afSPaul Burton unsigned i; \ 824ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], 1, si); \ 825ef1c47afSPaul Burton for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ 826ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], i, 0); \ 827ef1c47afSPaul Burton } while (0) 8281ac94400SLeonid Yegoshin 829bbd426f5SPaul Burton #define DIFROMREG(di, x) \ 830bbd426f5SPaul Burton ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) 831bbd426f5SPaul Burton 83247fa0c02SRalf Baechle #define DITOREG(di, x) \ 83347fa0c02SRalf Baechle do { \ 834ef1c47afSPaul Burton unsigned fpr, i; \ 835ef1c47afSPaul Burton fpr = (x) & ~(cop1_64bit(xcp) == 0); \ 836ef1c47afSPaul Burton set_fpr64(&ctx->fpr[fpr], 0, di); \ 837ef1c47afSPaul Burton for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \ 838ef1c47afSPaul Burton set_fpr64(&ctx->fpr[fpr], i, 0); \ 839ef1c47afSPaul Burton } while (0) 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) 8421da177e4SLinus Torvalds #define SPTOREG(sp, x) SITOREG((sp).bits, x) 8431da177e4SLinus Torvalds #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) 8441da177e4SLinus Torvalds #define DPTOREG(dp, x) DITOREG((dp).bits, x) 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds /* 847d4f5b088SMaciej W. Rozycki * Emulate a CFC1 instruction. 848d4f5b088SMaciej W. Rozycki */ 849d4f5b088SMaciej W. Rozycki static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 850d4f5b088SMaciej W. Rozycki mips_instruction ir) 851d4f5b088SMaciej W. Rozycki { 852c491cfa2SMaciej W. Rozycki u32 fcr31 = ctx->fcr31; 853c491cfa2SMaciej W. Rozycki u32 value = 0; 854d4f5b088SMaciej W. Rozycki 855c491cfa2SMaciej W. Rozycki switch (MIPSInst_RD(ir)) { 856c491cfa2SMaciej W. Rozycki case FPCREG_CSR: 857c491cfa2SMaciej W. Rozycki value = fcr31; 858d4f5b088SMaciej W. Rozycki pr_debug("%p gpr[%d]<-csr=%08x\n", 859c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 860c491cfa2SMaciej W. Rozycki break; 861c491cfa2SMaciej W. Rozycki 862c491cfa2SMaciej W. Rozycki case FPCREG_FENR: 863c491cfa2SMaciej W. Rozycki if (!cpu_has_mips_r) 864c491cfa2SMaciej W. Rozycki break; 865c491cfa2SMaciej W. Rozycki value = (fcr31 >> (FPU_CSR_FS_S - MIPS_FENR_FS_S)) & 866c491cfa2SMaciej W. Rozycki MIPS_FENR_FS; 867c491cfa2SMaciej W. Rozycki value |= fcr31 & (FPU_CSR_ALL_E | FPU_CSR_RM); 868c491cfa2SMaciej W. Rozycki pr_debug("%p gpr[%d]<-enr=%08x\n", 869c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 870c491cfa2SMaciej W. Rozycki break; 871c491cfa2SMaciej W. Rozycki 872c491cfa2SMaciej W. Rozycki case FPCREG_FEXR: 873c491cfa2SMaciej W. Rozycki if (!cpu_has_mips_r) 874c491cfa2SMaciej W. Rozycki break; 875c491cfa2SMaciej W. Rozycki value = fcr31 & (FPU_CSR_ALL_X | FPU_CSR_ALL_S); 876c491cfa2SMaciej W. Rozycki pr_debug("%p gpr[%d]<-exr=%08x\n", 877c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 878c491cfa2SMaciej W. Rozycki break; 879c491cfa2SMaciej W. Rozycki 880c491cfa2SMaciej W. Rozycki case FPCREG_FCCR: 881c491cfa2SMaciej W. Rozycki if (!cpu_has_mips_r) 882c491cfa2SMaciej W. Rozycki break; 883c491cfa2SMaciej W. Rozycki value = (fcr31 >> (FPU_CSR_COND_S - MIPS_FCCR_COND0_S)) & 884c491cfa2SMaciej W. Rozycki MIPS_FCCR_COND0; 885c491cfa2SMaciej W. Rozycki value |= (fcr31 >> (FPU_CSR_COND1_S - MIPS_FCCR_COND1_S)) & 886c491cfa2SMaciej W. Rozycki (MIPS_FCCR_CONDX & ~MIPS_FCCR_COND0); 887c491cfa2SMaciej W. Rozycki pr_debug("%p gpr[%d]<-ccr=%08x\n", 888c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 889c491cfa2SMaciej W. Rozycki break; 890c491cfa2SMaciej W. Rozycki 891c491cfa2SMaciej W. Rozycki case FPCREG_RID: 89203dce595SMaciej W. Rozycki value = boot_cpu_data.fpu_id; 893c491cfa2SMaciej W. Rozycki break; 894c491cfa2SMaciej W. Rozycki 895c491cfa2SMaciej W. Rozycki default: 896c491cfa2SMaciej W. Rozycki break; 897c491cfa2SMaciej W. Rozycki } 898c491cfa2SMaciej W. Rozycki 899d4f5b088SMaciej W. Rozycki if (MIPSInst_RT(ir)) 900d4f5b088SMaciej W. Rozycki xcp->regs[MIPSInst_RT(ir)] = value; 901d4f5b088SMaciej W. Rozycki } 902d4f5b088SMaciej W. Rozycki 903d4f5b088SMaciej W. Rozycki /* 904d4f5b088SMaciej W. Rozycki * Emulate a CTC1 instruction. 905d4f5b088SMaciej W. Rozycki */ 906d4f5b088SMaciej W. Rozycki static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 907d4f5b088SMaciej W. Rozycki mips_instruction ir) 908d4f5b088SMaciej W. Rozycki { 909c491cfa2SMaciej W. Rozycki u32 fcr31 = ctx->fcr31; 910d4f5b088SMaciej W. Rozycki u32 value; 9119b26616cSMaciej W. Rozycki u32 mask; 912d4f5b088SMaciej W. Rozycki 913d4f5b088SMaciej W. Rozycki if (MIPSInst_RT(ir) == 0) 914d4f5b088SMaciej W. Rozycki value = 0; 915d4f5b088SMaciej W. Rozycki else 916d4f5b088SMaciej W. Rozycki value = xcp->regs[MIPSInst_RT(ir)]; 917d4f5b088SMaciej W. Rozycki 918c491cfa2SMaciej W. Rozycki switch (MIPSInst_RD(ir)) { 919c491cfa2SMaciej W. Rozycki case FPCREG_CSR: 920d4f5b088SMaciej W. Rozycki pr_debug("%p gpr[%d]->csr=%08x\n", 921c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 922d4f5b088SMaciej W. Rozycki 9239b26616cSMaciej W. Rozycki /* Preserve read-only bits. */ 92403dce595SMaciej W. Rozycki mask = boot_cpu_data.fpu_msk31; 9259b26616cSMaciej W. Rozycki fcr31 = (value & ~mask) | (fcr31 & mask); 926c491cfa2SMaciej W. Rozycki break; 927c491cfa2SMaciej W. Rozycki 928c491cfa2SMaciej W. Rozycki case FPCREG_FENR: 929c491cfa2SMaciej W. Rozycki if (!cpu_has_mips_r) 930c491cfa2SMaciej W. Rozycki break; 931c491cfa2SMaciej W. Rozycki pr_debug("%p gpr[%d]->enr=%08x\n", 932c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 933c491cfa2SMaciej W. Rozycki fcr31 &= ~(FPU_CSR_FS | FPU_CSR_ALL_E | FPU_CSR_RM); 934c491cfa2SMaciej W. Rozycki fcr31 |= (value << (FPU_CSR_FS_S - MIPS_FENR_FS_S)) & 935c491cfa2SMaciej W. Rozycki FPU_CSR_FS; 936c491cfa2SMaciej W. Rozycki fcr31 |= value & (FPU_CSR_ALL_E | FPU_CSR_RM); 937c491cfa2SMaciej W. Rozycki break; 938c491cfa2SMaciej W. Rozycki 939c491cfa2SMaciej W. Rozycki case FPCREG_FEXR: 940c491cfa2SMaciej W. Rozycki if (!cpu_has_mips_r) 941c491cfa2SMaciej W. Rozycki break; 942c491cfa2SMaciej W. Rozycki pr_debug("%p gpr[%d]->exr=%08x\n", 943c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 944c491cfa2SMaciej W. Rozycki fcr31 &= ~(FPU_CSR_ALL_X | FPU_CSR_ALL_S); 945c491cfa2SMaciej W. Rozycki fcr31 |= value & (FPU_CSR_ALL_X | FPU_CSR_ALL_S); 946c491cfa2SMaciej W. Rozycki break; 947c491cfa2SMaciej W. Rozycki 948c491cfa2SMaciej W. Rozycki case FPCREG_FCCR: 949c491cfa2SMaciej W. Rozycki if (!cpu_has_mips_r) 950c491cfa2SMaciej W. Rozycki break; 951c491cfa2SMaciej W. Rozycki pr_debug("%p gpr[%d]->ccr=%08x\n", 952c491cfa2SMaciej W. Rozycki (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 953c491cfa2SMaciej W. Rozycki fcr31 &= ~(FPU_CSR_CONDX | FPU_CSR_COND); 954c491cfa2SMaciej W. Rozycki fcr31 |= (value << (FPU_CSR_COND_S - MIPS_FCCR_COND0_S)) & 955c491cfa2SMaciej W. Rozycki FPU_CSR_COND; 956c491cfa2SMaciej W. Rozycki fcr31 |= (value << (FPU_CSR_COND1_S - MIPS_FCCR_COND1_S)) & 957c491cfa2SMaciej W. Rozycki FPU_CSR_CONDX; 958c491cfa2SMaciej W. Rozycki break; 959c491cfa2SMaciej W. Rozycki 960c491cfa2SMaciej W. Rozycki default: 961c491cfa2SMaciej W. Rozycki break; 962d4f5b088SMaciej W. Rozycki } 963c491cfa2SMaciej W. Rozycki 964c491cfa2SMaciej W. Rozycki ctx->fcr31 = fcr31; 965d4f5b088SMaciej W. Rozycki } 966d4f5b088SMaciej W. Rozycki 967d4f5b088SMaciej W. Rozycki /* 9681da177e4SLinus Torvalds * Emulate the single floating point instruction pointed at by EPC. 9691da177e4SLinus Torvalds * Two instructions if the instruction is in a branch delay slot. 9701da177e4SLinus Torvalds */ 9711da177e4SLinus Torvalds 972515b029dSDavid Daney static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 973102cedc3SLeonid Yegoshin struct mm_decoded_insn dec_insn, void *__user *fault_addr) 9741da177e4SLinus Torvalds { 975102cedc3SLeonid Yegoshin unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; 9763f7cac41SRalf Baechle unsigned int cond, cbit; 9773f7cac41SRalf Baechle mips_instruction ir; 9783f7cac41SRalf Baechle int likely, pc_inc; 9793f7cac41SRalf Baechle u32 __user *wva; 9803f7cac41SRalf Baechle u64 __user *dva; 9813f7cac41SRalf Baechle u32 wval; 9823f7cac41SRalf Baechle u64 dval; 9833f7cac41SRalf Baechle int sig; 9841da177e4SLinus Torvalds 98570e4c234SRalf Baechle /* 98670e4c234SRalf Baechle * These are giving gcc a gentle hint about what to expect in 98770e4c234SRalf Baechle * dec_inst in order to do better optimization. 98870e4c234SRalf Baechle */ 98970e4c234SRalf Baechle if (!cpu_has_mmips && dec_insn.micro_mips_mode) 99070e4c234SRalf Baechle unreachable(); 99170e4c234SRalf Baechle 9921da177e4SLinus Torvalds /* XXX NEC Vr54xx bug workaround */ 993e7e9cae5SRalf Baechle if (delay_slot(xcp)) { 994102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 995102cedc3SLeonid Yegoshin if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) 996e7e9cae5SRalf Baechle clear_delay_slot(xcp); 997102cedc3SLeonid Yegoshin } else { 998102cedc3SLeonid Yegoshin if (!isBranchInstr(xcp, dec_insn, &contpc)) 999e7e9cae5SRalf Baechle clear_delay_slot(xcp); 1000102cedc3SLeonid Yegoshin } 1001102cedc3SLeonid Yegoshin } 10021da177e4SLinus Torvalds 1003e7e9cae5SRalf Baechle if (delay_slot(xcp)) { 10041da177e4SLinus Torvalds /* 10051da177e4SLinus Torvalds * The instruction to be emulated is in a branch delay slot 10061da177e4SLinus Torvalds * which means that we have to emulate the branch instruction 10071da177e4SLinus Torvalds * BEFORE we do the cop1 instruction. 10081da177e4SLinus Torvalds * 10091da177e4SLinus Torvalds * This branch could be a COP1 branch, but in that case we 10101da177e4SLinus Torvalds * would have had a trap for that instruction, and would not 10111da177e4SLinus Torvalds * come through this route. 10121da177e4SLinus Torvalds * 10131da177e4SLinus Torvalds * Linux MIPS branch emulator operates on context, updating the 10141da177e4SLinus Torvalds * cp0_epc. 10151da177e4SLinus Torvalds */ 1016102cedc3SLeonid Yegoshin ir = dec_insn.next_insn; /* process delay slot instr */ 1017102cedc3SLeonid Yegoshin pc_inc = dec_insn.next_pc_inc; 1018333d1f67SRalf Baechle } else { 1019102cedc3SLeonid Yegoshin ir = dec_insn.insn; /* process current instr */ 1020102cedc3SLeonid Yegoshin pc_inc = dec_insn.pc_inc; 1021102cedc3SLeonid Yegoshin } 1022102cedc3SLeonid Yegoshin 1023102cedc3SLeonid Yegoshin /* 1024102cedc3SLeonid Yegoshin * Since microMIPS FPU instructios are a subset of MIPS32 FPU 1025102cedc3SLeonid Yegoshin * instructions, we want to convert microMIPS FPU instructions 1026102cedc3SLeonid Yegoshin * into MIPS32 instructions so that we could reuse all of the 1027102cedc3SLeonid Yegoshin * FPU emulation code. 1028102cedc3SLeonid Yegoshin * 1029102cedc3SLeonid Yegoshin * NOTE: We cannot do this for branch instructions since they 1030102cedc3SLeonid Yegoshin * are not a subset. Example: Cannot emulate a 16-bit 1031102cedc3SLeonid Yegoshin * aligned target address with a MIPS32 instruction. 1032102cedc3SLeonid Yegoshin */ 1033102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 1034102cedc3SLeonid Yegoshin /* 1035102cedc3SLeonid Yegoshin * If next instruction is a 16-bit instruction, then it 1036102cedc3SLeonid Yegoshin * it cannot be a FPU instruction. This could happen 1037102cedc3SLeonid Yegoshin * since we can be called for non-FPU instructions. 1038102cedc3SLeonid Yegoshin */ 1039102cedc3SLeonid Yegoshin if ((pc_inc == 2) || 1040102cedc3SLeonid Yegoshin (microMIPS32_to_MIPS32((union mips_instruction *)&ir) 1041102cedc3SLeonid Yegoshin == SIGILL)) 1042102cedc3SLeonid Yegoshin return SIGILL; 10431da177e4SLinus Torvalds } 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds emul: 1046a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); 1047b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(emulated); 10481da177e4SLinus Torvalds switch (MIPSInst_OPCODE(ir)) { 10493f7cac41SRalf Baechle case ldc1_op: 10503f7cac41SRalf Baechle dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10511da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 1052b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1053515b029dSDavid Daney 10543f7cac41SRalf Baechle if (!access_ok(VERIFY_READ, dva, sizeof(u64))) { 1055b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10563f7cac41SRalf Baechle *fault_addr = dva; 10571da177e4SLinus Torvalds return SIGBUS; 10581da177e4SLinus Torvalds } 10593f7cac41SRalf Baechle if (__get_user(dval, dva)) { 1060515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10613f7cac41SRalf Baechle *fault_addr = dva; 1062515b029dSDavid Daney return SIGSEGV; 1063515b029dSDavid Daney } 10643f7cac41SRalf Baechle DITOREG(dval, MIPSInst_RT(ir)); 10651da177e4SLinus Torvalds break; 10661da177e4SLinus Torvalds 10673f7cac41SRalf Baechle case sdc1_op: 10683f7cac41SRalf Baechle dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10691da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 1070b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 10713f7cac41SRalf Baechle DIFROMREG(dval, MIPSInst_RT(ir)); 10723f7cac41SRalf Baechle if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { 1073b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10743f7cac41SRalf Baechle *fault_addr = dva; 10751da177e4SLinus Torvalds return SIGBUS; 10761da177e4SLinus Torvalds } 10773f7cac41SRalf Baechle if (__put_user(dval, dva)) { 1078515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10793f7cac41SRalf Baechle *fault_addr = dva; 1080515b029dSDavid Daney return SIGSEGV; 1081515b029dSDavid Daney } 10821da177e4SLinus Torvalds break; 10831da177e4SLinus Torvalds 10843f7cac41SRalf Baechle case lwc1_op: 10853f7cac41SRalf Baechle wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10861da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 1087b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 10883f7cac41SRalf Baechle if (!access_ok(VERIFY_READ, wva, sizeof(u32))) { 1089b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10903f7cac41SRalf Baechle *fault_addr = wva; 10911da177e4SLinus Torvalds return SIGBUS; 10921da177e4SLinus Torvalds } 10933f7cac41SRalf Baechle if (__get_user(wval, wva)) { 1094515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10953f7cac41SRalf Baechle *fault_addr = wva; 1096515b029dSDavid Daney return SIGSEGV; 1097515b029dSDavid Daney } 10983f7cac41SRalf Baechle SITOREG(wval, MIPSInst_RT(ir)); 10991da177e4SLinus Torvalds break; 11001da177e4SLinus Torvalds 11013f7cac41SRalf Baechle case swc1_op: 11023f7cac41SRalf Baechle wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 11031da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 1104b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 11053f7cac41SRalf Baechle SIFROMREG(wval, MIPSInst_RT(ir)); 11063f7cac41SRalf Baechle if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { 1107b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 11083f7cac41SRalf Baechle *fault_addr = wva; 11091da177e4SLinus Torvalds return SIGBUS; 11101da177e4SLinus Torvalds } 11113f7cac41SRalf Baechle if (__put_user(wval, wva)) { 1112515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 11133f7cac41SRalf Baechle *fault_addr = wva; 1114515b029dSDavid Daney return SIGSEGV; 1115515b029dSDavid Daney } 11161da177e4SLinus Torvalds break; 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds case cop1_op: 11191da177e4SLinus Torvalds switch (MIPSInst_RS(ir)) { 11201da177e4SLinus Torvalds case dmfc_op: 112108a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 112208a07904SRalf Baechle return SIGILL; 112308a07904SRalf Baechle 11241da177e4SLinus Torvalds /* copregister fs -> gpr[rt] */ 11251da177e4SLinus Torvalds if (MIPSInst_RT(ir) != 0) { 11261da177e4SLinus Torvalds DIFROMREG(xcp->regs[MIPSInst_RT(ir)], 11271da177e4SLinus Torvalds MIPSInst_RD(ir)); 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds break; 11301da177e4SLinus Torvalds 11311da177e4SLinus Torvalds case dmtc_op: 113208a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 113308a07904SRalf Baechle return SIGILL; 113408a07904SRalf Baechle 11351da177e4SLinus Torvalds /* copregister fs <- rt */ 11361da177e4SLinus Torvalds DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 11371da177e4SLinus Torvalds break; 11381da177e4SLinus Torvalds 11391ac94400SLeonid Yegoshin case mfhc_op: 1140e8f80cc1SMarkos Chandras if (!cpu_has_mips_r2_r6) 11411ac94400SLeonid Yegoshin goto sigill; 11421ac94400SLeonid Yegoshin 11431ac94400SLeonid Yegoshin /* copregister rd -> gpr[rt] */ 11441ac94400SLeonid Yegoshin if (MIPSInst_RT(ir) != 0) { 11451ac94400SLeonid Yegoshin SIFROMHREG(xcp->regs[MIPSInst_RT(ir)], 11461ac94400SLeonid Yegoshin MIPSInst_RD(ir)); 11471ac94400SLeonid Yegoshin } 11481ac94400SLeonid Yegoshin break; 11491ac94400SLeonid Yegoshin 11501ac94400SLeonid Yegoshin case mthc_op: 1151e8f80cc1SMarkos Chandras if (!cpu_has_mips_r2_r6) 11521ac94400SLeonid Yegoshin goto sigill; 11531ac94400SLeonid Yegoshin 11541ac94400SLeonid Yegoshin /* copregister rd <- gpr[rt] */ 11551ac94400SLeonid Yegoshin SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 11561ac94400SLeonid Yegoshin break; 11571ac94400SLeonid Yegoshin 11581da177e4SLinus Torvalds case mfc_op: 11591da177e4SLinus Torvalds /* copregister rd -> gpr[rt] */ 11601da177e4SLinus Torvalds if (MIPSInst_RT(ir) != 0) { 11611da177e4SLinus Torvalds SIFROMREG(xcp->regs[MIPSInst_RT(ir)], 11621da177e4SLinus Torvalds MIPSInst_RD(ir)); 11631da177e4SLinus Torvalds } 11641da177e4SLinus Torvalds break; 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds case mtc_op: 11671da177e4SLinus Torvalds /* copregister rd <- rt */ 11681da177e4SLinus Torvalds SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 11691da177e4SLinus Torvalds break; 11701da177e4SLinus Torvalds 11713f7cac41SRalf Baechle case cfc_op: 11721da177e4SLinus Torvalds /* cop control register rd -> gpr[rt] */ 1173d4f5b088SMaciej W. Rozycki cop1_cfc(xcp, ctx, ir); 11741da177e4SLinus Torvalds break; 11751da177e4SLinus Torvalds 11763f7cac41SRalf Baechle case ctc_op: 11771da177e4SLinus Torvalds /* copregister rd <- rt */ 1178d4f5b088SMaciej W. Rozycki cop1_ctc(xcp, ctx, ir); 11791da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 11801da177e4SLinus Torvalds return SIGFPE; 11811da177e4SLinus Torvalds } 11821da177e4SLinus Torvalds break; 11831da177e4SLinus Torvalds 1184c909ca71SMarkos Chandras case bc1eqz_op: 1185c909ca71SMarkos Chandras case bc1nez_op: 1186c909ca71SMarkos Chandras if (!cpu_has_mips_r6 || delay_slot(xcp)) 1187c909ca71SMarkos Chandras return SIGILL; 1188c909ca71SMarkos Chandras 1189c909ca71SMarkos Chandras cond = likely = 0; 1190c909ca71SMarkos Chandras switch (MIPSInst_RS(ir)) { 1191c909ca71SMarkos Chandras case bc1eqz_op: 1192c909ca71SMarkos Chandras if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) 1193c909ca71SMarkos Chandras cond = 1; 1194c909ca71SMarkos Chandras break; 1195c909ca71SMarkos Chandras case bc1nez_op: 1196c909ca71SMarkos Chandras if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) 1197c909ca71SMarkos Chandras cond = 1; 1198c909ca71SMarkos Chandras break; 1199c909ca71SMarkos Chandras } 1200c909ca71SMarkos Chandras goto branch_common; 1201c909ca71SMarkos Chandras 12023f7cac41SRalf Baechle case bc_op: 1203e7e9cae5SRalf Baechle if (delay_slot(xcp)) 12041da177e4SLinus Torvalds return SIGILL; 12051da177e4SLinus Torvalds 120608a07904SRalf Baechle if (cpu_has_mips_4_5_r) 120708a07904SRalf Baechle cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; 120808a07904SRalf Baechle else 120908a07904SRalf Baechle cbit = FPU_CSR_COND; 121008a07904SRalf Baechle cond = ctx->fcr31 & cbit; 121108a07904SRalf Baechle 12123f7cac41SRalf Baechle likely = 0; 12131da177e4SLinus Torvalds switch (MIPSInst_RT(ir) & 3) { 12141da177e4SLinus Torvalds case bcfl_op: 12152d83fea7SMaciej W. Rozycki if (cpu_has_mips_2_3_4_5_r) 12161da177e4SLinus Torvalds likely = 1; 12172d83fea7SMaciej W. Rozycki /* Fall through */ 12181da177e4SLinus Torvalds case bcf_op: 12191da177e4SLinus Torvalds cond = !cond; 12201da177e4SLinus Torvalds break; 12211da177e4SLinus Torvalds case bctl_op: 12222d83fea7SMaciej W. Rozycki if (cpu_has_mips_2_3_4_5_r) 12231da177e4SLinus Torvalds likely = 1; 12242d83fea7SMaciej W. Rozycki /* Fall through */ 12251da177e4SLinus Torvalds case bct_op: 12261da177e4SLinus Torvalds break; 12271da177e4SLinus Torvalds } 1228c909ca71SMarkos Chandras branch_common: 1229e7e9cae5SRalf Baechle set_delay_slot(xcp); 12301da177e4SLinus Torvalds if (cond) { 12313f7cac41SRalf Baechle /* 12323f7cac41SRalf Baechle * Branch taken: emulate dslot instruction 12331da177e4SLinus Torvalds */ 12349ab4471cSMaciej W. Rozycki unsigned long bcpc; 12359ab4471cSMaciej W. Rozycki 12369ab4471cSMaciej W. Rozycki /* 12379ab4471cSMaciej W. Rozycki * Remember EPC at the branch to point back 12389ab4471cSMaciej W. Rozycki * at so that any delay-slot instruction 12399ab4471cSMaciej W. Rozycki * signal is not silently ignored. 12409ab4471cSMaciej W. Rozycki */ 12419ab4471cSMaciej W. Rozycki bcpc = xcp->cp0_epc; 1242102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; 12431da177e4SLinus Torvalds 1244102cedc3SLeonid Yegoshin contpc = MIPSInst_SIMM(ir); 1245102cedc3SLeonid Yegoshin ir = dec_insn.next_insn; 1246102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 1247102cedc3SLeonid Yegoshin contpc = (xcp->cp0_epc + (contpc << 1)); 1248102cedc3SLeonid Yegoshin 1249102cedc3SLeonid Yegoshin /* If 16-bit instruction, not FPU. */ 1250102cedc3SLeonid Yegoshin if ((dec_insn.next_pc_inc == 2) || 1251102cedc3SLeonid Yegoshin (microMIPS32_to_MIPS32((union mips_instruction *)&ir) == SIGILL)) { 1252102cedc3SLeonid Yegoshin 1253102cedc3SLeonid Yegoshin /* 1254102cedc3SLeonid Yegoshin * Since this instruction will 1255102cedc3SLeonid Yegoshin * be put on the stack with 1256102cedc3SLeonid Yegoshin * 32-bit words, get around 1257102cedc3SLeonid Yegoshin * this problem by putting a 1258102cedc3SLeonid Yegoshin * NOP16 as the second one. 1259102cedc3SLeonid Yegoshin */ 1260102cedc3SLeonid Yegoshin if (dec_insn.next_pc_inc == 2) 1261102cedc3SLeonid Yegoshin ir = (ir & (~0xffff)) | MM_NOP16; 1262102cedc3SLeonid Yegoshin 1263102cedc3SLeonid Yegoshin /* 1264102cedc3SLeonid Yegoshin * Single step the non-CP1 1265102cedc3SLeonid Yegoshin * instruction in the dslot. 1266102cedc3SLeonid Yegoshin */ 12679ab4471cSMaciej W. Rozycki sig = mips_dsemul(xcp, ir, 12689ab4471cSMaciej W. Rozycki contpc); 12699ab4471cSMaciej W. Rozycki if (sig) 12709ab4471cSMaciej W. Rozycki xcp->cp0_epc = bcpc; 12719ab4471cSMaciej W. Rozycki /* 12729ab4471cSMaciej W. Rozycki * SIGILL forces out of 12739ab4471cSMaciej W. Rozycki * the emulation loop. 12749ab4471cSMaciej W. Rozycki */ 12759ab4471cSMaciej W. Rozycki return sig ? sig : SIGILL; 1276515b029dSDavid Daney } 1277102cedc3SLeonid Yegoshin } else 1278102cedc3SLeonid Yegoshin contpc = (xcp->cp0_epc + (contpc << 2)); 12791da177e4SLinus Torvalds 12801da177e4SLinus Torvalds switch (MIPSInst_OPCODE(ir)) { 12811da177e4SLinus Torvalds case lwc1_op: 12821da177e4SLinus Torvalds case swc1_op: 128308a07904SRalf Baechle goto emul; 12843f7cac41SRalf Baechle 12851da177e4SLinus Torvalds case ldc1_op: 12861da177e4SLinus Torvalds case sdc1_op: 12872d83fea7SMaciej W. Rozycki if (cpu_has_mips_2_3_4_5_r) 128808a07904SRalf Baechle goto emul; 128908a07904SRalf Baechle 12909ab4471cSMaciej W. Rozycki goto bc_sigill; 12913f7cac41SRalf Baechle 12921da177e4SLinus Torvalds case cop1_op: 129308a07904SRalf Baechle goto emul; 12943f7cac41SRalf Baechle 12951da177e4SLinus Torvalds case cop1x_op: 12962d83fea7SMaciej W. Rozycki if (cpu_has_mips_4_5_64_r2_r6) 12971da177e4SLinus Torvalds /* its one of ours */ 12981da177e4SLinus Torvalds goto emul; 129908a07904SRalf Baechle 13009ab4471cSMaciej W. Rozycki goto bc_sigill; 13013f7cac41SRalf Baechle 13021da177e4SLinus Torvalds case spec_op: 13032d83fea7SMaciej W. Rozycki switch (MIPSInst_FUNC(ir)) { 13042d83fea7SMaciej W. Rozycki case movc_op: 13052d83fea7SMaciej W. Rozycki if (cpu_has_mips_4_5_r) 13061da177e4SLinus Torvalds goto emul; 13072d83fea7SMaciej W. Rozycki 13089ab4471cSMaciej W. Rozycki goto bc_sigill; 13092d83fea7SMaciej W. Rozycki } 13101da177e4SLinus Torvalds break; 13119ab4471cSMaciej W. Rozycki 13129ab4471cSMaciej W. Rozycki bc_sigill: 13139ab4471cSMaciej W. Rozycki xcp->cp0_epc = bcpc; 13149ab4471cSMaciej W. Rozycki return SIGILL; 13151da177e4SLinus Torvalds } 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds /* 13181da177e4SLinus Torvalds * Single step the non-cp1 13191da177e4SLinus Torvalds * instruction in the dslot 13201da177e4SLinus Torvalds */ 13219ab4471cSMaciej W. Rozycki sig = mips_dsemul(xcp, ir, contpc); 13229ab4471cSMaciej W. Rozycki if (sig) 13239ab4471cSMaciej W. Rozycki xcp->cp0_epc = bcpc; 13249ab4471cSMaciej W. Rozycki /* SIGILL forces out of the emulation loop. */ 13259ab4471cSMaciej W. Rozycki return sig ? sig : SIGILL; 13263f7cac41SRalf Baechle } else if (likely) { /* branch not taken */ 13271da177e4SLinus Torvalds /* 13281da177e4SLinus Torvalds * branch likely nullifies 13291da177e4SLinus Torvalds * dslot if not taken 13301da177e4SLinus Torvalds */ 1331102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; 1332102cedc3SLeonid Yegoshin contpc += dec_insn.pc_inc; 13331da177e4SLinus Torvalds /* 13341da177e4SLinus Torvalds * else continue & execute 13351da177e4SLinus Torvalds * dslot as normal insn 13361da177e4SLinus Torvalds */ 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds break; 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds default: 13411da177e4SLinus Torvalds if (!(MIPSInst_RS(ir) & 0x10)) 13421da177e4SLinus Torvalds return SIGILL; 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds /* a real fpu computation instruction */ 13451da177e4SLinus Torvalds if ((sig = fpu_emu(xcp, ctx, ir))) 13461da177e4SLinus Torvalds return sig; 13471da177e4SLinus Torvalds } 13481da177e4SLinus Torvalds break; 13491da177e4SLinus Torvalds 13503f7cac41SRalf Baechle case cop1x_op: 13512d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 135208a07904SRalf Baechle return SIGILL; 135308a07904SRalf Baechle 135408a07904SRalf Baechle sig = fpux_emu(xcp, ctx, ir, fault_addr); 1355515b029dSDavid Daney if (sig) 13561da177e4SLinus Torvalds return sig; 13571da177e4SLinus Torvalds break; 13581da177e4SLinus Torvalds 13591da177e4SLinus Torvalds case spec_op: 136008a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 136108a07904SRalf Baechle return SIGILL; 136208a07904SRalf Baechle 13631da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) != movc_op) 13641da177e4SLinus Torvalds return SIGILL; 13651da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_RT(ir) >> 2]; 13661da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0)) 13671da177e4SLinus Torvalds xcp->regs[MIPSInst_RD(ir)] = 13681da177e4SLinus Torvalds xcp->regs[MIPSInst_RS(ir)]; 13691da177e4SLinus Torvalds break; 13701da177e4SLinus Torvalds default: 13711ac94400SLeonid Yegoshin sigill: 13721da177e4SLinus Torvalds return SIGILL; 13731da177e4SLinus Torvalds } 13741da177e4SLinus Torvalds 13751da177e4SLinus Torvalds /* we did it !! */ 1376e70dfc10SAtsushi Nemoto xcp->cp0_epc = contpc; 1377e7e9cae5SRalf Baechle clear_delay_slot(xcp); 1378333d1f67SRalf Baechle 13791da177e4SLinus Torvalds return 0; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds 13821da177e4SLinus Torvalds /* 13831da177e4SLinus Torvalds * Conversion table from MIPS compare ops 48-63 13841da177e4SLinus Torvalds * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig); 13851da177e4SLinus Torvalds */ 13861da177e4SLinus Torvalds static const unsigned char cmptab[8] = { 13871da177e4SLinus Torvalds 0, /* cmp_0 (sig) cmp_sf */ 13881da177e4SLinus Torvalds IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ 13891da177e4SLinus Torvalds IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ 13901da177e4SLinus Torvalds IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ 13911da177e4SLinus Torvalds IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ 13921da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ 13931da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ 13941da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ 13951da177e4SLinus Torvalds }; 13961da177e4SLinus Torvalds 1397f8c3c671SMarkos Chandras static const unsigned char negative_cmptab[8] = { 1398f8c3c671SMarkos Chandras 0, /* Reserved */ 1399f8c3c671SMarkos Chandras IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ, 1400f8c3c671SMarkos Chandras IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 1401f8c3c671SMarkos Chandras IEEE754_CLT | IEEE754_CGT, 1402f8c3c671SMarkos Chandras /* Reserved */ 1403f8c3c671SMarkos Chandras }; 1404f8c3c671SMarkos Chandras 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds /* 14071da177e4SLinus Torvalds * Additional MIPS4 instructions 14081da177e4SLinus Torvalds */ 14091da177e4SLinus Torvalds 14101da177e4SLinus Torvalds #define DEF3OP(name, p, f1, f2, f3) \ 141147fa0c02SRalf Baechle static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ 141247fa0c02SRalf Baechle union ieee754##p s, union ieee754##p t) \ 14131da177e4SLinus Torvalds { \ 1414cd21dfcfSRalf Baechle struct _ieee754_csr ieee754_csr_save; \ 14151da177e4SLinus Torvalds s = f1(s, t); \ 14161da177e4SLinus Torvalds ieee754_csr_save = ieee754_csr; \ 14171da177e4SLinus Torvalds s = f2(s, r); \ 14181da177e4SLinus Torvalds ieee754_csr_save.cx |= ieee754_csr.cx; \ 14191da177e4SLinus Torvalds ieee754_csr_save.sx |= ieee754_csr.sx; \ 14201da177e4SLinus Torvalds s = f3(s); \ 14211da177e4SLinus Torvalds ieee754_csr.cx |= ieee754_csr_save.cx; \ 14221da177e4SLinus Torvalds ieee754_csr.sx |= ieee754_csr_save.sx; \ 14231da177e4SLinus Torvalds return s; \ 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds 14262209bcb1SRalf Baechle static union ieee754dp fpemu_dp_recip(union ieee754dp d) 14271da177e4SLinus Torvalds { 14281da177e4SLinus Torvalds return ieee754dp_div(ieee754dp_one(0), d); 14291da177e4SLinus Torvalds } 14301da177e4SLinus Torvalds 14312209bcb1SRalf Baechle static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d) 14321da177e4SLinus Torvalds { 14331da177e4SLinus Torvalds return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); 14341da177e4SLinus Torvalds } 14351da177e4SLinus Torvalds 14362209bcb1SRalf Baechle static union ieee754sp fpemu_sp_recip(union ieee754sp s) 14371da177e4SLinus Torvalds { 14381da177e4SLinus Torvalds return ieee754sp_div(ieee754sp_one(0), s); 14391da177e4SLinus Torvalds } 14401da177e4SLinus Torvalds 14412209bcb1SRalf Baechle static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s) 14421da177e4SLinus Torvalds { 14431da177e4SLinus Torvalds return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); 14441da177e4SLinus Torvalds } 14451da177e4SLinus Torvalds 14461da177e4SLinus Torvalds DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, ); 14471da177e4SLinus Torvalds DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, ); 14481da177e4SLinus Torvalds DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); 14491da177e4SLinus Torvalds DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); 14501da177e4SLinus Torvalds DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, ); 14511da177e4SLinus Torvalds DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); 14521da177e4SLinus Torvalds DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); 14531da177e4SLinus Torvalds DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); 14541da177e4SLinus Torvalds 1455eae89076SAtsushi Nemoto static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 1456515b029dSDavid Daney mips_instruction ir, void *__user *fault_addr) 14571da177e4SLinus Torvalds { 14581da177e4SLinus Torvalds unsigned rcsr = 0; /* resulting csr */ 14591da177e4SLinus Torvalds 1460b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(cp1xops); 14611da177e4SLinus Torvalds 14621da177e4SLinus Torvalds switch (MIPSInst_FMA_FFMT(ir)) { 14631da177e4SLinus Torvalds case s_fmt:{ /* 0 */ 14641da177e4SLinus Torvalds 14652209bcb1SRalf Baechle union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); 14662209bcb1SRalf Baechle union ieee754sp fd, fr, fs, ft; 14673fccc015SRalf Baechle u32 __user *va; 14681da177e4SLinus Torvalds u32 val; 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 14711da177e4SLinus Torvalds case lwxc1_op: 14723fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 14731da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 14741da177e4SLinus Torvalds 1475b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1476515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u32))) { 1477b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1478515b029dSDavid Daney *fault_addr = va; 14791da177e4SLinus Torvalds return SIGBUS; 14801da177e4SLinus Torvalds } 1481515b029dSDavid Daney if (__get_user(val, va)) { 1482515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1483515b029dSDavid Daney *fault_addr = va; 1484515b029dSDavid Daney return SIGSEGV; 1485515b029dSDavid Daney } 14861da177e4SLinus Torvalds SITOREG(val, MIPSInst_FD(ir)); 14871da177e4SLinus Torvalds break; 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds case swxc1_op: 14903fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 14911da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 14921da177e4SLinus Torvalds 1493b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds SIFROMREG(val, MIPSInst_FS(ir)); 1496515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { 1497515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1498515b029dSDavid Daney *fault_addr = va; 1499515b029dSDavid Daney return SIGBUS; 1500515b029dSDavid Daney } 15011da177e4SLinus Torvalds if (put_user(val, va)) { 1502b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1503515b029dSDavid Daney *fault_addr = va; 1504515b029dSDavid Daney return SIGSEGV; 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds break; 15071da177e4SLinus Torvalds 15081da177e4SLinus Torvalds case madd_s_op: 15091da177e4SLinus Torvalds handler = fpemu_sp_madd; 15101da177e4SLinus Torvalds goto scoptop; 15111da177e4SLinus Torvalds case msub_s_op: 15121da177e4SLinus Torvalds handler = fpemu_sp_msub; 15131da177e4SLinus Torvalds goto scoptop; 15141da177e4SLinus Torvalds case nmadd_s_op: 15151da177e4SLinus Torvalds handler = fpemu_sp_nmadd; 15161da177e4SLinus Torvalds goto scoptop; 15171da177e4SLinus Torvalds case nmsub_s_op: 15181da177e4SLinus Torvalds handler = fpemu_sp_nmsub; 15191da177e4SLinus Torvalds goto scoptop; 15201da177e4SLinus Torvalds 15211da177e4SLinus Torvalds scoptop: 15221da177e4SLinus Torvalds SPFROMREG(fr, MIPSInst_FR(ir)); 15231da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 15241da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 15251da177e4SLinus Torvalds fd = (*handler) (fr, fs, ft); 15261da177e4SLinus Torvalds SPTOREG(fd, MIPSInst_FD(ir)); 15271da177e4SLinus Torvalds 15281da177e4SLinus Torvalds copcsr: 1529c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INEXACT)) { 1530c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_inexact); 15311da177e4SLinus Torvalds rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 1532c4103526SDeng-Cheng Zhu } 1533c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_UNDERFLOW)) { 1534c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_underflow); 15351da177e4SLinus Torvalds rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 1536c4103526SDeng-Cheng Zhu } 1537c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_OVERFLOW)) { 1538c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_overflow); 15391da177e4SLinus Torvalds rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 1540c4103526SDeng-Cheng Zhu } 1541c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { 1542c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); 15431da177e4SLinus Torvalds rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 1544c4103526SDeng-Cheng Zhu } 15451da177e4SLinus Torvalds 15461da177e4SLinus Torvalds ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 15471da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 15483f7cac41SRalf Baechle /*printk ("SIGFPE: FPU csr = %08x\n", 15491da177e4SLinus Torvalds ctx->fcr31); */ 15501da177e4SLinus Torvalds return SIGFPE; 15511da177e4SLinus Torvalds } 15521da177e4SLinus Torvalds 15531da177e4SLinus Torvalds break; 15541da177e4SLinus Torvalds 15551da177e4SLinus Torvalds default: 15561da177e4SLinus Torvalds return SIGILL; 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds break; 15591da177e4SLinus Torvalds } 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds case d_fmt:{ /* 1 */ 15622209bcb1SRalf Baechle union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); 15632209bcb1SRalf Baechle union ieee754dp fd, fr, fs, ft; 15643fccc015SRalf Baechle u64 __user *va; 15651da177e4SLinus Torvalds u64 val; 15661da177e4SLinus Torvalds 15671da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 15681da177e4SLinus Torvalds case ldxc1_op: 15693fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 15701da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 15711da177e4SLinus Torvalds 1572b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1573515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u64))) { 1574b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1575515b029dSDavid Daney *fault_addr = va; 15761da177e4SLinus Torvalds return SIGBUS; 15771da177e4SLinus Torvalds } 1578515b029dSDavid Daney if (__get_user(val, va)) { 1579515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1580515b029dSDavid Daney *fault_addr = va; 1581515b029dSDavid Daney return SIGSEGV; 1582515b029dSDavid Daney } 15831da177e4SLinus Torvalds DITOREG(val, MIPSInst_FD(ir)); 15841da177e4SLinus Torvalds break; 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds case sdxc1_op: 15873fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 15881da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 15891da177e4SLinus Torvalds 1590b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 15911da177e4SLinus Torvalds DIFROMREG(val, MIPSInst_FS(ir)); 1592515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { 1593b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1594515b029dSDavid Daney *fault_addr = va; 15951da177e4SLinus Torvalds return SIGBUS; 15961da177e4SLinus Torvalds } 1597515b029dSDavid Daney if (__put_user(val, va)) { 1598515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1599515b029dSDavid Daney *fault_addr = va; 1600515b029dSDavid Daney return SIGSEGV; 1601515b029dSDavid Daney } 16021da177e4SLinus Torvalds break; 16031da177e4SLinus Torvalds 16041da177e4SLinus Torvalds case madd_d_op: 16051da177e4SLinus Torvalds handler = fpemu_dp_madd; 16061da177e4SLinus Torvalds goto dcoptop; 16071da177e4SLinus Torvalds case msub_d_op: 16081da177e4SLinus Torvalds handler = fpemu_dp_msub; 16091da177e4SLinus Torvalds goto dcoptop; 16101da177e4SLinus Torvalds case nmadd_d_op: 16111da177e4SLinus Torvalds handler = fpemu_dp_nmadd; 16121da177e4SLinus Torvalds goto dcoptop; 16131da177e4SLinus Torvalds case nmsub_d_op: 16141da177e4SLinus Torvalds handler = fpemu_dp_nmsub; 16151da177e4SLinus Torvalds goto dcoptop; 16161da177e4SLinus Torvalds 16171da177e4SLinus Torvalds dcoptop: 16181da177e4SLinus Torvalds DPFROMREG(fr, MIPSInst_FR(ir)); 16191da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 16201da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 16211da177e4SLinus Torvalds fd = (*handler) (fr, fs, ft); 16221da177e4SLinus Torvalds DPTOREG(fd, MIPSInst_FD(ir)); 16231da177e4SLinus Torvalds goto copcsr; 16241da177e4SLinus Torvalds 16251da177e4SLinus Torvalds default: 16261da177e4SLinus Torvalds return SIGILL; 16271da177e4SLinus Torvalds } 16281da177e4SLinus Torvalds break; 16291da177e4SLinus Torvalds } 16301da177e4SLinus Torvalds 163151061b88SDeng-Cheng Zhu case 0x3: 163251061b88SDeng-Cheng Zhu if (MIPSInst_FUNC(ir) != pfetch_op) 16331da177e4SLinus Torvalds return SIGILL; 163451061b88SDeng-Cheng Zhu 16351da177e4SLinus Torvalds /* ignore prefx operation */ 16361da177e4SLinus Torvalds break; 16371da177e4SLinus Torvalds 16381da177e4SLinus Torvalds default: 16391da177e4SLinus Torvalds return SIGILL; 16401da177e4SLinus Torvalds } 16411da177e4SLinus Torvalds 16421da177e4SLinus Torvalds return 0; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds /* 16481da177e4SLinus Torvalds * Emulate a single COP1 arithmetic instruction. 16491da177e4SLinus Torvalds */ 1650eae89076SAtsushi Nemoto static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 16511da177e4SLinus Torvalds mips_instruction ir) 16521da177e4SLinus Torvalds { 16531da177e4SLinus Torvalds int rfmt; /* resulting format */ 16541da177e4SLinus Torvalds unsigned rcsr = 0; /* resulting csr */ 16553f7cac41SRalf Baechle unsigned int oldrm; 16563f7cac41SRalf Baechle unsigned int cbit; 16571da177e4SLinus Torvalds unsigned cond; 16581da177e4SLinus Torvalds union { 16592209bcb1SRalf Baechle union ieee754dp d; 16602209bcb1SRalf Baechle union ieee754sp s; 16611da177e4SLinus Torvalds int w; 16621da177e4SLinus Torvalds s64 l; 16631da177e4SLinus Torvalds } rv; /* resulting value */ 16643f7cac41SRalf Baechle u64 bits; 16651da177e4SLinus Torvalds 1666b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(cp1ops); 16671da177e4SLinus Torvalds switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { 16681da177e4SLinus Torvalds case s_fmt: { /* 0 */ 16691da177e4SLinus Torvalds union { 16702209bcb1SRalf Baechle union ieee754sp(*b) (union ieee754sp, union ieee754sp); 16712209bcb1SRalf Baechle union ieee754sp(*u) (union ieee754sp); 16721da177e4SLinus Torvalds } handler; 16733f7cac41SRalf Baechle union ieee754sp fs, ft; 16741da177e4SLinus Torvalds 16751da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 16761da177e4SLinus Torvalds /* binary ops */ 16771da177e4SLinus Torvalds case fadd_op: 16781da177e4SLinus Torvalds handler.b = ieee754sp_add; 16791da177e4SLinus Torvalds goto scopbop; 16801da177e4SLinus Torvalds case fsub_op: 16811da177e4SLinus Torvalds handler.b = ieee754sp_sub; 16821da177e4SLinus Torvalds goto scopbop; 16831da177e4SLinus Torvalds case fmul_op: 16841da177e4SLinus Torvalds handler.b = ieee754sp_mul; 16851da177e4SLinus Torvalds goto scopbop; 16861da177e4SLinus Torvalds case fdiv_op: 16871da177e4SLinus Torvalds handler.b = ieee754sp_div; 16881da177e4SLinus Torvalds goto scopbop; 16891da177e4SLinus Torvalds 16901da177e4SLinus Torvalds /* unary ops */ 16911da177e4SLinus Torvalds case fsqrt_op: 16922d83fea7SMaciej W. Rozycki if (!cpu_has_mips_2_3_4_5_r) 169308a07904SRalf Baechle return SIGILL; 169408a07904SRalf Baechle 16951da177e4SLinus Torvalds handler.u = ieee754sp_sqrt; 16961da177e4SLinus Torvalds goto scopuop; 16973f7cac41SRalf Baechle 169808a07904SRalf Baechle /* 169908a07904SRalf Baechle * Note that on some MIPS IV implementations such as the 170008a07904SRalf Baechle * R5000 and R8000 the FSQRT and FRECIP instructions do not 170108a07904SRalf Baechle * achieve full IEEE-754 accuracy - however this emulator does. 170208a07904SRalf Baechle */ 17031da177e4SLinus Torvalds case frsqrt_op: 17042d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 170508a07904SRalf Baechle return SIGILL; 170608a07904SRalf Baechle 17071da177e4SLinus Torvalds handler.u = fpemu_sp_rsqrt; 17081da177e4SLinus Torvalds goto scopuop; 17093f7cac41SRalf Baechle 17101da177e4SLinus Torvalds case frecip_op: 17112d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 171208a07904SRalf Baechle return SIGILL; 171308a07904SRalf Baechle 17141da177e4SLinus Torvalds handler.u = fpemu_sp_recip; 17151da177e4SLinus Torvalds goto scopuop; 171608a07904SRalf Baechle 17171da177e4SLinus Torvalds case fmovc_op: 171808a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 171908a07904SRalf Baechle return SIGILL; 172008a07904SRalf Baechle 17211da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 17221da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) != 17231da177e4SLinus Torvalds ((MIPSInst_FT(ir) & 1) != 0)) 17241da177e4SLinus Torvalds return 0; 17251da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 17261da177e4SLinus Torvalds break; 17273f7cac41SRalf Baechle 17281da177e4SLinus Torvalds case fmovz_op: 172908a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 173008a07904SRalf Baechle return SIGILL; 173108a07904SRalf Baechle 17321da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] != 0) 17331da177e4SLinus Torvalds return 0; 17341da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 17351da177e4SLinus Torvalds break; 17363f7cac41SRalf Baechle 17371da177e4SLinus Torvalds case fmovn_op: 173808a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 173908a07904SRalf Baechle return SIGILL; 174008a07904SRalf Baechle 17411da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] == 0) 17421da177e4SLinus Torvalds return 0; 17431da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 17441da177e4SLinus Torvalds break; 17453f7cac41SRalf Baechle 174667613f02SMarkos Chandras case fseleqz_op: 174767613f02SMarkos Chandras if (!cpu_has_mips_r6) 174867613f02SMarkos Chandras return SIGILL; 174967613f02SMarkos Chandras 175067613f02SMarkos Chandras SPFROMREG(rv.s, MIPSInst_FT(ir)); 175167613f02SMarkos Chandras if (rv.w & 0x1) 175267613f02SMarkos Chandras rv.w = 0; 175367613f02SMarkos Chandras else 175467613f02SMarkos Chandras SPFROMREG(rv.s, MIPSInst_FS(ir)); 175567613f02SMarkos Chandras break; 175667613f02SMarkos Chandras 1757130fe357SMarkos Chandras case fselnez_op: 1758130fe357SMarkos Chandras if (!cpu_has_mips_r6) 1759130fe357SMarkos Chandras return SIGILL; 1760130fe357SMarkos Chandras 1761130fe357SMarkos Chandras SPFROMREG(rv.s, MIPSInst_FT(ir)); 1762130fe357SMarkos Chandras if (rv.w & 0x1) 1763130fe357SMarkos Chandras SPFROMREG(rv.s, MIPSInst_FS(ir)); 1764130fe357SMarkos Chandras else 1765130fe357SMarkos Chandras rv.w = 0; 1766130fe357SMarkos Chandras break; 1767130fe357SMarkos Chandras 1768e24c3becSMarkos Chandras case fmaddf_op: { 1769e24c3becSMarkos Chandras union ieee754sp ft, fs, fd; 1770e24c3becSMarkos Chandras 1771e24c3becSMarkos Chandras if (!cpu_has_mips_r6) 1772e24c3becSMarkos Chandras return SIGILL; 1773e24c3becSMarkos Chandras 1774e24c3becSMarkos Chandras SPFROMREG(ft, MIPSInst_FT(ir)); 1775e24c3becSMarkos Chandras SPFROMREG(fs, MIPSInst_FS(ir)); 1776e24c3becSMarkos Chandras SPFROMREG(fd, MIPSInst_FD(ir)); 1777e24c3becSMarkos Chandras rv.s = ieee754sp_maddf(fd, fs, ft); 1778e24c3becSMarkos Chandras break; 1779e24c3becSMarkos Chandras } 1780e24c3becSMarkos Chandras 178183d43305SMarkos Chandras case fmsubf_op: { 178283d43305SMarkos Chandras union ieee754sp ft, fs, fd; 178383d43305SMarkos Chandras 178483d43305SMarkos Chandras if (!cpu_has_mips_r6) 178583d43305SMarkos Chandras return SIGILL; 178683d43305SMarkos Chandras 178783d43305SMarkos Chandras SPFROMREG(ft, MIPSInst_FT(ir)); 178883d43305SMarkos Chandras SPFROMREG(fs, MIPSInst_FS(ir)); 178983d43305SMarkos Chandras SPFROMREG(fd, MIPSInst_FD(ir)); 179083d43305SMarkos Chandras rv.s = ieee754sp_msubf(fd, fs, ft); 179183d43305SMarkos Chandras break; 179283d43305SMarkos Chandras } 179383d43305SMarkos Chandras 1794400bd2e4SMarkos Chandras case frint_op: { 1795400bd2e4SMarkos Chandras union ieee754sp fs; 1796400bd2e4SMarkos Chandras 1797400bd2e4SMarkos Chandras if (!cpu_has_mips_r6) 1798400bd2e4SMarkos Chandras return SIGILL; 1799400bd2e4SMarkos Chandras 1800400bd2e4SMarkos Chandras SPFROMREG(fs, MIPSInst_FS(ir)); 1801400bd2e4SMarkos Chandras rv.l = ieee754sp_tlong(fs); 1802400bd2e4SMarkos Chandras rv.s = ieee754sp_flong(rv.l); 1803400bd2e4SMarkos Chandras goto copcsr; 1804400bd2e4SMarkos Chandras } 1805400bd2e4SMarkos Chandras 1806*38db37baSMarkos Chandras case fclass_op: { 1807*38db37baSMarkos Chandras union ieee754sp fs; 1808*38db37baSMarkos Chandras 1809*38db37baSMarkos Chandras if (!cpu_has_mips_r6) 1810*38db37baSMarkos Chandras return SIGILL; 1811*38db37baSMarkos Chandras 1812*38db37baSMarkos Chandras SPFROMREG(fs, MIPSInst_FS(ir)); 1813*38db37baSMarkos Chandras rv.w = ieee754sp_2008class(fs); 1814*38db37baSMarkos Chandras rfmt = w_fmt; 1815*38db37baSMarkos Chandras break; 1816*38db37baSMarkos Chandras } 1817*38db37baSMarkos Chandras 18181da177e4SLinus Torvalds case fabs_op: 18191da177e4SLinus Torvalds handler.u = ieee754sp_abs; 18201da177e4SLinus Torvalds goto scopuop; 18213f7cac41SRalf Baechle 18221da177e4SLinus Torvalds case fneg_op: 18231da177e4SLinus Torvalds handler.u = ieee754sp_neg; 18241da177e4SLinus Torvalds goto scopuop; 18253f7cac41SRalf Baechle 18261da177e4SLinus Torvalds case fmov_op: 18271da177e4SLinus Torvalds /* an easy one */ 18281da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 18291da177e4SLinus Torvalds goto copcsr; 18301da177e4SLinus Torvalds 18311da177e4SLinus Torvalds /* binary op on handler */ 18321da177e4SLinus Torvalds scopbop: 18331da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 18341da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 18351da177e4SLinus Torvalds 18361da177e4SLinus Torvalds rv.s = (*handler.b) (fs, ft); 18371da177e4SLinus Torvalds goto copcsr; 18381da177e4SLinus Torvalds scopuop: 18391da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 18401da177e4SLinus Torvalds rv.s = (*handler.u) (fs); 18411da177e4SLinus Torvalds goto copcsr; 18421da177e4SLinus Torvalds copcsr: 1843c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INEXACT)) { 1844c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_inexact); 18451da177e4SLinus Torvalds rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 1846c4103526SDeng-Cheng Zhu } 1847c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_UNDERFLOW)) { 1848c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_underflow); 18491da177e4SLinus Torvalds rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 1850c4103526SDeng-Cheng Zhu } 1851c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_OVERFLOW)) { 1852c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_overflow); 18531da177e4SLinus Torvalds rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 1854c4103526SDeng-Cheng Zhu } 1855c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) { 1856c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_zerodiv); 18571da177e4SLinus Torvalds rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; 1858c4103526SDeng-Cheng Zhu } 1859c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { 1860c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); 18611da177e4SLinus Torvalds rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 1862c4103526SDeng-Cheng Zhu } 18631da177e4SLinus Torvalds break; 18641da177e4SLinus Torvalds 18651da177e4SLinus Torvalds /* unary conv ops */ 18661da177e4SLinus Torvalds case fcvts_op: 18671da177e4SLinus Torvalds return SIGILL; /* not defined */ 18681da177e4SLinus Torvalds 18693f7cac41SRalf Baechle case fcvtd_op: 18701da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 18711da177e4SLinus Torvalds rv.d = ieee754dp_fsp(fs); 18721da177e4SLinus Torvalds rfmt = d_fmt; 18731da177e4SLinus Torvalds goto copcsr; 18741da177e4SLinus Torvalds 18753f7cac41SRalf Baechle case fcvtw_op: 18761da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 18771da177e4SLinus Torvalds rv.w = ieee754sp_tint(fs); 18781da177e4SLinus Torvalds rfmt = w_fmt; 18791da177e4SLinus Torvalds goto copcsr; 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds case fround_op: 18821da177e4SLinus Torvalds case ftrunc_op: 18831da177e4SLinus Torvalds case fceil_op: 18843f7cac41SRalf Baechle case ffloor_op: 18852d83fea7SMaciej W. Rozycki if (!cpu_has_mips_2_3_4_5_r) 188608a07904SRalf Baechle return SIGILL; 188708a07904SRalf Baechle 18883f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 18891da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 18902cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 18911da177e4SLinus Torvalds rv.w = ieee754sp_tint(fs); 18921da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 18931da177e4SLinus Torvalds rfmt = w_fmt; 18941da177e4SLinus Torvalds goto copcsr; 18951da177e4SLinus Torvalds 18963f7cac41SRalf Baechle case fcvtl_op: 18972d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 189808a07904SRalf Baechle return SIGILL; 189908a07904SRalf Baechle 19001da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 19011da177e4SLinus Torvalds rv.l = ieee754sp_tlong(fs); 19021da177e4SLinus Torvalds rfmt = l_fmt; 19031da177e4SLinus Torvalds goto copcsr; 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds case froundl_op: 19061da177e4SLinus Torvalds case ftruncl_op: 19071da177e4SLinus Torvalds case fceill_op: 19083f7cac41SRalf Baechle case ffloorl_op: 19092d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 191008a07904SRalf Baechle return SIGILL; 191108a07904SRalf Baechle 19123f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 19131da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 19142cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 19151da177e4SLinus Torvalds rv.l = ieee754sp_tlong(fs); 19161da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 19171da177e4SLinus Torvalds rfmt = l_fmt; 19181da177e4SLinus Torvalds goto copcsr; 19191da177e4SLinus Torvalds 19201da177e4SLinus Torvalds default: 1921f8c3c671SMarkos Chandras if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { 19221da177e4SLinus Torvalds unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 19232209bcb1SRalf Baechle union ieee754sp fs, ft; 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 19261da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 19271da177e4SLinus Torvalds rv.w = ieee754sp_cmp(fs, ft, 19281da177e4SLinus Torvalds cmptab[cmpop & 0x7], cmpop & 0x8); 19291da177e4SLinus Torvalds rfmt = -1; 19301da177e4SLinus Torvalds if ((cmpop & 0x8) && ieee754_cxtest 19311da177e4SLinus Torvalds (IEEE754_INVALID_OPERATION)) 19321da177e4SLinus Torvalds rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 19331da177e4SLinus Torvalds else 19341da177e4SLinus Torvalds goto copcsr; 19351da177e4SLinus Torvalds 19363f7cac41SRalf Baechle } else 19371da177e4SLinus Torvalds return SIGILL; 19381da177e4SLinus Torvalds break; 19391da177e4SLinus Torvalds } 19401da177e4SLinus Torvalds break; 19411da177e4SLinus Torvalds } 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds case d_fmt: { 19443f7cac41SRalf Baechle union ieee754dp fs, ft; 19451da177e4SLinus Torvalds union { 19462209bcb1SRalf Baechle union ieee754dp(*b) (union ieee754dp, union ieee754dp); 19472209bcb1SRalf Baechle union ieee754dp(*u) (union ieee754dp); 19481da177e4SLinus Torvalds } handler; 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 19511da177e4SLinus Torvalds /* binary ops */ 19521da177e4SLinus Torvalds case fadd_op: 19531da177e4SLinus Torvalds handler.b = ieee754dp_add; 19541da177e4SLinus Torvalds goto dcopbop; 19551da177e4SLinus Torvalds case fsub_op: 19561da177e4SLinus Torvalds handler.b = ieee754dp_sub; 19571da177e4SLinus Torvalds goto dcopbop; 19581da177e4SLinus Torvalds case fmul_op: 19591da177e4SLinus Torvalds handler.b = ieee754dp_mul; 19601da177e4SLinus Torvalds goto dcopbop; 19611da177e4SLinus Torvalds case fdiv_op: 19621da177e4SLinus Torvalds handler.b = ieee754dp_div; 19631da177e4SLinus Torvalds goto dcopbop; 19641da177e4SLinus Torvalds 19651da177e4SLinus Torvalds /* unary ops */ 19661da177e4SLinus Torvalds case fsqrt_op: 196708a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5_r) 196808a07904SRalf Baechle return SIGILL; 196908a07904SRalf Baechle 19701da177e4SLinus Torvalds handler.u = ieee754dp_sqrt; 19711da177e4SLinus Torvalds goto dcopuop; 197208a07904SRalf Baechle /* 197308a07904SRalf Baechle * Note that on some MIPS IV implementations such as the 197408a07904SRalf Baechle * R5000 and R8000 the FSQRT and FRECIP instructions do not 197508a07904SRalf Baechle * achieve full IEEE-754 accuracy - however this emulator does. 197608a07904SRalf Baechle */ 19771da177e4SLinus Torvalds case frsqrt_op: 19782d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 197908a07904SRalf Baechle return SIGILL; 198008a07904SRalf Baechle 19811da177e4SLinus Torvalds handler.u = fpemu_dp_rsqrt; 19821da177e4SLinus Torvalds goto dcopuop; 19831da177e4SLinus Torvalds case frecip_op: 19842d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 198508a07904SRalf Baechle return SIGILL; 198608a07904SRalf Baechle 19871da177e4SLinus Torvalds handler.u = fpemu_dp_recip; 19881da177e4SLinus Torvalds goto dcopuop; 19891da177e4SLinus Torvalds case fmovc_op: 199008a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 199108a07904SRalf Baechle return SIGILL; 199208a07904SRalf Baechle 19931da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 19941da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) != 19951da177e4SLinus Torvalds ((MIPSInst_FT(ir) & 1) != 0)) 19961da177e4SLinus Torvalds return 0; 19971da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 19981da177e4SLinus Torvalds break; 19991da177e4SLinus Torvalds case fmovz_op: 200008a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 200108a07904SRalf Baechle return SIGILL; 200208a07904SRalf Baechle 20031da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] != 0) 20041da177e4SLinus Torvalds return 0; 20051da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 20061da177e4SLinus Torvalds break; 20071da177e4SLinus Torvalds case fmovn_op: 200808a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 200908a07904SRalf Baechle return SIGILL; 201008a07904SRalf Baechle 20111da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] == 0) 20121da177e4SLinus Torvalds return 0; 20131da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 20141da177e4SLinus Torvalds break; 201567613f02SMarkos Chandras 201667613f02SMarkos Chandras case fseleqz_op: 201767613f02SMarkos Chandras if (!cpu_has_mips_r6) 201867613f02SMarkos Chandras return SIGILL; 201967613f02SMarkos Chandras 202067613f02SMarkos Chandras DPFROMREG(rv.d, MIPSInst_FT(ir)); 202167613f02SMarkos Chandras if (rv.l & 0x1) 202267613f02SMarkos Chandras rv.l = 0; 202367613f02SMarkos Chandras else 202467613f02SMarkos Chandras DPFROMREG(rv.d, MIPSInst_FS(ir)); 202567613f02SMarkos Chandras break; 202667613f02SMarkos Chandras 2027130fe357SMarkos Chandras case fselnez_op: 2028130fe357SMarkos Chandras if (!cpu_has_mips_r6) 2029130fe357SMarkos Chandras return SIGILL; 2030130fe357SMarkos Chandras 2031130fe357SMarkos Chandras DPFROMREG(rv.d, MIPSInst_FT(ir)); 2032130fe357SMarkos Chandras if (rv.l & 0x1) 2033130fe357SMarkos Chandras DPFROMREG(rv.d, MIPSInst_FS(ir)); 2034130fe357SMarkos Chandras else 2035130fe357SMarkos Chandras rv.l = 0; 2036130fe357SMarkos Chandras break; 2037130fe357SMarkos Chandras 2038e24c3becSMarkos Chandras case fmaddf_op: { 2039e24c3becSMarkos Chandras union ieee754dp ft, fs, fd; 2040e24c3becSMarkos Chandras 2041e24c3becSMarkos Chandras if (!cpu_has_mips_r6) 2042e24c3becSMarkos Chandras return SIGILL; 2043e24c3becSMarkos Chandras 2044e24c3becSMarkos Chandras DPFROMREG(ft, MIPSInst_FT(ir)); 2045e24c3becSMarkos Chandras DPFROMREG(fs, MIPSInst_FS(ir)); 2046e24c3becSMarkos Chandras DPFROMREG(fd, MIPSInst_FD(ir)); 2047e24c3becSMarkos Chandras rv.d = ieee754dp_maddf(fd, fs, ft); 2048e24c3becSMarkos Chandras break; 2049e24c3becSMarkos Chandras } 2050e24c3becSMarkos Chandras 205183d43305SMarkos Chandras case fmsubf_op: { 205283d43305SMarkos Chandras union ieee754dp ft, fs, fd; 205383d43305SMarkos Chandras 205483d43305SMarkos Chandras if (!cpu_has_mips_r6) 205583d43305SMarkos Chandras return SIGILL; 205683d43305SMarkos Chandras 205783d43305SMarkos Chandras DPFROMREG(ft, MIPSInst_FT(ir)); 205883d43305SMarkos Chandras DPFROMREG(fs, MIPSInst_FS(ir)); 205983d43305SMarkos Chandras DPFROMREG(fd, MIPSInst_FD(ir)); 206083d43305SMarkos Chandras rv.d = ieee754dp_msubf(fd, fs, ft); 206183d43305SMarkos Chandras break; 206283d43305SMarkos Chandras } 206383d43305SMarkos Chandras 2064400bd2e4SMarkos Chandras case frint_op: { 2065400bd2e4SMarkos Chandras union ieee754dp fs; 2066400bd2e4SMarkos Chandras 2067400bd2e4SMarkos Chandras if (!cpu_has_mips_r6) 2068400bd2e4SMarkos Chandras return SIGILL; 2069400bd2e4SMarkos Chandras 2070400bd2e4SMarkos Chandras DPFROMREG(fs, MIPSInst_FS(ir)); 2071400bd2e4SMarkos Chandras rv.l = ieee754dp_tlong(fs); 2072400bd2e4SMarkos Chandras rv.d = ieee754dp_flong(rv.l); 2073400bd2e4SMarkos Chandras goto copcsr; 2074400bd2e4SMarkos Chandras } 2075400bd2e4SMarkos Chandras 2076*38db37baSMarkos Chandras case fclass_op: { 2077*38db37baSMarkos Chandras union ieee754dp fs; 2078*38db37baSMarkos Chandras 2079*38db37baSMarkos Chandras if (!cpu_has_mips_r6) 2080*38db37baSMarkos Chandras return SIGILL; 2081*38db37baSMarkos Chandras 2082*38db37baSMarkos Chandras DPFROMREG(fs, MIPSInst_FS(ir)); 2083*38db37baSMarkos Chandras rv.w = ieee754dp_2008class(fs); 2084*38db37baSMarkos Chandras rfmt = w_fmt; 2085*38db37baSMarkos Chandras break; 2086*38db37baSMarkos Chandras } 2087*38db37baSMarkos Chandras 20881da177e4SLinus Torvalds case fabs_op: 20891da177e4SLinus Torvalds handler.u = ieee754dp_abs; 20901da177e4SLinus Torvalds goto dcopuop; 20911da177e4SLinus Torvalds 20921da177e4SLinus Torvalds case fneg_op: 20931da177e4SLinus Torvalds handler.u = ieee754dp_neg; 20941da177e4SLinus Torvalds goto dcopuop; 20951da177e4SLinus Torvalds 20961da177e4SLinus Torvalds case fmov_op: 20971da177e4SLinus Torvalds /* an easy one */ 20981da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 20991da177e4SLinus Torvalds goto copcsr; 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds /* binary op on handler */ 21023f7cac41SRalf Baechle dcopbop: 21031da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21041da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds rv.d = (*handler.b) (fs, ft); 21071da177e4SLinus Torvalds goto copcsr; 21083f7cac41SRalf Baechle dcopuop: 21091da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21101da177e4SLinus Torvalds rv.d = (*handler.u) (fs); 21111da177e4SLinus Torvalds goto copcsr; 21121da177e4SLinus Torvalds 21133f7cac41SRalf Baechle /* 21143f7cac41SRalf Baechle * unary conv ops 21153f7cac41SRalf Baechle */ 21163f7cac41SRalf Baechle case fcvts_op: 21171da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21181da177e4SLinus Torvalds rv.s = ieee754sp_fdp(fs); 21191da177e4SLinus Torvalds rfmt = s_fmt; 21201da177e4SLinus Torvalds goto copcsr; 21213f7cac41SRalf Baechle 21221da177e4SLinus Torvalds case fcvtd_op: 21231da177e4SLinus Torvalds return SIGILL; /* not defined */ 21241da177e4SLinus Torvalds 21253f7cac41SRalf Baechle case fcvtw_op: 21261da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21271da177e4SLinus Torvalds rv.w = ieee754dp_tint(fs); /* wrong */ 21281da177e4SLinus Torvalds rfmt = w_fmt; 21291da177e4SLinus Torvalds goto copcsr; 21301da177e4SLinus Torvalds 21311da177e4SLinus Torvalds case fround_op: 21321da177e4SLinus Torvalds case ftrunc_op: 21331da177e4SLinus Torvalds case fceil_op: 21343f7cac41SRalf Baechle case ffloor_op: 213508a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5_r) 213608a07904SRalf Baechle return SIGILL; 213708a07904SRalf Baechle 21383f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 21391da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21402cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 21411da177e4SLinus Torvalds rv.w = ieee754dp_tint(fs); 21421da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 21431da177e4SLinus Torvalds rfmt = w_fmt; 21441da177e4SLinus Torvalds goto copcsr; 21451da177e4SLinus Torvalds 21463f7cac41SRalf Baechle case fcvtl_op: 21472d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 214808a07904SRalf Baechle return SIGILL; 214908a07904SRalf Baechle 21501da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21511da177e4SLinus Torvalds rv.l = ieee754dp_tlong(fs); 21521da177e4SLinus Torvalds rfmt = l_fmt; 21531da177e4SLinus Torvalds goto copcsr; 21541da177e4SLinus Torvalds 21551da177e4SLinus Torvalds case froundl_op: 21561da177e4SLinus Torvalds case ftruncl_op: 21571da177e4SLinus Torvalds case fceill_op: 21583f7cac41SRalf Baechle case ffloorl_op: 21592d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 216008a07904SRalf Baechle return SIGILL; 216108a07904SRalf Baechle 21623f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 21631da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21642cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 21651da177e4SLinus Torvalds rv.l = ieee754dp_tlong(fs); 21661da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 21671da177e4SLinus Torvalds rfmt = l_fmt; 21681da177e4SLinus Torvalds goto copcsr; 21691da177e4SLinus Torvalds 21701da177e4SLinus Torvalds default: 2171f8c3c671SMarkos Chandras if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { 21721da177e4SLinus Torvalds unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 21732209bcb1SRalf Baechle union ieee754dp fs, ft; 21741da177e4SLinus Torvalds 21751da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 21761da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 21771da177e4SLinus Torvalds rv.w = ieee754dp_cmp(fs, ft, 21781da177e4SLinus Torvalds cmptab[cmpop & 0x7], cmpop & 0x8); 21791da177e4SLinus Torvalds rfmt = -1; 21801da177e4SLinus Torvalds if ((cmpop & 0x8) 21811da177e4SLinus Torvalds && 21821da177e4SLinus Torvalds ieee754_cxtest 21831da177e4SLinus Torvalds (IEEE754_INVALID_OPERATION)) 21841da177e4SLinus Torvalds rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 21851da177e4SLinus Torvalds else 21861da177e4SLinus Torvalds goto copcsr; 21871da177e4SLinus Torvalds 21881da177e4SLinus Torvalds } 21891da177e4SLinus Torvalds else { 21901da177e4SLinus Torvalds return SIGILL; 21911da177e4SLinus Torvalds } 21921da177e4SLinus Torvalds break; 21931da177e4SLinus Torvalds } 21941da177e4SLinus Torvalds break; 2195bbdd8147SMarkos Chandras } 21961da177e4SLinus Torvalds 2197bbdd8147SMarkos Chandras case w_fmt: { 2198bbdd8147SMarkos Chandras union ieee754dp fs; 2199bbdd8147SMarkos Chandras 22001da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 22011da177e4SLinus Torvalds case fcvts_op: 22021da177e4SLinus Torvalds /* convert word to single precision real */ 22031da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 22041da177e4SLinus Torvalds rv.s = ieee754sp_fint(fs.bits); 22051da177e4SLinus Torvalds rfmt = s_fmt; 22061da177e4SLinus Torvalds goto copcsr; 22071da177e4SLinus Torvalds case fcvtd_op: 22081da177e4SLinus Torvalds /* convert word to double precision real */ 22091da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 22101da177e4SLinus Torvalds rv.d = ieee754dp_fint(fs.bits); 22111da177e4SLinus Torvalds rfmt = d_fmt; 22121da177e4SLinus Torvalds goto copcsr; 2213f8c3c671SMarkos Chandras default: { 2214f8c3c671SMarkos Chandras /* Emulating the new CMP.condn.fmt R6 instruction */ 2215f8c3c671SMarkos Chandras #define CMPOP_MASK 0x7 2216f8c3c671SMarkos Chandras #define SIGN_BIT (0x1 << 3) 2217f8c3c671SMarkos Chandras #define PREDICATE_BIT (0x1 << 4) 2218f8c3c671SMarkos Chandras 2219f8c3c671SMarkos Chandras int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; 2220f8c3c671SMarkos Chandras int sig = MIPSInst_FUNC(ir) & SIGN_BIT; 2221f8c3c671SMarkos Chandras union ieee754sp fs, ft; 2222f8c3c671SMarkos Chandras 2223f8c3c671SMarkos Chandras /* This is an R6 only instruction */ 2224f8c3c671SMarkos Chandras if (!cpu_has_mips_r6 || 2225f8c3c671SMarkos Chandras (MIPSInst_FUNC(ir) & 0x20)) 2226f8c3c671SMarkos Chandras return SIGILL; 2227f8c3c671SMarkos Chandras 2228f8c3c671SMarkos Chandras /* fmt is w_fmt for single precision so fix it */ 2229f8c3c671SMarkos Chandras rfmt = s_fmt; 2230f8c3c671SMarkos Chandras /* default to false */ 2231f8c3c671SMarkos Chandras rv.w = 0; 2232f8c3c671SMarkos Chandras 2233f8c3c671SMarkos Chandras /* CMP.condn.S */ 2234f8c3c671SMarkos Chandras SPFROMREG(fs, MIPSInst_FS(ir)); 2235f8c3c671SMarkos Chandras SPFROMREG(ft, MIPSInst_FT(ir)); 2236f8c3c671SMarkos Chandras 2237f8c3c671SMarkos Chandras /* positive predicates */ 2238f8c3c671SMarkos Chandras if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { 2239f8c3c671SMarkos Chandras if (ieee754sp_cmp(fs, ft, cmptab[cmpop], 2240f8c3c671SMarkos Chandras sig)) 2241f8c3c671SMarkos Chandras rv.w = -1; /* true, all 1s */ 2242f8c3c671SMarkos Chandras if ((sig) && 2243f8c3c671SMarkos Chandras ieee754_cxtest(IEEE754_INVALID_OPERATION)) 2244f8c3c671SMarkos Chandras rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 2245f8c3c671SMarkos Chandras else 2246f8c3c671SMarkos Chandras goto copcsr; 2247f8c3c671SMarkos Chandras } else { 2248f8c3c671SMarkos Chandras /* negative predicates */ 2249f8c3c671SMarkos Chandras switch (cmpop) { 2250f8c3c671SMarkos Chandras case 1: 2251f8c3c671SMarkos Chandras case 2: 2252f8c3c671SMarkos Chandras case 3: 2253f8c3c671SMarkos Chandras if (ieee754sp_cmp(fs, ft, 2254f8c3c671SMarkos Chandras negative_cmptab[cmpop], 2255f8c3c671SMarkos Chandras sig)) 2256f8c3c671SMarkos Chandras rv.w = -1; /* true, all 1s */ 2257f8c3c671SMarkos Chandras if (sig && 2258f8c3c671SMarkos Chandras ieee754_cxtest(IEEE754_INVALID_OPERATION)) 2259f8c3c671SMarkos Chandras rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 2260f8c3c671SMarkos Chandras else 2261f8c3c671SMarkos Chandras goto copcsr; 2262f8c3c671SMarkos Chandras break; 22631da177e4SLinus Torvalds default: 2264f8c3c671SMarkos Chandras /* Reserved R6 ops */ 2265f8c3c671SMarkos Chandras pr_err("Reserved MIPS R6 CMP.condn.S operation\n"); 22661da177e4SLinus Torvalds return SIGILL; 22671da177e4SLinus Torvalds } 2268f8c3c671SMarkos Chandras } 22691da177e4SLinus Torvalds break; 22701da177e4SLinus Torvalds } 2271f8c3c671SMarkos Chandras } 2272f8c3c671SMarkos Chandras } 22731da177e4SLinus Torvalds 22743f7cac41SRalf Baechle case l_fmt: 227508a07904SRalf Baechle 22762d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 227708a07904SRalf Baechle return SIGILL; 227808a07904SRalf Baechle 2279bbd426f5SPaul Burton DIFROMREG(bits, MIPSInst_FS(ir)); 2280bbd426f5SPaul Burton 22811da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 22821da177e4SLinus Torvalds case fcvts_op: 22831da177e4SLinus Torvalds /* convert long to single precision real */ 2284bbd426f5SPaul Burton rv.s = ieee754sp_flong(bits); 22851da177e4SLinus Torvalds rfmt = s_fmt; 22861da177e4SLinus Torvalds goto copcsr; 22871da177e4SLinus Torvalds case fcvtd_op: 22881da177e4SLinus Torvalds /* convert long to double precision real */ 2289bbd426f5SPaul Burton rv.d = ieee754dp_flong(bits); 22901da177e4SLinus Torvalds rfmt = d_fmt; 22911da177e4SLinus Torvalds goto copcsr; 2292f8c3c671SMarkos Chandras default: { 2293f8c3c671SMarkos Chandras /* Emulating the new CMP.condn.fmt R6 instruction */ 2294f8c3c671SMarkos Chandras int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; 2295f8c3c671SMarkos Chandras int sig = MIPSInst_FUNC(ir) & SIGN_BIT; 2296f8c3c671SMarkos Chandras union ieee754dp fs, ft; 2297f8c3c671SMarkos Chandras 2298f8c3c671SMarkos Chandras if (!cpu_has_mips_r6 || 2299f8c3c671SMarkos Chandras (MIPSInst_FUNC(ir) & 0x20)) 2300f8c3c671SMarkos Chandras return SIGILL; 2301f8c3c671SMarkos Chandras 2302f8c3c671SMarkos Chandras /* fmt is l_fmt for double precision so fix it */ 2303f8c3c671SMarkos Chandras rfmt = d_fmt; 2304f8c3c671SMarkos Chandras /* default to false */ 2305f8c3c671SMarkos Chandras rv.l = 0; 2306f8c3c671SMarkos Chandras 2307f8c3c671SMarkos Chandras /* CMP.condn.D */ 2308f8c3c671SMarkos Chandras DPFROMREG(fs, MIPSInst_FS(ir)); 2309f8c3c671SMarkos Chandras DPFROMREG(ft, MIPSInst_FT(ir)); 2310f8c3c671SMarkos Chandras 2311f8c3c671SMarkos Chandras /* positive predicates */ 2312f8c3c671SMarkos Chandras if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { 2313f8c3c671SMarkos Chandras if (ieee754dp_cmp(fs, ft, 2314f8c3c671SMarkos Chandras cmptab[cmpop], sig)) 2315f8c3c671SMarkos Chandras rv.l = -1LL; /* true, all 1s */ 2316f8c3c671SMarkos Chandras if (sig && 2317f8c3c671SMarkos Chandras ieee754_cxtest(IEEE754_INVALID_OPERATION)) 2318f8c3c671SMarkos Chandras rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 2319f8c3c671SMarkos Chandras else 2320f8c3c671SMarkos Chandras goto copcsr; 2321f8c3c671SMarkos Chandras } else { 2322f8c3c671SMarkos Chandras /* negative predicates */ 2323f8c3c671SMarkos Chandras switch (cmpop) { 2324f8c3c671SMarkos Chandras case 1: 2325f8c3c671SMarkos Chandras case 2: 2326f8c3c671SMarkos Chandras case 3: 2327f8c3c671SMarkos Chandras if (ieee754dp_cmp(fs, ft, 2328f8c3c671SMarkos Chandras negative_cmptab[cmpop], 2329f8c3c671SMarkos Chandras sig)) 2330f8c3c671SMarkos Chandras rv.l = -1LL; /* true, all 1s */ 2331f8c3c671SMarkos Chandras if (sig && 2332f8c3c671SMarkos Chandras ieee754_cxtest(IEEE754_INVALID_OPERATION)) 2333f8c3c671SMarkos Chandras rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 2334f8c3c671SMarkos Chandras else 2335f8c3c671SMarkos Chandras goto copcsr; 2336f8c3c671SMarkos Chandras break; 23371da177e4SLinus Torvalds default: 2338f8c3c671SMarkos Chandras /* Reserved R6 ops */ 2339f8c3c671SMarkos Chandras pr_err("Reserved MIPS R6 CMP.condn.D operation\n"); 23401da177e4SLinus Torvalds return SIGILL; 23411da177e4SLinus Torvalds } 2342f8c3c671SMarkos Chandras } 23431da177e4SLinus Torvalds break; 2344f8c3c671SMarkos Chandras } 2345f8c3c671SMarkos Chandras } 23461da177e4SLinus Torvalds default: 23471da177e4SLinus Torvalds return SIGILL; 23481da177e4SLinus Torvalds } 23491da177e4SLinus Torvalds 23501da177e4SLinus Torvalds /* 23511da177e4SLinus Torvalds * Update the fpu CSR register for this operation. 23521da177e4SLinus Torvalds * If an exception is required, generate a tidy SIGFPE exception, 23531da177e4SLinus Torvalds * without updating the result register. 23541da177e4SLinus Torvalds * Note: cause exception bits do not accumulate, they are rewritten 23551da177e4SLinus Torvalds * for each op; only the flag/sticky bits accumulate. 23561da177e4SLinus Torvalds */ 23571da177e4SLinus Torvalds ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 23581da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 23593f7cac41SRalf Baechle /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */ 23601da177e4SLinus Torvalds return SIGFPE; 23611da177e4SLinus Torvalds } 23621da177e4SLinus Torvalds 23631da177e4SLinus Torvalds /* 23641da177e4SLinus Torvalds * Now we can safely write the result back to the register file. 23651da177e4SLinus Torvalds */ 23661da177e4SLinus Torvalds switch (rfmt) { 236708a07904SRalf Baechle case -1: 236808a07904SRalf Baechle 236908a07904SRalf Baechle if (cpu_has_mips_4_5_r) 2370c3b9b945SRob Kendrick cbit = fpucondbit[MIPSInst_FD(ir) >> 2]; 23711da177e4SLinus Torvalds else 237208a07904SRalf Baechle cbit = FPU_CSR_COND; 237308a07904SRalf Baechle if (rv.w) 237408a07904SRalf Baechle ctx->fcr31 |= cbit; 237508a07904SRalf Baechle else 237608a07904SRalf Baechle ctx->fcr31 &= ~cbit; 23771da177e4SLinus Torvalds break; 237808a07904SRalf Baechle 23791da177e4SLinus Torvalds case d_fmt: 23801da177e4SLinus Torvalds DPTOREG(rv.d, MIPSInst_FD(ir)); 23811da177e4SLinus Torvalds break; 23821da177e4SLinus Torvalds case s_fmt: 23831da177e4SLinus Torvalds SPTOREG(rv.s, MIPSInst_FD(ir)); 23841da177e4SLinus Torvalds break; 23851da177e4SLinus Torvalds case w_fmt: 23861da177e4SLinus Torvalds SITOREG(rv.w, MIPSInst_FD(ir)); 23871da177e4SLinus Torvalds break; 23881da177e4SLinus Torvalds case l_fmt: 23892d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 239008a07904SRalf Baechle return SIGILL; 239108a07904SRalf Baechle 23921da177e4SLinus Torvalds DITOREG(rv.l, MIPSInst_FD(ir)); 23931da177e4SLinus Torvalds break; 23941da177e4SLinus Torvalds default: 23951da177e4SLinus Torvalds return SIGILL; 23961da177e4SLinus Torvalds } 23971da177e4SLinus Torvalds 23981da177e4SLinus Torvalds return 0; 23991da177e4SLinus Torvalds } 24001da177e4SLinus Torvalds 2401e04582b7SAtsushi Nemoto int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 2402515b029dSDavid Daney int has_fpu, void *__user *fault_addr) 24031da177e4SLinus Torvalds { 2404333d1f67SRalf Baechle unsigned long oldepc, prevepc; 2405102cedc3SLeonid Yegoshin struct mm_decoded_insn dec_insn; 2406102cedc3SLeonid Yegoshin u16 instr[4]; 2407102cedc3SLeonid Yegoshin u16 *instr_ptr; 24081da177e4SLinus Torvalds int sig = 0; 24091da177e4SLinus Torvalds 24101da177e4SLinus Torvalds oldepc = xcp->cp0_epc; 24111da177e4SLinus Torvalds do { 24121da177e4SLinus Torvalds prevepc = xcp->cp0_epc; 24131da177e4SLinus Torvalds 2414102cedc3SLeonid Yegoshin if (get_isa16_mode(prevepc) && cpu_has_mmips) { 2415102cedc3SLeonid Yegoshin /* 2416102cedc3SLeonid Yegoshin * Get next 2 microMIPS instructions and convert them 2417102cedc3SLeonid Yegoshin * into 32-bit instructions. 2418102cedc3SLeonid Yegoshin */ 2419102cedc3SLeonid Yegoshin if ((get_user(instr[0], (u16 __user *)msk_isa16_mode(xcp->cp0_epc))) || 2420102cedc3SLeonid Yegoshin (get_user(instr[1], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 2))) || 2421102cedc3SLeonid Yegoshin (get_user(instr[2], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 4))) || 2422102cedc3SLeonid Yegoshin (get_user(instr[3], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 6)))) { 2423b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 24241da177e4SLinus Torvalds return SIGBUS; 24251da177e4SLinus Torvalds } 2426102cedc3SLeonid Yegoshin instr_ptr = instr; 2427102cedc3SLeonid Yegoshin 2428102cedc3SLeonid Yegoshin /* Get first instruction. */ 2429102cedc3SLeonid Yegoshin if (mm_insn_16bit(*instr_ptr)) { 2430102cedc3SLeonid Yegoshin /* Duplicate the half-word. */ 2431102cedc3SLeonid Yegoshin dec_insn.insn = (*instr_ptr << 16) | 2432102cedc3SLeonid Yegoshin (*instr_ptr); 2433102cedc3SLeonid Yegoshin /* 16-bit instruction. */ 2434102cedc3SLeonid Yegoshin dec_insn.pc_inc = 2; 2435102cedc3SLeonid Yegoshin instr_ptr += 1; 2436102cedc3SLeonid Yegoshin } else { 2437102cedc3SLeonid Yegoshin dec_insn.insn = (*instr_ptr << 16) | 2438102cedc3SLeonid Yegoshin *(instr_ptr+1); 2439102cedc3SLeonid Yegoshin /* 32-bit instruction. */ 2440102cedc3SLeonid Yegoshin dec_insn.pc_inc = 4; 2441102cedc3SLeonid Yegoshin instr_ptr += 2; 2442515b029dSDavid Daney } 2443102cedc3SLeonid Yegoshin /* Get second instruction. */ 2444102cedc3SLeonid Yegoshin if (mm_insn_16bit(*instr_ptr)) { 2445102cedc3SLeonid Yegoshin /* Duplicate the half-word. */ 2446102cedc3SLeonid Yegoshin dec_insn.next_insn = (*instr_ptr << 16) | 2447102cedc3SLeonid Yegoshin (*instr_ptr); 2448102cedc3SLeonid Yegoshin /* 16-bit instruction. */ 2449102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 2; 2450102cedc3SLeonid Yegoshin } else { 2451102cedc3SLeonid Yegoshin dec_insn.next_insn = (*instr_ptr << 16) | 2452102cedc3SLeonid Yegoshin *(instr_ptr+1); 2453102cedc3SLeonid Yegoshin /* 32-bit instruction. */ 2454102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 4; 2455102cedc3SLeonid Yegoshin } 2456102cedc3SLeonid Yegoshin dec_insn.micro_mips_mode = 1; 2457102cedc3SLeonid Yegoshin } else { 2458102cedc3SLeonid Yegoshin if ((get_user(dec_insn.insn, 2459102cedc3SLeonid Yegoshin (mips_instruction __user *) xcp->cp0_epc)) || 2460102cedc3SLeonid Yegoshin (get_user(dec_insn.next_insn, 2461102cedc3SLeonid Yegoshin (mips_instruction __user *)(xcp->cp0_epc+4)))) { 2462102cedc3SLeonid Yegoshin MIPS_FPU_EMU_INC_STATS(errors); 2463102cedc3SLeonid Yegoshin return SIGBUS; 2464102cedc3SLeonid Yegoshin } 2465102cedc3SLeonid Yegoshin dec_insn.pc_inc = 4; 2466102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 4; 2467102cedc3SLeonid Yegoshin dec_insn.micro_mips_mode = 0; 2468102cedc3SLeonid Yegoshin } 2469102cedc3SLeonid Yegoshin 2470102cedc3SLeonid Yegoshin if ((dec_insn.insn == 0) || 2471102cedc3SLeonid Yegoshin ((dec_insn.pc_inc == 2) && 2472102cedc3SLeonid Yegoshin ((dec_insn.insn & 0xffff) == MM_NOP16))) 2473102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; /* Skip NOPs */ 24741da177e4SLinus Torvalds else { 2475cd21dfcfSRalf Baechle /* 24762cfcf8a8SMaciej W. Rozycki * The 'ieee754_csr' is an alias of ctx->fcr31. 24772cfcf8a8SMaciej W. Rozycki * No need to copy ctx->fcr31 to ieee754_csr. 2478cd21dfcfSRalf Baechle */ 2479102cedc3SLeonid Yegoshin sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); 24801da177e4SLinus Torvalds } 24811da177e4SLinus Torvalds 2482e04582b7SAtsushi Nemoto if (has_fpu) 24831da177e4SLinus Torvalds break; 24841da177e4SLinus Torvalds if (sig) 24851da177e4SLinus Torvalds break; 24861da177e4SLinus Torvalds 24871da177e4SLinus Torvalds cond_resched(); 24881da177e4SLinus Torvalds } while (xcp->cp0_epc > prevepc); 24891da177e4SLinus Torvalds 24901da177e4SLinus Torvalds /* SIGILL indicates a non-fpu instruction */ 24911da177e4SLinus Torvalds if (sig == SIGILL && xcp->cp0_epc != oldepc) 24923f7cac41SRalf Baechle /* but if EPC has advanced, then ignore it */ 24931da177e4SLinus Torvalds sig = 0; 24941da177e4SLinus Torvalds 24951da177e4SLinus Torvalds return sig; 24961da177e4SLinus Torvalds } 2497