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 48cd8ee345SRalf Baechle #include <asm/processor.h> 491da177e4SLinus Torvalds #include <asm/fpu_emulator.h> 50102cedc3SLeonid Yegoshin #include <asm/fpu.h> 51b0a668fbSLeonid Yegoshin #include <asm/mips-r2-to-r6-emul.h> 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds #include "ieee754.h" 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /* Function which emulates a floating point instruction. */ 561da177e4SLinus Torvalds 57eae89076SAtsushi Nemoto static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, 581da177e4SLinus Torvalds mips_instruction); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds static int fpux_emu(struct pt_regs *, 61515b029dSDavid Daney struct mips_fpu_struct *, mips_instruction, void *__user *); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* Control registers */ 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds #define FPCREG_RID 0 /* $0 = revision id */ 661da177e4SLinus Torvalds #define FPCREG_CSR 31 /* $31 = csr */ 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* convert condition code register number to csr bit */ 69b0a668fbSLeonid Yegoshin const unsigned int fpucondbit[8] = { 701da177e4SLinus Torvalds FPU_CSR_COND0, 711da177e4SLinus Torvalds FPU_CSR_COND1, 721da177e4SLinus Torvalds FPU_CSR_COND2, 731da177e4SLinus Torvalds FPU_CSR_COND3, 741da177e4SLinus Torvalds FPU_CSR_COND4, 751da177e4SLinus Torvalds FPU_CSR_COND5, 761da177e4SLinus Torvalds FPU_CSR_COND6, 771da177e4SLinus Torvalds FPU_CSR_COND7 781da177e4SLinus Torvalds }; 791da177e4SLinus Torvalds 80102cedc3SLeonid Yegoshin /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ 81102cedc3SLeonid Yegoshin static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; 82102cedc3SLeonid Yegoshin static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; 83102cedc3SLeonid Yegoshin static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0}; 84102cedc3SLeonid Yegoshin static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0}; 85102cedc3SLeonid Yegoshin 86102cedc3SLeonid Yegoshin /* 87102cedc3SLeonid Yegoshin * This functions translates a 32-bit microMIPS instruction 88102cedc3SLeonid Yegoshin * into a 32-bit MIPS32 instruction. Returns 0 on success 89102cedc3SLeonid Yegoshin * and SIGILL otherwise. 90102cedc3SLeonid Yegoshin */ 91102cedc3SLeonid Yegoshin static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) 92102cedc3SLeonid Yegoshin { 93102cedc3SLeonid Yegoshin union mips_instruction insn = *insn_ptr; 94102cedc3SLeonid Yegoshin union mips_instruction mips32_insn = insn; 95102cedc3SLeonid Yegoshin int func, fmt, op; 96102cedc3SLeonid Yegoshin 97102cedc3SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 98102cedc3SLeonid Yegoshin case mm_ldc132_op: 99102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = ldc1_op; 100102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 101102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 102102cedc3SLeonid Yegoshin break; 103102cedc3SLeonid Yegoshin case mm_lwc132_op: 104102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = lwc1_op; 105102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 106102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 107102cedc3SLeonid Yegoshin break; 108102cedc3SLeonid Yegoshin case mm_sdc132_op: 109102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = sdc1_op; 110102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 111102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 112102cedc3SLeonid Yegoshin break; 113102cedc3SLeonid Yegoshin case mm_swc132_op: 114102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = swc1_op; 115102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 116102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 117102cedc3SLeonid Yegoshin break; 118102cedc3SLeonid Yegoshin case mm_pool32i_op: 119102cedc3SLeonid Yegoshin /* NOTE: offset is << by 1 if in microMIPS mode. */ 120102cedc3SLeonid Yegoshin if ((insn.mm_i_format.rt == mm_bc1f_op) || 121102cedc3SLeonid Yegoshin (insn.mm_i_format.rt == mm_bc1t_op)) { 122102cedc3SLeonid Yegoshin mips32_insn.fb_format.opcode = cop1_op; 123102cedc3SLeonid Yegoshin mips32_insn.fb_format.bc = bc_op; 124102cedc3SLeonid Yegoshin mips32_insn.fb_format.flag = 125102cedc3SLeonid Yegoshin (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0; 126102cedc3SLeonid Yegoshin } else 127102cedc3SLeonid Yegoshin return SIGILL; 128102cedc3SLeonid Yegoshin break; 129102cedc3SLeonid Yegoshin case mm_pool32f_op: 130102cedc3SLeonid Yegoshin switch (insn.mm_fp0_format.func) { 131102cedc3SLeonid Yegoshin case mm_32f_01_op: 132102cedc3SLeonid Yegoshin case mm_32f_11_op: 133102cedc3SLeonid Yegoshin case mm_32f_02_op: 134102cedc3SLeonid Yegoshin case mm_32f_12_op: 135102cedc3SLeonid Yegoshin case mm_32f_41_op: 136102cedc3SLeonid Yegoshin case mm_32f_51_op: 137102cedc3SLeonid Yegoshin case mm_32f_42_op: 138102cedc3SLeonid Yegoshin case mm_32f_52_op: 139102cedc3SLeonid Yegoshin op = insn.mm_fp0_format.func; 140102cedc3SLeonid Yegoshin if (op == mm_32f_01_op) 141102cedc3SLeonid Yegoshin func = madd_s_op; 142102cedc3SLeonid Yegoshin else if (op == mm_32f_11_op) 143102cedc3SLeonid Yegoshin func = madd_d_op; 144102cedc3SLeonid Yegoshin else if (op == mm_32f_02_op) 145102cedc3SLeonid Yegoshin func = nmadd_s_op; 146102cedc3SLeonid Yegoshin else if (op == mm_32f_12_op) 147102cedc3SLeonid Yegoshin func = nmadd_d_op; 148102cedc3SLeonid Yegoshin else if (op == mm_32f_41_op) 149102cedc3SLeonid Yegoshin func = msub_s_op; 150102cedc3SLeonid Yegoshin else if (op == mm_32f_51_op) 151102cedc3SLeonid Yegoshin func = msub_d_op; 152102cedc3SLeonid Yegoshin else if (op == mm_32f_42_op) 153102cedc3SLeonid Yegoshin func = nmsub_s_op; 154102cedc3SLeonid Yegoshin else 155102cedc3SLeonid Yegoshin func = nmsub_d_op; 156102cedc3SLeonid Yegoshin mips32_insn.fp6_format.opcode = cop1x_op; 157102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr; 158102cedc3SLeonid Yegoshin mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft; 159102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs; 160102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd; 161102cedc3SLeonid Yegoshin mips32_insn.fp6_format.func = func; 162102cedc3SLeonid Yegoshin break; 163102cedc3SLeonid Yegoshin case mm_32f_10_op: 164102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 165102cedc3SLeonid Yegoshin op = insn.mm_fp5_format.op & 0x7; 166102cedc3SLeonid Yegoshin if (op == mm_ldxc1_op) 167102cedc3SLeonid Yegoshin func = ldxc1_op; 168102cedc3SLeonid Yegoshin else if (op == mm_sdxc1_op) 169102cedc3SLeonid Yegoshin func = sdxc1_op; 170102cedc3SLeonid Yegoshin else if (op == mm_lwxc1_op) 171102cedc3SLeonid Yegoshin func = lwxc1_op; 172102cedc3SLeonid Yegoshin else if (op == mm_swxc1_op) 173102cedc3SLeonid Yegoshin func = swxc1_op; 174102cedc3SLeonid Yegoshin 175102cedc3SLeonid Yegoshin if (func != -1) { 176102cedc3SLeonid Yegoshin mips32_insn.r_format.opcode = cop1x_op; 177102cedc3SLeonid Yegoshin mips32_insn.r_format.rs = 178102cedc3SLeonid Yegoshin insn.mm_fp5_format.base; 179102cedc3SLeonid Yegoshin mips32_insn.r_format.rt = 180102cedc3SLeonid Yegoshin insn.mm_fp5_format.index; 181102cedc3SLeonid Yegoshin mips32_insn.r_format.rd = 0; 182102cedc3SLeonid Yegoshin mips32_insn.r_format.re = insn.mm_fp5_format.fd; 183102cedc3SLeonid Yegoshin mips32_insn.r_format.func = func; 184102cedc3SLeonid Yegoshin } else 185102cedc3SLeonid Yegoshin return SIGILL; 186102cedc3SLeonid Yegoshin break; 187102cedc3SLeonid Yegoshin case mm_32f_40_op: 188102cedc3SLeonid Yegoshin op = -1; /* Invalid */ 189102cedc3SLeonid Yegoshin if (insn.mm_fp2_format.op == mm_fmovt_op) 190102cedc3SLeonid Yegoshin op = 1; 191102cedc3SLeonid Yegoshin else if (insn.mm_fp2_format.op == mm_fmovf_op) 192102cedc3SLeonid Yegoshin op = 0; 193102cedc3SLeonid Yegoshin if (op != -1) { 194102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 195102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 196102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp2_format.fmt]; 197102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 198102cedc3SLeonid Yegoshin (insn.mm_fp2_format.cc<<2) + op; 199102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 200102cedc3SLeonid Yegoshin insn.mm_fp2_format.fs; 201102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 202102cedc3SLeonid Yegoshin insn.mm_fp2_format.fd; 203102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = fmovc_op; 204102cedc3SLeonid Yegoshin } else 205102cedc3SLeonid Yegoshin return SIGILL; 206102cedc3SLeonid Yegoshin break; 207102cedc3SLeonid Yegoshin case mm_32f_60_op: 208102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 209102cedc3SLeonid Yegoshin if (insn.mm_fp0_format.op == mm_fadd_op) 210102cedc3SLeonid Yegoshin func = fadd_op; 211102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fsub_op) 212102cedc3SLeonid Yegoshin func = fsub_op; 213102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fmul_op) 214102cedc3SLeonid Yegoshin func = fmul_op; 215102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fdiv_op) 216102cedc3SLeonid Yegoshin func = fdiv_op; 217102cedc3SLeonid Yegoshin if (func != -1) { 218102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 219102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 220102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp0_format.fmt]; 221102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 222102cedc3SLeonid Yegoshin insn.mm_fp0_format.ft; 223102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 224102cedc3SLeonid Yegoshin insn.mm_fp0_format.fs; 225102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 226102cedc3SLeonid Yegoshin insn.mm_fp0_format.fd; 227102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 228102cedc3SLeonid Yegoshin } else 229102cedc3SLeonid Yegoshin return SIGILL; 230102cedc3SLeonid Yegoshin break; 231102cedc3SLeonid Yegoshin case mm_32f_70_op: 232102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 233102cedc3SLeonid Yegoshin if (insn.mm_fp0_format.op == mm_fmovn_op) 234102cedc3SLeonid Yegoshin func = fmovn_op; 235102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fmovz_op) 236102cedc3SLeonid Yegoshin func = fmovz_op; 237102cedc3SLeonid Yegoshin if (func != -1) { 238102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 239102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 240102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp0_format.fmt]; 241102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 242102cedc3SLeonid Yegoshin insn.mm_fp0_format.ft; 243102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 244102cedc3SLeonid Yegoshin insn.mm_fp0_format.fs; 245102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 246102cedc3SLeonid Yegoshin insn.mm_fp0_format.fd; 247102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 248102cedc3SLeonid Yegoshin } else 249102cedc3SLeonid Yegoshin return SIGILL; 250102cedc3SLeonid Yegoshin break; 251102cedc3SLeonid Yegoshin case mm_32f_73_op: /* POOL32FXF */ 252102cedc3SLeonid Yegoshin switch (insn.mm_fp1_format.op) { 253102cedc3SLeonid Yegoshin case mm_movf0_op: 254102cedc3SLeonid Yegoshin case mm_movf1_op: 255102cedc3SLeonid Yegoshin case mm_movt0_op: 256102cedc3SLeonid Yegoshin case mm_movt1_op: 257102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 258102cedc3SLeonid Yegoshin mm_movf0_op) 259102cedc3SLeonid Yegoshin op = 0; 260102cedc3SLeonid Yegoshin else 261102cedc3SLeonid Yegoshin op = 1; 262102cedc3SLeonid Yegoshin mips32_insn.r_format.opcode = spec_op; 263102cedc3SLeonid Yegoshin mips32_insn.r_format.rs = insn.mm_fp4_format.fs; 264102cedc3SLeonid Yegoshin mips32_insn.r_format.rt = 265102cedc3SLeonid Yegoshin (insn.mm_fp4_format.cc << 2) + op; 266102cedc3SLeonid Yegoshin mips32_insn.r_format.rd = insn.mm_fp4_format.rt; 267102cedc3SLeonid Yegoshin mips32_insn.r_format.re = 0; 268102cedc3SLeonid Yegoshin mips32_insn.r_format.func = movc_op; 269102cedc3SLeonid Yegoshin break; 270102cedc3SLeonid Yegoshin case mm_fcvtd0_op: 271102cedc3SLeonid Yegoshin case mm_fcvtd1_op: 272102cedc3SLeonid Yegoshin case mm_fcvts0_op: 273102cedc3SLeonid Yegoshin case mm_fcvts1_op: 274102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 275102cedc3SLeonid Yegoshin mm_fcvtd0_op) { 276102cedc3SLeonid Yegoshin func = fcvtd_op; 277102cedc3SLeonid Yegoshin fmt = swl_format[insn.mm_fp3_format.fmt]; 278102cedc3SLeonid Yegoshin } else { 279102cedc3SLeonid Yegoshin func = fcvts_op; 280102cedc3SLeonid Yegoshin fmt = dwl_format[insn.mm_fp3_format.fmt]; 281102cedc3SLeonid Yegoshin } 282102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 283102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = fmt; 284102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 285102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 286102cedc3SLeonid Yegoshin insn.mm_fp3_format.fs; 287102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 288102cedc3SLeonid Yegoshin insn.mm_fp3_format.rt; 289102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 290102cedc3SLeonid Yegoshin break; 291102cedc3SLeonid Yegoshin case mm_fmov0_op: 292102cedc3SLeonid Yegoshin case mm_fmov1_op: 293102cedc3SLeonid Yegoshin case mm_fabs0_op: 294102cedc3SLeonid Yegoshin case mm_fabs1_op: 295102cedc3SLeonid Yegoshin case mm_fneg0_op: 296102cedc3SLeonid Yegoshin case mm_fneg1_op: 297102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 298102cedc3SLeonid Yegoshin mm_fmov0_op) 299102cedc3SLeonid Yegoshin func = fmov_op; 300102cedc3SLeonid Yegoshin else if ((insn.mm_fp1_format.op & 0x7f) == 301102cedc3SLeonid Yegoshin mm_fabs0_op) 302102cedc3SLeonid Yegoshin func = fabs_op; 303102cedc3SLeonid Yegoshin else 304102cedc3SLeonid Yegoshin func = fneg_op; 305102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 306102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 307102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp3_format.fmt]; 308102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 309102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 310102cedc3SLeonid Yegoshin insn.mm_fp3_format.fs; 311102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 312102cedc3SLeonid Yegoshin insn.mm_fp3_format.rt; 313102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 314102cedc3SLeonid Yegoshin break; 315102cedc3SLeonid Yegoshin case mm_ffloorl_op: 316102cedc3SLeonid Yegoshin case mm_ffloorw_op: 317102cedc3SLeonid Yegoshin case mm_fceill_op: 318102cedc3SLeonid Yegoshin case mm_fceilw_op: 319102cedc3SLeonid Yegoshin case mm_ftruncl_op: 320102cedc3SLeonid Yegoshin case mm_ftruncw_op: 321102cedc3SLeonid Yegoshin case mm_froundl_op: 322102cedc3SLeonid Yegoshin case mm_froundw_op: 323102cedc3SLeonid Yegoshin case mm_fcvtl_op: 324102cedc3SLeonid Yegoshin case mm_fcvtw_op: 325102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_ffloorl_op) 326102cedc3SLeonid Yegoshin func = ffloorl_op; 327102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ffloorw_op) 328102cedc3SLeonid Yegoshin func = ffloor_op; 329102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fceill_op) 330102cedc3SLeonid Yegoshin func = fceill_op; 331102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fceilw_op) 332102cedc3SLeonid Yegoshin func = fceil_op; 333102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ftruncl_op) 334102cedc3SLeonid Yegoshin func = ftruncl_op; 335102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ftruncw_op) 336102cedc3SLeonid Yegoshin func = ftrunc_op; 337102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_froundl_op) 338102cedc3SLeonid Yegoshin func = froundl_op; 339102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_froundw_op) 340102cedc3SLeonid Yegoshin func = fround_op; 341102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fcvtl_op) 342102cedc3SLeonid Yegoshin func = fcvtl_op; 343102cedc3SLeonid Yegoshin else 344102cedc3SLeonid Yegoshin func = fcvtw_op; 345102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 346102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 347102cedc3SLeonid Yegoshin sd_format[insn.mm_fp1_format.fmt]; 348102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 349102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 350102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 351102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 352102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 353102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 354102cedc3SLeonid Yegoshin break; 355102cedc3SLeonid Yegoshin case mm_frsqrt_op: 356102cedc3SLeonid Yegoshin case mm_fsqrt_op: 357102cedc3SLeonid Yegoshin case mm_frecip_op: 358102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_frsqrt_op) 359102cedc3SLeonid Yegoshin func = frsqrt_op; 360102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fsqrt_op) 361102cedc3SLeonid Yegoshin func = fsqrt_op; 362102cedc3SLeonid Yegoshin else 363102cedc3SLeonid Yegoshin func = frecip_op; 364102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 365102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 366102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp1_format.fmt]; 367102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 368102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 369102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 370102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 371102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 372102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 373102cedc3SLeonid Yegoshin break; 374102cedc3SLeonid Yegoshin case mm_mfc1_op: 375102cedc3SLeonid Yegoshin case mm_mtc1_op: 376102cedc3SLeonid Yegoshin case mm_cfc1_op: 377102cedc3SLeonid Yegoshin case mm_ctc1_op: 3789355e59cSSteven J. Hill case mm_mfhc1_op: 3799355e59cSSteven J. Hill case mm_mthc1_op: 380102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_mfc1_op) 381102cedc3SLeonid Yegoshin op = mfc_op; 382102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_mtc1_op) 383102cedc3SLeonid Yegoshin op = mtc_op; 384102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_cfc1_op) 385102cedc3SLeonid Yegoshin op = cfc_op; 3869355e59cSSteven J. Hill else if (insn.mm_fp1_format.op == mm_ctc1_op) 387102cedc3SLeonid Yegoshin op = ctc_op; 3889355e59cSSteven J. Hill else if (insn.mm_fp1_format.op == mm_mfhc1_op) 3899355e59cSSteven J. Hill op = mfhc_op; 3909355e59cSSteven J. Hill else 3919355e59cSSteven J. Hill op = mthc_op; 392102cedc3SLeonid Yegoshin mips32_insn.fp1_format.opcode = cop1_op; 393102cedc3SLeonid Yegoshin mips32_insn.fp1_format.op = op; 394102cedc3SLeonid Yegoshin mips32_insn.fp1_format.rt = 395102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 396102cedc3SLeonid Yegoshin mips32_insn.fp1_format.fs = 397102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 398102cedc3SLeonid Yegoshin mips32_insn.fp1_format.fd = 0; 399102cedc3SLeonid Yegoshin mips32_insn.fp1_format.func = 0; 400102cedc3SLeonid Yegoshin break; 401102cedc3SLeonid Yegoshin default: 402102cedc3SLeonid Yegoshin return SIGILL; 403102cedc3SLeonid Yegoshin } 404102cedc3SLeonid Yegoshin break; 405102cedc3SLeonid Yegoshin case mm_32f_74_op: /* c.cond.fmt */ 406102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 407102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 408102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp4_format.fmt]; 409102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt; 410102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs; 411102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2; 412102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = 413102cedc3SLeonid Yegoshin insn.mm_fp4_format.cond | MM_MIPS32_COND_FC; 414102cedc3SLeonid Yegoshin break; 415102cedc3SLeonid Yegoshin default: 416102cedc3SLeonid Yegoshin return SIGILL; 417102cedc3SLeonid Yegoshin } 418102cedc3SLeonid Yegoshin break; 419102cedc3SLeonid Yegoshin default: 420102cedc3SLeonid Yegoshin return SIGILL; 421102cedc3SLeonid Yegoshin } 422102cedc3SLeonid Yegoshin 423102cedc3SLeonid Yegoshin *insn_ptr = mips32_insn; 424102cedc3SLeonid Yegoshin return 0; 425102cedc3SLeonid Yegoshin } 426102cedc3SLeonid Yegoshin 4271da177e4SLinus Torvalds /* 4281da177e4SLinus Torvalds * Redundant with logic already in kernel/branch.c, 4291da177e4SLinus Torvalds * embedded in compute_return_epc. At some point, 4301da177e4SLinus Torvalds * a single subroutine should be used across both 4311da177e4SLinus Torvalds * modules. 4321da177e4SLinus Torvalds */ 433102cedc3SLeonid Yegoshin static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, 434102cedc3SLeonid Yegoshin unsigned long *contpc) 4351da177e4SLinus Torvalds { 436102cedc3SLeonid Yegoshin union mips_instruction insn = (union mips_instruction)dec_insn.insn; 437102cedc3SLeonid Yegoshin unsigned int fcr31; 438102cedc3SLeonid Yegoshin unsigned int bit = 0; 439102cedc3SLeonid Yegoshin 440102cedc3SLeonid Yegoshin switch (insn.i_format.opcode) { 4411da177e4SLinus Torvalds case spec_op: 442102cedc3SLeonid Yegoshin switch (insn.r_format.func) { 4431da177e4SLinus Torvalds case jalr_op: 444102cedc3SLeonid Yegoshin regs->regs[insn.r_format.rd] = 445102cedc3SLeonid Yegoshin regs->cp0_epc + dec_insn.pc_inc + 446102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 447102cedc3SLeonid Yegoshin /* Fall through */ 4481da177e4SLinus Torvalds case jr_op: 4495f9f41c4SMarkos Chandras /* For R6, JR already emulated in jalr_op */ 4505f9f41c4SMarkos Chandras if (NO_R6EMU && insn.r_format.opcode == jr_op) 4515f9f41c4SMarkos Chandras break; 452102cedc3SLeonid Yegoshin *contpc = regs->regs[insn.r_format.rs]; 4531da177e4SLinus Torvalds return 1; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds break; 4561da177e4SLinus Torvalds case bcond_op: 457102cedc3SLeonid Yegoshin switch (insn.i_format.rt) { 4581da177e4SLinus Torvalds case bltzal_op: 4591da177e4SLinus Torvalds case bltzall_op: 460319824eaSMarkos Chandras if (NO_R6EMU && (insn.i_format.rs || 461319824eaSMarkos Chandras insn.i_format.rt == bltzall_op)) 462319824eaSMarkos Chandras break; 463319824eaSMarkos Chandras 464102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 465102cedc3SLeonid Yegoshin dec_insn.pc_inc + 466102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 467102cedc3SLeonid Yegoshin /* Fall through */ 468102cedc3SLeonid Yegoshin case bltzl_op: 469319824eaSMarkos Chandras if (NO_R6EMU) 470319824eaSMarkos Chandras break; 471319824eaSMarkos Chandras case bltz_op: 472102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] < 0) 473102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 474102cedc3SLeonid Yegoshin dec_insn.pc_inc + 475102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 476102cedc3SLeonid Yegoshin else 477102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 478102cedc3SLeonid Yegoshin dec_insn.pc_inc + 479102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 4801da177e4SLinus Torvalds return 1; 481102cedc3SLeonid Yegoshin case bgezal_op: 482102cedc3SLeonid Yegoshin case bgezall_op: 483319824eaSMarkos Chandras if (NO_R6EMU && (insn.i_format.rs || 484319824eaSMarkos Chandras insn.i_format.rt == bgezall_op)) 485319824eaSMarkos Chandras break; 486319824eaSMarkos Chandras 487102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 488102cedc3SLeonid Yegoshin dec_insn.pc_inc + 489102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 490102cedc3SLeonid Yegoshin /* Fall through */ 491102cedc3SLeonid Yegoshin case bgezl_op: 492319824eaSMarkos Chandras if (NO_R6EMU) 493319824eaSMarkos Chandras break; 494319824eaSMarkos Chandras case bgez_op: 495102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] >= 0) 496102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 497102cedc3SLeonid Yegoshin dec_insn.pc_inc + 498102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 499102cedc3SLeonid Yegoshin else 500102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 501102cedc3SLeonid Yegoshin dec_insn.pc_inc + 502102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 503102cedc3SLeonid Yegoshin return 1; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds break; 5061da177e4SLinus Torvalds case jalx_op: 507102cedc3SLeonid Yegoshin set_isa16_mode(bit); 508102cedc3SLeonid Yegoshin case jal_op: 509102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 510102cedc3SLeonid Yegoshin dec_insn.pc_inc + 511102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 512102cedc3SLeonid Yegoshin /* Fall through */ 513102cedc3SLeonid Yegoshin case j_op: 514102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + dec_insn.pc_inc; 515102cedc3SLeonid Yegoshin *contpc >>= 28; 516102cedc3SLeonid Yegoshin *contpc <<= 28; 517102cedc3SLeonid Yegoshin *contpc |= (insn.j_format.target << 2); 518102cedc3SLeonid Yegoshin /* Set microMIPS mode bit: XOR for jalx. */ 519102cedc3SLeonid Yegoshin *contpc ^= bit; 5201da177e4SLinus Torvalds return 1; 521102cedc3SLeonid Yegoshin case beql_op: 522319824eaSMarkos Chandras if (NO_R6EMU) 523319824eaSMarkos Chandras break; 524319824eaSMarkos Chandras case beq_op: 525102cedc3SLeonid Yegoshin if (regs->regs[insn.i_format.rs] == 526102cedc3SLeonid Yegoshin regs->regs[insn.i_format.rt]) 527102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 528102cedc3SLeonid Yegoshin dec_insn.pc_inc + 529102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 530102cedc3SLeonid Yegoshin else 531102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 532102cedc3SLeonid Yegoshin dec_insn.pc_inc + 533102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 534102cedc3SLeonid Yegoshin return 1; 535102cedc3SLeonid Yegoshin case bnel_op: 536319824eaSMarkos Chandras if (NO_R6EMU) 537319824eaSMarkos Chandras break; 538319824eaSMarkos Chandras case bne_op: 539102cedc3SLeonid Yegoshin if (regs->regs[insn.i_format.rs] != 540102cedc3SLeonid Yegoshin regs->regs[insn.i_format.rt]) 541102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 542102cedc3SLeonid Yegoshin dec_insn.pc_inc + 543102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 544102cedc3SLeonid Yegoshin else 545102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 546102cedc3SLeonid Yegoshin dec_insn.pc_inc + 547102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 548102cedc3SLeonid Yegoshin return 1; 549102cedc3SLeonid Yegoshin case blezl_op: 550319824eaSMarkos Chandras if (NO_R6EMU) 551319824eaSMarkos Chandras break; 552319824eaSMarkos Chandras case blez_op: 553a8ff66f5SMarkos Chandras 554a8ff66f5SMarkos Chandras /* 555a8ff66f5SMarkos Chandras * Compact branches for R6 for the 556a8ff66f5SMarkos Chandras * blez and blezl opcodes. 557a8ff66f5SMarkos Chandras * BLEZ | rs = 0 | rt != 0 == BLEZALC 558a8ff66f5SMarkos Chandras * BLEZ | rs = rt != 0 == BGEZALC 559a8ff66f5SMarkos Chandras * BLEZ | rs != 0 | rt != 0 == BGEUC 560a8ff66f5SMarkos Chandras * BLEZL | rs = 0 | rt != 0 == BLEZC 561a8ff66f5SMarkos Chandras * BLEZL | rs = rt != 0 == BGEZC 562a8ff66f5SMarkos Chandras * BLEZL | rs != 0 | rt != 0 == BGEC 563a8ff66f5SMarkos Chandras * 564a8ff66f5SMarkos Chandras * For real BLEZ{,L}, rt is always 0. 565a8ff66f5SMarkos Chandras */ 566a8ff66f5SMarkos Chandras if (cpu_has_mips_r6 && insn.i_format.rt) { 567a8ff66f5SMarkos Chandras if ((insn.i_format.opcode == blez_op) && 568a8ff66f5SMarkos Chandras ((!insn.i_format.rs && insn.i_format.rt) || 569a8ff66f5SMarkos Chandras (insn.i_format.rs == insn.i_format.rt))) 570a8ff66f5SMarkos Chandras regs->regs[31] = regs->cp0_epc + 571a8ff66f5SMarkos Chandras dec_insn.pc_inc; 572a8ff66f5SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 573a8ff66f5SMarkos Chandras dec_insn.next_pc_inc; 574a8ff66f5SMarkos Chandras 575a8ff66f5SMarkos Chandras return 1; 576a8ff66f5SMarkos Chandras } 577102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] <= 0) 578102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 579102cedc3SLeonid Yegoshin dec_insn.pc_inc + 580102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 581102cedc3SLeonid Yegoshin else 582102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 583102cedc3SLeonid Yegoshin dec_insn.pc_inc + 584102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 585102cedc3SLeonid Yegoshin return 1; 586102cedc3SLeonid Yegoshin case bgtzl_op: 587319824eaSMarkos Chandras if (NO_R6EMU) 588319824eaSMarkos Chandras break; 589319824eaSMarkos Chandras case bgtz_op: 590f1b44067SMarkos Chandras /* 591f1b44067SMarkos Chandras * Compact branches for R6 for the 592f1b44067SMarkos Chandras * bgtz and bgtzl opcodes. 593f1b44067SMarkos Chandras * BGTZ | rs = 0 | rt != 0 == BGTZALC 594f1b44067SMarkos Chandras * BGTZ | rs = rt != 0 == BLTZALC 595f1b44067SMarkos Chandras * BGTZ | rs != 0 | rt != 0 == BLTUC 596f1b44067SMarkos Chandras * BGTZL | rs = 0 | rt != 0 == BGTZC 597f1b44067SMarkos Chandras * BGTZL | rs = rt != 0 == BLTZC 598f1b44067SMarkos Chandras * BGTZL | rs != 0 | rt != 0 == BLTC 599f1b44067SMarkos Chandras * 600f1b44067SMarkos Chandras * *ZALC varint for BGTZ &&& rt != 0 601f1b44067SMarkos Chandras * For real GTZ{,L}, rt is always 0. 602f1b44067SMarkos Chandras */ 603f1b44067SMarkos Chandras if (cpu_has_mips_r6 && insn.i_format.rt) { 604f1b44067SMarkos Chandras if ((insn.i_format.opcode == blez_op) && 605f1b44067SMarkos Chandras ((!insn.i_format.rs && insn.i_format.rt) || 606f1b44067SMarkos Chandras (insn.i_format.rs == insn.i_format.rt))) 607f1b44067SMarkos Chandras regs->regs[31] = regs->cp0_epc + 608f1b44067SMarkos Chandras dec_insn.pc_inc; 609f1b44067SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 610f1b44067SMarkos Chandras dec_insn.next_pc_inc; 611f1b44067SMarkos Chandras 612f1b44067SMarkos Chandras return 1; 613f1b44067SMarkos Chandras } 614f1b44067SMarkos Chandras 615102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] > 0) 616102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 617102cedc3SLeonid Yegoshin dec_insn.pc_inc + 618102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 619102cedc3SLeonid Yegoshin else 620102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 621102cedc3SLeonid Yegoshin dec_insn.pc_inc + 622102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 623102cedc3SLeonid Yegoshin return 1; 624c893ce38SMarkos Chandras case cbcond0_op: 62510d962d5SMarkos Chandras case cbcond1_op: 626c893ce38SMarkos Chandras if (!cpu_has_mips_r6) 627c893ce38SMarkos Chandras break; 628c893ce38SMarkos Chandras if (insn.i_format.rt && !insn.i_format.rs) 629c893ce38SMarkos Chandras regs->regs[31] = regs->cp0_epc + 4; 630c893ce38SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 631c893ce38SMarkos Chandras dec_insn.next_pc_inc; 632c893ce38SMarkos Chandras 633c893ce38SMarkos Chandras return 1; 634c26d4219SDavid Daney #ifdef CONFIG_CPU_CAVIUM_OCTEON 635c26d4219SDavid Daney case lwc2_op: /* This is bbit0 on Octeon */ 636c26d4219SDavid Daney if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0) 637c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 638c26d4219SDavid Daney else 639c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 640c26d4219SDavid Daney return 1; 641c26d4219SDavid Daney case ldc2_op: /* This is bbit032 on Octeon */ 642c26d4219SDavid Daney if ((regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) == 0) 643c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 644c26d4219SDavid Daney else 645c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 646c26d4219SDavid Daney return 1; 647c26d4219SDavid Daney case swc2_op: /* This is bbit1 on Octeon */ 648c26d4219SDavid Daney if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) 649c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 650c26d4219SDavid Daney else 651c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 652c26d4219SDavid Daney return 1; 653c26d4219SDavid Daney case sdc2_op: /* This is bbit132 on Octeon */ 654c26d4219SDavid Daney if (regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) 655c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 656c26d4219SDavid Daney else 657c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 658c26d4219SDavid Daney return 1; 6598467ca01SMarkos Chandras #else 6608467ca01SMarkos Chandras case bc6_op: 6618467ca01SMarkos Chandras /* 6628467ca01SMarkos Chandras * Only valid for MIPS R6 but we can still end up 6638467ca01SMarkos Chandras * here from a broken userland so just tell emulator 6648467ca01SMarkos Chandras * this is not a branch and let it break later on. 6658467ca01SMarkos Chandras */ 6668467ca01SMarkos Chandras if (!cpu_has_mips_r6) 6678467ca01SMarkos Chandras break; 6688467ca01SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 6698467ca01SMarkos Chandras dec_insn.next_pc_inc; 6708467ca01SMarkos Chandras 6718467ca01SMarkos Chandras return 1; 67284fef630SMarkos Chandras case balc6_op: 67384fef630SMarkos Chandras if (!cpu_has_mips_r6) 67484fef630SMarkos Chandras break; 67584fef630SMarkos Chandras regs->regs[31] = regs->cp0_epc + 4; 67684fef630SMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 67784fef630SMarkos Chandras dec_insn.next_pc_inc; 67884fef630SMarkos Chandras 67984fef630SMarkos Chandras return 1; 68069b9a2fdSMarkos Chandras case beqzcjic_op: 68169b9a2fdSMarkos Chandras if (!cpu_has_mips_r6) 68269b9a2fdSMarkos Chandras break; 68369b9a2fdSMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 68469b9a2fdSMarkos Chandras dec_insn.next_pc_inc; 68569b9a2fdSMarkos Chandras 68669b9a2fdSMarkos Chandras return 1; 68728d6f93dSMarkos Chandras case bnezcjialc_op: 68828d6f93dSMarkos Chandras if (!cpu_has_mips_r6) 68928d6f93dSMarkos Chandras break; 69028d6f93dSMarkos Chandras if (!insn.i_format.rs) 69128d6f93dSMarkos Chandras regs->regs[31] = regs->cp0_epc + 4; 69228d6f93dSMarkos Chandras *contpc = regs->cp0_epc + dec_insn.pc_inc + 69328d6f93dSMarkos Chandras dec_insn.next_pc_inc; 69428d6f93dSMarkos Chandras 69528d6f93dSMarkos Chandras return 1; 696c26d4219SDavid Daney #endif 6971da177e4SLinus Torvalds case cop0_op: 6981da177e4SLinus Torvalds case cop1_op: 699c8a34581SMarkos Chandras /* Need to check for R6 bc1nez and bc1eqz branches */ 700c8a34581SMarkos Chandras if (cpu_has_mips_r6 && 701c8a34581SMarkos Chandras ((insn.i_format.rs == bc1eqz_op) || 702c8a34581SMarkos Chandras (insn.i_format.rs == bc1nez_op))) { 703c8a34581SMarkos Chandras bit = 0; 704c8a34581SMarkos Chandras switch (insn.i_format.rs) { 705c8a34581SMarkos Chandras case bc1eqz_op: 706c8a34581SMarkos Chandras if (get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1) 707c8a34581SMarkos Chandras bit = 1; 708c8a34581SMarkos Chandras break; 709c8a34581SMarkos Chandras case bc1nez_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 } 714c8a34581SMarkos Chandras if (bit) 715c8a34581SMarkos Chandras *contpc = regs->cp0_epc + 716c8a34581SMarkos Chandras dec_insn.pc_inc + 717c8a34581SMarkos Chandras (insn.i_format.simmediate << 2); 718c8a34581SMarkos Chandras else 719c8a34581SMarkos Chandras *contpc = regs->cp0_epc + 720c8a34581SMarkos Chandras dec_insn.pc_inc + 721c8a34581SMarkos Chandras dec_insn.next_pc_inc; 722c8a34581SMarkos Chandras 723c8a34581SMarkos Chandras return 1; 724c8a34581SMarkos Chandras } 725c8a34581SMarkos Chandras /* R2/R6 compatible cop1 instruction. Fall through */ 7261da177e4SLinus Torvalds case cop2_op: 7271da177e4SLinus Torvalds case cop1x_op: 728102cedc3SLeonid Yegoshin if (insn.i_format.rs == bc_op) { 729102cedc3SLeonid Yegoshin preempt_disable(); 730102cedc3SLeonid Yegoshin if (is_fpu_owner()) 731842dfc11SManuel Lauss fcr31 = read_32bit_cp1_register(CP1_STATUS); 732102cedc3SLeonid Yegoshin else 733102cedc3SLeonid Yegoshin fcr31 = current->thread.fpu.fcr31; 734102cedc3SLeonid Yegoshin preempt_enable(); 735102cedc3SLeonid Yegoshin 736102cedc3SLeonid Yegoshin bit = (insn.i_format.rt >> 2); 737102cedc3SLeonid Yegoshin bit += (bit != 0); 738102cedc3SLeonid Yegoshin bit += 23; 739102cedc3SLeonid Yegoshin switch (insn.i_format.rt & 3) { 740102cedc3SLeonid Yegoshin case 0: /* bc1f */ 741102cedc3SLeonid Yegoshin case 2: /* bc1fl */ 742102cedc3SLeonid Yegoshin if (~fcr31 & (1 << bit)) 743102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 744102cedc3SLeonid Yegoshin dec_insn.pc_inc + 745102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 746102cedc3SLeonid Yegoshin else 747102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 748102cedc3SLeonid Yegoshin dec_insn.pc_inc + 749102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 750102cedc3SLeonid Yegoshin return 1; 751102cedc3SLeonid Yegoshin case 1: /* bc1t */ 752102cedc3SLeonid Yegoshin case 3: /* bc1tl */ 753102cedc3SLeonid Yegoshin if (fcr31 & (1 << bit)) 754102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 755102cedc3SLeonid Yegoshin dec_insn.pc_inc + 756102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 757102cedc3SLeonid Yegoshin else 758102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 759102cedc3SLeonid Yegoshin dec_insn.pc_inc + 760102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 7611da177e4SLinus Torvalds return 1; 7621da177e4SLinus Torvalds } 763102cedc3SLeonid Yegoshin } 764102cedc3SLeonid Yegoshin break; 765102cedc3SLeonid Yegoshin } 7661da177e4SLinus Torvalds return 0; 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds /* 7701da177e4SLinus Torvalds * In the Linux kernel, we support selection of FPR format on the 771da0bac33SDavid Daney * basis of the Status.FR bit. If an FPU is not present, the FR bit 772da0bac33SDavid Daney * is hardwired to zero, which would imply a 32-bit FPU even for 773597ce172SPaul Burton * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS. 77451d943f0SRalf Baechle * FPU emu is slow and bulky and optimizing this function offers fairly 77551d943f0SRalf Baechle * sizeable benefits so we try to be clever and make this function return 77651d943f0SRalf Baechle * a constant whenever possible, that is on 64-bit kernels without O32 777597ce172SPaul Burton * compatibility enabled and on 32-bit without 64-bit FPU support. 7781da177e4SLinus Torvalds */ 779da0bac33SDavid Daney static inline int cop1_64bit(struct pt_regs *xcp) 780da0bac33SDavid Daney { 78108a07904SRalf Baechle if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) 78251d943f0SRalf Baechle return 1; 78308a07904SRalf Baechle else if (config_enabled(CONFIG_32BIT) && 78408a07904SRalf Baechle !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) 785da0bac33SDavid Daney return 0; 78608a07904SRalf Baechle 787597ce172SPaul Burton return !test_thread_flag(TIF_32BIT_FPREGS); 788da0bac33SDavid Daney } 7891da177e4SLinus Torvalds 7904227a2d4SPaul Burton static inline bool hybrid_fprs(void) 7914227a2d4SPaul Burton { 7924227a2d4SPaul Burton return test_thread_flag(TIF_HYBRID_FPREGS); 7934227a2d4SPaul Burton } 7944227a2d4SPaul Burton 79547fa0c02SRalf Baechle #define SIFROMREG(si, x) \ 79647fa0c02SRalf Baechle do { \ 7974227a2d4SPaul Burton if (cop1_64bit(xcp) && !hybrid_fprs()) \ 798c8c0da6bSPaul Burton (si) = (int)get_fpr32(&ctx->fpr[x], 0); \ 799bbd426f5SPaul Burton else \ 800c8c0da6bSPaul Burton (si) = (int)get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ 801bbd426f5SPaul Burton } while (0) 802da0bac33SDavid Daney 80347fa0c02SRalf Baechle #define SITOREG(si, x) \ 80447fa0c02SRalf Baechle do { \ 8054227a2d4SPaul Burton if (cop1_64bit(xcp) && !hybrid_fprs()) { \ 806ef1c47afSPaul Burton unsigned i; \ 807bbd426f5SPaul Burton set_fpr32(&ctx->fpr[x], 0, si); \ 808ef1c47afSPaul Burton for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ 809ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], i, 0); \ 810ef1c47afSPaul Burton } else { \ 811bbd426f5SPaul Burton set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \ 812ef1c47afSPaul Burton } \ 813bbd426f5SPaul Burton } while (0) 8141da177e4SLinus Torvalds 815c8c0da6bSPaul Burton #define SIFROMHREG(si, x) ((si) = (int)get_fpr32(&ctx->fpr[x], 1)) 816ef1c47afSPaul Burton 81747fa0c02SRalf Baechle #define SITOHREG(si, x) \ 81847fa0c02SRalf Baechle do { \ 819ef1c47afSPaul Burton unsigned i; \ 820ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], 1, si); \ 821ef1c47afSPaul Burton for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ 822ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], i, 0); \ 823ef1c47afSPaul Burton } while (0) 8241ac94400SLeonid Yegoshin 825bbd426f5SPaul Burton #define DIFROMREG(di, x) \ 826bbd426f5SPaul Burton ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) 827bbd426f5SPaul Burton 82847fa0c02SRalf Baechle #define DITOREG(di, x) \ 82947fa0c02SRalf Baechle do { \ 830ef1c47afSPaul Burton unsigned fpr, i; \ 831ef1c47afSPaul Burton fpr = (x) & ~(cop1_64bit(xcp) == 0); \ 832ef1c47afSPaul Burton set_fpr64(&ctx->fpr[fpr], 0, di); \ 833ef1c47afSPaul Burton for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \ 834ef1c47afSPaul Burton set_fpr64(&ctx->fpr[fpr], i, 0); \ 835ef1c47afSPaul Burton } while (0) 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) 8381da177e4SLinus Torvalds #define SPTOREG(sp, x) SITOREG((sp).bits, x) 8391da177e4SLinus Torvalds #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) 8401da177e4SLinus Torvalds #define DPTOREG(dp, x) DITOREG((dp).bits, x) 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds /* 843d4f5b088SMaciej W. Rozycki * Emulate a CFC1 instruction. 844d4f5b088SMaciej W. Rozycki */ 845d4f5b088SMaciej W. Rozycki static inline void cop1_cfc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 846d4f5b088SMaciej W. Rozycki mips_instruction ir) 847d4f5b088SMaciej W. Rozycki { 848d4f5b088SMaciej W. Rozycki u32 value; 849d4f5b088SMaciej W. Rozycki 850d4f5b088SMaciej W. Rozycki if (MIPSInst_RD(ir) == FPCREG_CSR) { 851d4f5b088SMaciej W. Rozycki value = ctx->fcr31; 852d4f5b088SMaciej W. Rozycki pr_debug("%p gpr[%d]<-csr=%08x\n", 853d4f5b088SMaciej W. Rozycki (void *)xcp->cp0_epc, 854d4f5b088SMaciej W. Rozycki MIPSInst_RT(ir), value); 855d4f5b088SMaciej W. Rozycki } else if (MIPSInst_RD(ir) == FPCREG_RID) 856d4f5b088SMaciej W. Rozycki value = 0; 857d4f5b088SMaciej W. Rozycki else 858d4f5b088SMaciej W. Rozycki value = 0; 859d4f5b088SMaciej W. Rozycki if (MIPSInst_RT(ir)) 860d4f5b088SMaciej W. Rozycki xcp->regs[MIPSInst_RT(ir)] = value; 861d4f5b088SMaciej W. Rozycki } 862d4f5b088SMaciej W. Rozycki 863d4f5b088SMaciej W. Rozycki /* 864d4f5b088SMaciej W. Rozycki * Emulate a CTC1 instruction. 865d4f5b088SMaciej W. Rozycki */ 866d4f5b088SMaciej W. Rozycki static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 867d4f5b088SMaciej W. Rozycki mips_instruction ir) 868d4f5b088SMaciej W. Rozycki { 869d4f5b088SMaciej W. Rozycki u32 value; 870d4f5b088SMaciej W. Rozycki 871d4f5b088SMaciej W. Rozycki if (MIPSInst_RT(ir) == 0) 872d4f5b088SMaciej W. Rozycki value = 0; 873d4f5b088SMaciej W. Rozycki else 874d4f5b088SMaciej W. Rozycki value = xcp->regs[MIPSInst_RT(ir)]; 875d4f5b088SMaciej W. Rozycki 876d4f5b088SMaciej W. Rozycki /* we only have one writable control reg 877d4f5b088SMaciej W. Rozycki */ 878d4f5b088SMaciej W. Rozycki if (MIPSInst_RD(ir) == FPCREG_CSR) { 879d4f5b088SMaciej W. Rozycki pr_debug("%p gpr[%d]->csr=%08x\n", 880d4f5b088SMaciej W. Rozycki (void *)xcp->cp0_epc, 881d4f5b088SMaciej W. Rozycki MIPSInst_RT(ir), value); 882d4f5b088SMaciej W. Rozycki 883d4f5b088SMaciej W. Rozycki /* Don't write reserved bits. */ 884d4f5b088SMaciej W. Rozycki ctx->fcr31 = value & ~FPU_CSR_RSVD; 885d4f5b088SMaciej W. Rozycki } 886d4f5b088SMaciej W. Rozycki } 887d4f5b088SMaciej W. Rozycki 888d4f5b088SMaciej W. Rozycki /* 8891da177e4SLinus Torvalds * Emulate the single floating point instruction pointed at by EPC. 8901da177e4SLinus Torvalds * Two instructions if the instruction is in a branch delay slot. 8911da177e4SLinus Torvalds */ 8921da177e4SLinus Torvalds 893515b029dSDavid Daney static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 894102cedc3SLeonid Yegoshin struct mm_decoded_insn dec_insn, void *__user *fault_addr) 8951da177e4SLinus Torvalds { 896102cedc3SLeonid Yegoshin unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; 8973f7cac41SRalf Baechle unsigned int cond, cbit; 8983f7cac41SRalf Baechle mips_instruction ir; 8993f7cac41SRalf Baechle int likely, pc_inc; 9003f7cac41SRalf Baechle u32 __user *wva; 9013f7cac41SRalf Baechle u64 __user *dva; 9023f7cac41SRalf Baechle u32 wval; 9033f7cac41SRalf Baechle u64 dval; 9043f7cac41SRalf Baechle int sig; 9051da177e4SLinus Torvalds 90670e4c234SRalf Baechle /* 90770e4c234SRalf Baechle * These are giving gcc a gentle hint about what to expect in 90870e4c234SRalf Baechle * dec_inst in order to do better optimization. 90970e4c234SRalf Baechle */ 91070e4c234SRalf Baechle if (!cpu_has_mmips && dec_insn.micro_mips_mode) 91170e4c234SRalf Baechle unreachable(); 91270e4c234SRalf Baechle 9131da177e4SLinus Torvalds /* XXX NEC Vr54xx bug workaround */ 914e7e9cae5SRalf Baechle if (delay_slot(xcp)) { 915102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 916102cedc3SLeonid Yegoshin if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) 917e7e9cae5SRalf Baechle clear_delay_slot(xcp); 918102cedc3SLeonid Yegoshin } else { 919102cedc3SLeonid Yegoshin if (!isBranchInstr(xcp, dec_insn, &contpc)) 920e7e9cae5SRalf Baechle clear_delay_slot(xcp); 921102cedc3SLeonid Yegoshin } 922102cedc3SLeonid Yegoshin } 9231da177e4SLinus Torvalds 924e7e9cae5SRalf Baechle if (delay_slot(xcp)) { 9251da177e4SLinus Torvalds /* 9261da177e4SLinus Torvalds * The instruction to be emulated is in a branch delay slot 9271da177e4SLinus Torvalds * which means that we have to emulate the branch instruction 9281da177e4SLinus Torvalds * BEFORE we do the cop1 instruction. 9291da177e4SLinus Torvalds * 9301da177e4SLinus Torvalds * This branch could be a COP1 branch, but in that case we 9311da177e4SLinus Torvalds * would have had a trap for that instruction, and would not 9321da177e4SLinus Torvalds * come through this route. 9331da177e4SLinus Torvalds * 9341da177e4SLinus Torvalds * Linux MIPS branch emulator operates on context, updating the 9351da177e4SLinus Torvalds * cp0_epc. 9361da177e4SLinus Torvalds */ 937102cedc3SLeonid Yegoshin ir = dec_insn.next_insn; /* process delay slot instr */ 938102cedc3SLeonid Yegoshin pc_inc = dec_insn.next_pc_inc; 939333d1f67SRalf Baechle } else { 940102cedc3SLeonid Yegoshin ir = dec_insn.insn; /* process current instr */ 941102cedc3SLeonid Yegoshin pc_inc = dec_insn.pc_inc; 942102cedc3SLeonid Yegoshin } 943102cedc3SLeonid Yegoshin 944102cedc3SLeonid Yegoshin /* 945102cedc3SLeonid Yegoshin * Since microMIPS FPU instructios are a subset of MIPS32 FPU 946102cedc3SLeonid Yegoshin * instructions, we want to convert microMIPS FPU instructions 947102cedc3SLeonid Yegoshin * into MIPS32 instructions so that we could reuse all of the 948102cedc3SLeonid Yegoshin * FPU emulation code. 949102cedc3SLeonid Yegoshin * 950102cedc3SLeonid Yegoshin * NOTE: We cannot do this for branch instructions since they 951102cedc3SLeonid Yegoshin * are not a subset. Example: Cannot emulate a 16-bit 952102cedc3SLeonid Yegoshin * aligned target address with a MIPS32 instruction. 953102cedc3SLeonid Yegoshin */ 954102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 955102cedc3SLeonid Yegoshin /* 956102cedc3SLeonid Yegoshin * If next instruction is a 16-bit instruction, then it 957102cedc3SLeonid Yegoshin * it cannot be a FPU instruction. This could happen 958102cedc3SLeonid Yegoshin * since we can be called for non-FPU instructions. 959102cedc3SLeonid Yegoshin */ 960102cedc3SLeonid Yegoshin if ((pc_inc == 2) || 961102cedc3SLeonid Yegoshin (microMIPS32_to_MIPS32((union mips_instruction *)&ir) 962102cedc3SLeonid Yegoshin == SIGILL)) 963102cedc3SLeonid Yegoshin return SIGILL; 9641da177e4SLinus Torvalds } 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds emul: 967a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); 968b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(emulated); 9691da177e4SLinus Torvalds switch (MIPSInst_OPCODE(ir)) { 9703f7cac41SRalf Baechle case ldc1_op: 9713f7cac41SRalf Baechle dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 9721da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 973b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 974515b029dSDavid Daney 9753f7cac41SRalf Baechle if (!access_ok(VERIFY_READ, dva, sizeof(u64))) { 976b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 9773f7cac41SRalf Baechle *fault_addr = dva; 9781da177e4SLinus Torvalds return SIGBUS; 9791da177e4SLinus Torvalds } 9803f7cac41SRalf Baechle if (__get_user(dval, dva)) { 981515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 9823f7cac41SRalf Baechle *fault_addr = dva; 983515b029dSDavid Daney return SIGSEGV; 984515b029dSDavid Daney } 9853f7cac41SRalf Baechle DITOREG(dval, MIPSInst_RT(ir)); 9861da177e4SLinus Torvalds break; 9871da177e4SLinus Torvalds 9883f7cac41SRalf Baechle case sdc1_op: 9893f7cac41SRalf Baechle dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 9901da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 991b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 9923f7cac41SRalf Baechle DIFROMREG(dval, MIPSInst_RT(ir)); 9933f7cac41SRalf Baechle if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { 994b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 9953f7cac41SRalf Baechle *fault_addr = dva; 9961da177e4SLinus Torvalds return SIGBUS; 9971da177e4SLinus Torvalds } 9983f7cac41SRalf Baechle if (__put_user(dval, dva)) { 999515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10003f7cac41SRalf Baechle *fault_addr = dva; 1001515b029dSDavid Daney return SIGSEGV; 1002515b029dSDavid Daney } 10031da177e4SLinus Torvalds break; 10041da177e4SLinus Torvalds 10053f7cac41SRalf Baechle case lwc1_op: 10063f7cac41SRalf Baechle wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10071da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 1008b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 10093f7cac41SRalf Baechle if (!access_ok(VERIFY_READ, wva, sizeof(u32))) { 1010b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10113f7cac41SRalf Baechle *fault_addr = wva; 10121da177e4SLinus Torvalds return SIGBUS; 10131da177e4SLinus Torvalds } 10143f7cac41SRalf Baechle if (__get_user(wval, wva)) { 1015515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10163f7cac41SRalf Baechle *fault_addr = wva; 1017515b029dSDavid Daney return SIGSEGV; 1018515b029dSDavid Daney } 10193f7cac41SRalf Baechle SITOREG(wval, MIPSInst_RT(ir)); 10201da177e4SLinus Torvalds break; 10211da177e4SLinus Torvalds 10223f7cac41SRalf Baechle case swc1_op: 10233f7cac41SRalf Baechle wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10241da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 1025b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 10263f7cac41SRalf Baechle SIFROMREG(wval, MIPSInst_RT(ir)); 10273f7cac41SRalf Baechle if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { 1028b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10293f7cac41SRalf Baechle *fault_addr = wva; 10301da177e4SLinus Torvalds return SIGBUS; 10311da177e4SLinus Torvalds } 10323f7cac41SRalf Baechle if (__put_user(wval, wva)) { 1033515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 10343f7cac41SRalf Baechle *fault_addr = wva; 1035515b029dSDavid Daney return SIGSEGV; 1036515b029dSDavid Daney } 10371da177e4SLinus Torvalds break; 10381da177e4SLinus Torvalds 10391da177e4SLinus Torvalds case cop1_op: 10401da177e4SLinus Torvalds switch (MIPSInst_RS(ir)) { 10411da177e4SLinus Torvalds case dmfc_op: 104208a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 104308a07904SRalf Baechle return SIGILL; 104408a07904SRalf Baechle 10451da177e4SLinus Torvalds /* copregister fs -> gpr[rt] */ 10461da177e4SLinus Torvalds if (MIPSInst_RT(ir) != 0) { 10471da177e4SLinus Torvalds DIFROMREG(xcp->regs[MIPSInst_RT(ir)], 10481da177e4SLinus Torvalds MIPSInst_RD(ir)); 10491da177e4SLinus Torvalds } 10501da177e4SLinus Torvalds break; 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds case dmtc_op: 105308a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 105408a07904SRalf Baechle return SIGILL; 105508a07904SRalf Baechle 10561da177e4SLinus Torvalds /* copregister fs <- rt */ 10571da177e4SLinus Torvalds DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 10581da177e4SLinus Torvalds break; 10591da177e4SLinus Torvalds 10601ac94400SLeonid Yegoshin case mfhc_op: 10611ac94400SLeonid Yegoshin if (!cpu_has_mips_r2) 10621ac94400SLeonid Yegoshin goto sigill; 10631ac94400SLeonid Yegoshin 10641ac94400SLeonid Yegoshin /* copregister rd -> gpr[rt] */ 10651ac94400SLeonid Yegoshin if (MIPSInst_RT(ir) != 0) { 10661ac94400SLeonid Yegoshin SIFROMHREG(xcp->regs[MIPSInst_RT(ir)], 10671ac94400SLeonid Yegoshin MIPSInst_RD(ir)); 10681ac94400SLeonid Yegoshin } 10691ac94400SLeonid Yegoshin break; 10701ac94400SLeonid Yegoshin 10711ac94400SLeonid Yegoshin case mthc_op: 10721ac94400SLeonid Yegoshin if (!cpu_has_mips_r2) 10731ac94400SLeonid Yegoshin goto sigill; 10741ac94400SLeonid Yegoshin 10751ac94400SLeonid Yegoshin /* copregister rd <- gpr[rt] */ 10761ac94400SLeonid Yegoshin SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 10771ac94400SLeonid Yegoshin break; 10781ac94400SLeonid Yegoshin 10791da177e4SLinus Torvalds case mfc_op: 10801da177e4SLinus Torvalds /* copregister rd -> gpr[rt] */ 10811da177e4SLinus Torvalds if (MIPSInst_RT(ir) != 0) { 10821da177e4SLinus Torvalds SIFROMREG(xcp->regs[MIPSInst_RT(ir)], 10831da177e4SLinus Torvalds MIPSInst_RD(ir)); 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds break; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds case mtc_op: 10881da177e4SLinus Torvalds /* copregister rd <- rt */ 10891da177e4SLinus Torvalds SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 10901da177e4SLinus Torvalds break; 10911da177e4SLinus Torvalds 10923f7cac41SRalf Baechle case cfc_op: 10931da177e4SLinus Torvalds /* cop control register rd -> gpr[rt] */ 1094d4f5b088SMaciej W. Rozycki cop1_cfc(xcp, ctx, ir); 10951da177e4SLinus Torvalds break; 10961da177e4SLinus Torvalds 10973f7cac41SRalf Baechle case ctc_op: 10981da177e4SLinus Torvalds /* copregister rd <- rt */ 1099d4f5b088SMaciej W. Rozycki cop1_ctc(xcp, ctx, ir); 11001da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 11011da177e4SLinus Torvalds return SIGFPE; 11021da177e4SLinus Torvalds } 11031da177e4SLinus Torvalds break; 11041da177e4SLinus Torvalds 11053f7cac41SRalf Baechle case bc_op: 1106e7e9cae5SRalf Baechle if (delay_slot(xcp)) 11071da177e4SLinus Torvalds return SIGILL; 11081da177e4SLinus Torvalds 110908a07904SRalf Baechle if (cpu_has_mips_4_5_r) 111008a07904SRalf Baechle cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; 111108a07904SRalf Baechle else 111208a07904SRalf Baechle cbit = FPU_CSR_COND; 111308a07904SRalf Baechle cond = ctx->fcr31 & cbit; 111408a07904SRalf Baechle 11153f7cac41SRalf Baechle likely = 0; 11161da177e4SLinus Torvalds switch (MIPSInst_RT(ir) & 3) { 11171da177e4SLinus Torvalds case bcfl_op: 11182d83fea7SMaciej W. Rozycki if (cpu_has_mips_2_3_4_5_r) 11191da177e4SLinus Torvalds likely = 1; 11202d83fea7SMaciej W. Rozycki /* Fall through */ 11211da177e4SLinus Torvalds case bcf_op: 11221da177e4SLinus Torvalds cond = !cond; 11231da177e4SLinus Torvalds break; 11241da177e4SLinus Torvalds case bctl_op: 11252d83fea7SMaciej W. Rozycki if (cpu_has_mips_2_3_4_5_r) 11261da177e4SLinus Torvalds likely = 1; 11272d83fea7SMaciej W. Rozycki /* Fall through */ 11281da177e4SLinus Torvalds case bct_op: 11291da177e4SLinus Torvalds break; 11301da177e4SLinus Torvalds } 11311da177e4SLinus Torvalds 1132e7e9cae5SRalf Baechle set_delay_slot(xcp); 11331da177e4SLinus Torvalds if (cond) { 11343f7cac41SRalf Baechle /* 11353f7cac41SRalf Baechle * Branch taken: emulate dslot instruction 11361da177e4SLinus Torvalds */ 1137*9ab4471cSMaciej W. Rozycki unsigned long bcpc; 1138*9ab4471cSMaciej W. Rozycki 1139*9ab4471cSMaciej W. Rozycki /* 1140*9ab4471cSMaciej W. Rozycki * Remember EPC at the branch to point back 1141*9ab4471cSMaciej W. Rozycki * at so that any delay-slot instruction 1142*9ab4471cSMaciej W. Rozycki * signal is not silently ignored. 1143*9ab4471cSMaciej W. Rozycki */ 1144*9ab4471cSMaciej W. Rozycki bcpc = xcp->cp0_epc; 1145102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; 11461da177e4SLinus Torvalds 1147102cedc3SLeonid Yegoshin contpc = MIPSInst_SIMM(ir); 1148102cedc3SLeonid Yegoshin ir = dec_insn.next_insn; 1149102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 1150102cedc3SLeonid Yegoshin contpc = (xcp->cp0_epc + (contpc << 1)); 1151102cedc3SLeonid Yegoshin 1152102cedc3SLeonid Yegoshin /* If 16-bit instruction, not FPU. */ 1153102cedc3SLeonid Yegoshin if ((dec_insn.next_pc_inc == 2) || 1154102cedc3SLeonid Yegoshin (microMIPS32_to_MIPS32((union mips_instruction *)&ir) == SIGILL)) { 1155102cedc3SLeonid Yegoshin 1156102cedc3SLeonid Yegoshin /* 1157102cedc3SLeonid Yegoshin * Since this instruction will 1158102cedc3SLeonid Yegoshin * be put on the stack with 1159102cedc3SLeonid Yegoshin * 32-bit words, get around 1160102cedc3SLeonid Yegoshin * this problem by putting a 1161102cedc3SLeonid Yegoshin * NOP16 as the second one. 1162102cedc3SLeonid Yegoshin */ 1163102cedc3SLeonid Yegoshin if (dec_insn.next_pc_inc == 2) 1164102cedc3SLeonid Yegoshin ir = (ir & (~0xffff)) | MM_NOP16; 1165102cedc3SLeonid Yegoshin 1166102cedc3SLeonid Yegoshin /* 1167102cedc3SLeonid Yegoshin * Single step the non-CP1 1168102cedc3SLeonid Yegoshin * instruction in the dslot. 1169102cedc3SLeonid Yegoshin */ 1170*9ab4471cSMaciej W. Rozycki sig = mips_dsemul(xcp, ir, 1171*9ab4471cSMaciej W. Rozycki contpc); 1172*9ab4471cSMaciej W. Rozycki if (sig) 1173*9ab4471cSMaciej W. Rozycki xcp->cp0_epc = bcpc; 1174*9ab4471cSMaciej W. Rozycki /* 1175*9ab4471cSMaciej W. Rozycki * SIGILL forces out of 1176*9ab4471cSMaciej W. Rozycki * the emulation loop. 1177*9ab4471cSMaciej W. Rozycki */ 1178*9ab4471cSMaciej W. Rozycki return sig ? sig : SIGILL; 1179515b029dSDavid Daney } 1180102cedc3SLeonid Yegoshin } else 1181102cedc3SLeonid Yegoshin contpc = (xcp->cp0_epc + (contpc << 2)); 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds switch (MIPSInst_OPCODE(ir)) { 11841da177e4SLinus Torvalds case lwc1_op: 11851da177e4SLinus Torvalds case swc1_op: 118608a07904SRalf Baechle goto emul; 11873f7cac41SRalf Baechle 11881da177e4SLinus Torvalds case ldc1_op: 11891da177e4SLinus Torvalds case sdc1_op: 11902d83fea7SMaciej W. Rozycki if (cpu_has_mips_2_3_4_5_r) 119108a07904SRalf Baechle goto emul; 119208a07904SRalf Baechle 1193*9ab4471cSMaciej W. Rozycki goto bc_sigill; 11943f7cac41SRalf Baechle 11951da177e4SLinus Torvalds case cop1_op: 119608a07904SRalf Baechle goto emul; 11973f7cac41SRalf Baechle 11981da177e4SLinus Torvalds case cop1x_op: 11992d83fea7SMaciej W. Rozycki if (cpu_has_mips_4_5_64_r2_r6) 12001da177e4SLinus Torvalds /* its one of ours */ 12011da177e4SLinus Torvalds goto emul; 120208a07904SRalf Baechle 1203*9ab4471cSMaciej W. Rozycki goto bc_sigill; 12043f7cac41SRalf Baechle 12051da177e4SLinus Torvalds case spec_op: 12062d83fea7SMaciej W. Rozycki switch (MIPSInst_FUNC(ir)) { 12072d83fea7SMaciej W. Rozycki case movc_op: 12082d83fea7SMaciej W. Rozycki if (cpu_has_mips_4_5_r) 12091da177e4SLinus Torvalds goto emul; 12102d83fea7SMaciej W. Rozycki 1211*9ab4471cSMaciej W. Rozycki goto bc_sigill; 12122d83fea7SMaciej W. Rozycki } 12131da177e4SLinus Torvalds break; 1214*9ab4471cSMaciej W. Rozycki 1215*9ab4471cSMaciej W. Rozycki bc_sigill: 1216*9ab4471cSMaciej W. Rozycki xcp->cp0_epc = bcpc; 1217*9ab4471cSMaciej W. Rozycki return SIGILL; 12181da177e4SLinus Torvalds } 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds /* 12211da177e4SLinus Torvalds * Single step the non-cp1 12221da177e4SLinus Torvalds * instruction in the dslot 12231da177e4SLinus Torvalds */ 1224*9ab4471cSMaciej W. Rozycki sig = mips_dsemul(xcp, ir, contpc); 1225*9ab4471cSMaciej W. Rozycki if (sig) 1226*9ab4471cSMaciej W. Rozycki xcp->cp0_epc = bcpc; 1227*9ab4471cSMaciej W. Rozycki /* SIGILL forces out of the emulation loop. */ 1228*9ab4471cSMaciej W. Rozycki return sig ? sig : SIGILL; 12293f7cac41SRalf Baechle } else if (likely) { /* branch not taken */ 12301da177e4SLinus Torvalds /* 12311da177e4SLinus Torvalds * branch likely nullifies 12321da177e4SLinus Torvalds * dslot if not taken 12331da177e4SLinus Torvalds */ 1234102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; 1235102cedc3SLeonid Yegoshin contpc += dec_insn.pc_inc; 12361da177e4SLinus Torvalds /* 12371da177e4SLinus Torvalds * else continue & execute 12381da177e4SLinus Torvalds * dslot as normal insn 12391da177e4SLinus Torvalds */ 12401da177e4SLinus Torvalds } 12411da177e4SLinus Torvalds break; 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds default: 12441da177e4SLinus Torvalds if (!(MIPSInst_RS(ir) & 0x10)) 12451da177e4SLinus Torvalds return SIGILL; 12461da177e4SLinus Torvalds 12471da177e4SLinus Torvalds /* a real fpu computation instruction */ 12481da177e4SLinus Torvalds if ((sig = fpu_emu(xcp, ctx, ir))) 12491da177e4SLinus Torvalds return sig; 12501da177e4SLinus Torvalds } 12511da177e4SLinus Torvalds break; 12521da177e4SLinus Torvalds 12533f7cac41SRalf Baechle case cop1x_op: 12542d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 125508a07904SRalf Baechle return SIGILL; 125608a07904SRalf Baechle 125708a07904SRalf Baechle sig = fpux_emu(xcp, ctx, ir, fault_addr); 1258515b029dSDavid Daney if (sig) 12591da177e4SLinus Torvalds return sig; 12601da177e4SLinus Torvalds break; 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds case spec_op: 126308a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 126408a07904SRalf Baechle return SIGILL; 126508a07904SRalf Baechle 12661da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) != movc_op) 12671da177e4SLinus Torvalds return SIGILL; 12681da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_RT(ir) >> 2]; 12691da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0)) 12701da177e4SLinus Torvalds xcp->regs[MIPSInst_RD(ir)] = 12711da177e4SLinus Torvalds xcp->regs[MIPSInst_RS(ir)]; 12721da177e4SLinus Torvalds break; 12731da177e4SLinus Torvalds default: 12741ac94400SLeonid Yegoshin sigill: 12751da177e4SLinus Torvalds return SIGILL; 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds /* we did it !! */ 1279e70dfc10SAtsushi Nemoto xcp->cp0_epc = contpc; 1280e7e9cae5SRalf Baechle clear_delay_slot(xcp); 1281333d1f67SRalf Baechle 12821da177e4SLinus Torvalds return 0; 12831da177e4SLinus Torvalds } 12841da177e4SLinus Torvalds 12851da177e4SLinus Torvalds /* 12861da177e4SLinus Torvalds * Conversion table from MIPS compare ops 48-63 12871da177e4SLinus Torvalds * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig); 12881da177e4SLinus Torvalds */ 12891da177e4SLinus Torvalds static const unsigned char cmptab[8] = { 12901da177e4SLinus Torvalds 0, /* cmp_0 (sig) cmp_sf */ 12911da177e4SLinus Torvalds IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ 12921da177e4SLinus Torvalds IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ 12931da177e4SLinus Torvalds IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ 12941da177e4SLinus Torvalds IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ 12951da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ 12961da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ 12971da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ 12981da177e4SLinus Torvalds }; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds /* 13021da177e4SLinus Torvalds * Additional MIPS4 instructions 13031da177e4SLinus Torvalds */ 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds #define DEF3OP(name, p, f1, f2, f3) \ 130647fa0c02SRalf Baechle static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ 130747fa0c02SRalf Baechle union ieee754##p s, union ieee754##p t) \ 13081da177e4SLinus Torvalds { \ 1309cd21dfcfSRalf Baechle struct _ieee754_csr ieee754_csr_save; \ 13101da177e4SLinus Torvalds s = f1(s, t); \ 13111da177e4SLinus Torvalds ieee754_csr_save = ieee754_csr; \ 13121da177e4SLinus Torvalds s = f2(s, r); \ 13131da177e4SLinus Torvalds ieee754_csr_save.cx |= ieee754_csr.cx; \ 13141da177e4SLinus Torvalds ieee754_csr_save.sx |= ieee754_csr.sx; \ 13151da177e4SLinus Torvalds s = f3(s); \ 13161da177e4SLinus Torvalds ieee754_csr.cx |= ieee754_csr_save.cx; \ 13171da177e4SLinus Torvalds ieee754_csr.sx |= ieee754_csr_save.sx; \ 13181da177e4SLinus Torvalds return s; \ 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds 13212209bcb1SRalf Baechle static union ieee754dp fpemu_dp_recip(union ieee754dp d) 13221da177e4SLinus Torvalds { 13231da177e4SLinus Torvalds return ieee754dp_div(ieee754dp_one(0), d); 13241da177e4SLinus Torvalds } 13251da177e4SLinus Torvalds 13262209bcb1SRalf Baechle static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d) 13271da177e4SLinus Torvalds { 13281da177e4SLinus Torvalds return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); 13291da177e4SLinus Torvalds } 13301da177e4SLinus Torvalds 13312209bcb1SRalf Baechle static union ieee754sp fpemu_sp_recip(union ieee754sp s) 13321da177e4SLinus Torvalds { 13331da177e4SLinus Torvalds return ieee754sp_div(ieee754sp_one(0), s); 13341da177e4SLinus Torvalds } 13351da177e4SLinus Torvalds 13362209bcb1SRalf Baechle static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s) 13371da177e4SLinus Torvalds { 13381da177e4SLinus Torvalds return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); 13391da177e4SLinus Torvalds } 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, ); 13421da177e4SLinus Torvalds DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, ); 13431da177e4SLinus Torvalds DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); 13441da177e4SLinus Torvalds DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); 13451da177e4SLinus Torvalds DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, ); 13461da177e4SLinus Torvalds DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); 13471da177e4SLinus Torvalds DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); 13481da177e4SLinus Torvalds DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); 13491da177e4SLinus Torvalds 1350eae89076SAtsushi Nemoto static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 1351515b029dSDavid Daney mips_instruction ir, void *__user *fault_addr) 13521da177e4SLinus Torvalds { 13531da177e4SLinus Torvalds unsigned rcsr = 0; /* resulting csr */ 13541da177e4SLinus Torvalds 1355b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(cp1xops); 13561da177e4SLinus Torvalds 13571da177e4SLinus Torvalds switch (MIPSInst_FMA_FFMT(ir)) { 13581da177e4SLinus Torvalds case s_fmt:{ /* 0 */ 13591da177e4SLinus Torvalds 13602209bcb1SRalf Baechle union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); 13612209bcb1SRalf Baechle union ieee754sp fd, fr, fs, ft; 13623fccc015SRalf Baechle u32 __user *va; 13631da177e4SLinus Torvalds u32 val; 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 13661da177e4SLinus Torvalds case lwxc1_op: 13673fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 13681da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 13691da177e4SLinus Torvalds 1370b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1371515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u32))) { 1372b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1373515b029dSDavid Daney *fault_addr = va; 13741da177e4SLinus Torvalds return SIGBUS; 13751da177e4SLinus Torvalds } 1376515b029dSDavid Daney if (__get_user(val, va)) { 1377515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1378515b029dSDavid Daney *fault_addr = va; 1379515b029dSDavid Daney return SIGSEGV; 1380515b029dSDavid Daney } 13811da177e4SLinus Torvalds SITOREG(val, MIPSInst_FD(ir)); 13821da177e4SLinus Torvalds break; 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds case swxc1_op: 13853fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 13861da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 13871da177e4SLinus Torvalds 1388b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 13891da177e4SLinus Torvalds 13901da177e4SLinus Torvalds SIFROMREG(val, MIPSInst_FS(ir)); 1391515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { 1392515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1393515b029dSDavid Daney *fault_addr = va; 1394515b029dSDavid Daney return SIGBUS; 1395515b029dSDavid Daney } 13961da177e4SLinus Torvalds if (put_user(val, va)) { 1397b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1398515b029dSDavid Daney *fault_addr = va; 1399515b029dSDavid Daney return SIGSEGV; 14001da177e4SLinus Torvalds } 14011da177e4SLinus Torvalds break; 14021da177e4SLinus Torvalds 14031da177e4SLinus Torvalds case madd_s_op: 14041da177e4SLinus Torvalds handler = fpemu_sp_madd; 14051da177e4SLinus Torvalds goto scoptop; 14061da177e4SLinus Torvalds case msub_s_op: 14071da177e4SLinus Torvalds handler = fpemu_sp_msub; 14081da177e4SLinus Torvalds goto scoptop; 14091da177e4SLinus Torvalds case nmadd_s_op: 14101da177e4SLinus Torvalds handler = fpemu_sp_nmadd; 14111da177e4SLinus Torvalds goto scoptop; 14121da177e4SLinus Torvalds case nmsub_s_op: 14131da177e4SLinus Torvalds handler = fpemu_sp_nmsub; 14141da177e4SLinus Torvalds goto scoptop; 14151da177e4SLinus Torvalds 14161da177e4SLinus Torvalds scoptop: 14171da177e4SLinus Torvalds SPFROMREG(fr, MIPSInst_FR(ir)); 14181da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 14191da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 14201da177e4SLinus Torvalds fd = (*handler) (fr, fs, ft); 14211da177e4SLinus Torvalds SPTOREG(fd, MIPSInst_FD(ir)); 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds copcsr: 1424c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INEXACT)) { 1425c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_inexact); 14261da177e4SLinus Torvalds rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 1427c4103526SDeng-Cheng Zhu } 1428c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_UNDERFLOW)) { 1429c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_underflow); 14301da177e4SLinus Torvalds rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 1431c4103526SDeng-Cheng Zhu } 1432c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_OVERFLOW)) { 1433c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_overflow); 14341da177e4SLinus Torvalds rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 1435c4103526SDeng-Cheng Zhu } 1436c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { 1437c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); 14381da177e4SLinus Torvalds rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 1439c4103526SDeng-Cheng Zhu } 14401da177e4SLinus Torvalds 14411da177e4SLinus Torvalds ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 14421da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 14433f7cac41SRalf Baechle /*printk ("SIGFPE: FPU csr = %08x\n", 14441da177e4SLinus Torvalds ctx->fcr31); */ 14451da177e4SLinus Torvalds return SIGFPE; 14461da177e4SLinus Torvalds } 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds break; 14491da177e4SLinus Torvalds 14501da177e4SLinus Torvalds default: 14511da177e4SLinus Torvalds return SIGILL; 14521da177e4SLinus Torvalds } 14531da177e4SLinus Torvalds break; 14541da177e4SLinus Torvalds } 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds case d_fmt:{ /* 1 */ 14572209bcb1SRalf Baechle union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); 14582209bcb1SRalf Baechle union ieee754dp fd, fr, fs, ft; 14593fccc015SRalf Baechle u64 __user *va; 14601da177e4SLinus Torvalds u64 val; 14611da177e4SLinus Torvalds 14621da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 14631da177e4SLinus Torvalds case ldxc1_op: 14643fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 14651da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 14661da177e4SLinus Torvalds 1467b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1468515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u64))) { 1469b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1470515b029dSDavid Daney *fault_addr = va; 14711da177e4SLinus Torvalds return SIGBUS; 14721da177e4SLinus Torvalds } 1473515b029dSDavid Daney if (__get_user(val, va)) { 1474515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1475515b029dSDavid Daney *fault_addr = va; 1476515b029dSDavid Daney return SIGSEGV; 1477515b029dSDavid Daney } 14781da177e4SLinus Torvalds DITOREG(val, MIPSInst_FD(ir)); 14791da177e4SLinus Torvalds break; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds case sdxc1_op: 14823fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 14831da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 14841da177e4SLinus Torvalds 1485b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 14861da177e4SLinus Torvalds DIFROMREG(val, MIPSInst_FS(ir)); 1487515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { 1488b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1489515b029dSDavid Daney *fault_addr = va; 14901da177e4SLinus Torvalds return SIGBUS; 14911da177e4SLinus Torvalds } 1492515b029dSDavid Daney if (__put_user(val, va)) { 1493515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1494515b029dSDavid Daney *fault_addr = va; 1495515b029dSDavid Daney return SIGSEGV; 1496515b029dSDavid Daney } 14971da177e4SLinus Torvalds break; 14981da177e4SLinus Torvalds 14991da177e4SLinus Torvalds case madd_d_op: 15001da177e4SLinus Torvalds handler = fpemu_dp_madd; 15011da177e4SLinus Torvalds goto dcoptop; 15021da177e4SLinus Torvalds case msub_d_op: 15031da177e4SLinus Torvalds handler = fpemu_dp_msub; 15041da177e4SLinus Torvalds goto dcoptop; 15051da177e4SLinus Torvalds case nmadd_d_op: 15061da177e4SLinus Torvalds handler = fpemu_dp_nmadd; 15071da177e4SLinus Torvalds goto dcoptop; 15081da177e4SLinus Torvalds case nmsub_d_op: 15091da177e4SLinus Torvalds handler = fpemu_dp_nmsub; 15101da177e4SLinus Torvalds goto dcoptop; 15111da177e4SLinus Torvalds 15121da177e4SLinus Torvalds dcoptop: 15131da177e4SLinus Torvalds DPFROMREG(fr, MIPSInst_FR(ir)); 15141da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 15151da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 15161da177e4SLinus Torvalds fd = (*handler) (fr, fs, ft); 15171da177e4SLinus Torvalds DPTOREG(fd, MIPSInst_FD(ir)); 15181da177e4SLinus Torvalds goto copcsr; 15191da177e4SLinus Torvalds 15201da177e4SLinus Torvalds default: 15211da177e4SLinus Torvalds return SIGILL; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds break; 15241da177e4SLinus Torvalds } 15251da177e4SLinus Torvalds 152651061b88SDeng-Cheng Zhu case 0x3: 152751061b88SDeng-Cheng Zhu if (MIPSInst_FUNC(ir) != pfetch_op) 15281da177e4SLinus Torvalds return SIGILL; 152951061b88SDeng-Cheng Zhu 15301da177e4SLinus Torvalds /* ignore prefx operation */ 15311da177e4SLinus Torvalds break; 15321da177e4SLinus Torvalds 15331da177e4SLinus Torvalds default: 15341da177e4SLinus Torvalds return SIGILL; 15351da177e4SLinus Torvalds } 15361da177e4SLinus Torvalds 15371da177e4SLinus Torvalds return 0; 15381da177e4SLinus Torvalds } 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds 15411da177e4SLinus Torvalds 15421da177e4SLinus Torvalds /* 15431da177e4SLinus Torvalds * Emulate a single COP1 arithmetic instruction. 15441da177e4SLinus Torvalds */ 1545eae89076SAtsushi Nemoto static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 15461da177e4SLinus Torvalds mips_instruction ir) 15471da177e4SLinus Torvalds { 15481da177e4SLinus Torvalds int rfmt; /* resulting format */ 15491da177e4SLinus Torvalds unsigned rcsr = 0; /* resulting csr */ 15503f7cac41SRalf Baechle unsigned int oldrm; 15513f7cac41SRalf Baechle unsigned int cbit; 15521da177e4SLinus Torvalds unsigned cond; 15531da177e4SLinus Torvalds union { 15542209bcb1SRalf Baechle union ieee754dp d; 15552209bcb1SRalf Baechle union ieee754sp s; 15561da177e4SLinus Torvalds int w; 15571da177e4SLinus Torvalds s64 l; 15581da177e4SLinus Torvalds } rv; /* resulting value */ 15593f7cac41SRalf Baechle u64 bits; 15601da177e4SLinus Torvalds 1561b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(cp1ops); 15621da177e4SLinus Torvalds switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { 15631da177e4SLinus Torvalds case s_fmt: { /* 0 */ 15641da177e4SLinus Torvalds union { 15652209bcb1SRalf Baechle union ieee754sp(*b) (union ieee754sp, union ieee754sp); 15662209bcb1SRalf Baechle union ieee754sp(*u) (union ieee754sp); 15671da177e4SLinus Torvalds } handler; 15683f7cac41SRalf Baechle union ieee754sp fs, ft; 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 15711da177e4SLinus Torvalds /* binary ops */ 15721da177e4SLinus Torvalds case fadd_op: 15731da177e4SLinus Torvalds handler.b = ieee754sp_add; 15741da177e4SLinus Torvalds goto scopbop; 15751da177e4SLinus Torvalds case fsub_op: 15761da177e4SLinus Torvalds handler.b = ieee754sp_sub; 15771da177e4SLinus Torvalds goto scopbop; 15781da177e4SLinus Torvalds case fmul_op: 15791da177e4SLinus Torvalds handler.b = ieee754sp_mul; 15801da177e4SLinus Torvalds goto scopbop; 15811da177e4SLinus Torvalds case fdiv_op: 15821da177e4SLinus Torvalds handler.b = ieee754sp_div; 15831da177e4SLinus Torvalds goto scopbop; 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds /* unary ops */ 15861da177e4SLinus Torvalds case fsqrt_op: 15872d83fea7SMaciej W. Rozycki if (!cpu_has_mips_2_3_4_5_r) 158808a07904SRalf Baechle return SIGILL; 158908a07904SRalf Baechle 15901da177e4SLinus Torvalds handler.u = ieee754sp_sqrt; 15911da177e4SLinus Torvalds goto scopuop; 15923f7cac41SRalf Baechle 159308a07904SRalf Baechle /* 159408a07904SRalf Baechle * Note that on some MIPS IV implementations such as the 159508a07904SRalf Baechle * R5000 and R8000 the FSQRT and FRECIP instructions do not 159608a07904SRalf Baechle * achieve full IEEE-754 accuracy - however this emulator does. 159708a07904SRalf Baechle */ 15981da177e4SLinus Torvalds case frsqrt_op: 15992d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 160008a07904SRalf Baechle return SIGILL; 160108a07904SRalf Baechle 16021da177e4SLinus Torvalds handler.u = fpemu_sp_rsqrt; 16031da177e4SLinus Torvalds goto scopuop; 16043f7cac41SRalf Baechle 16051da177e4SLinus Torvalds case frecip_op: 16062d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 160708a07904SRalf Baechle return SIGILL; 160808a07904SRalf Baechle 16091da177e4SLinus Torvalds handler.u = fpemu_sp_recip; 16101da177e4SLinus Torvalds goto scopuop; 161108a07904SRalf Baechle 16121da177e4SLinus Torvalds case fmovc_op: 161308a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 161408a07904SRalf Baechle return SIGILL; 161508a07904SRalf Baechle 16161da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 16171da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) != 16181da177e4SLinus Torvalds ((MIPSInst_FT(ir) & 1) != 0)) 16191da177e4SLinus Torvalds return 0; 16201da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16211da177e4SLinus Torvalds break; 16223f7cac41SRalf Baechle 16231da177e4SLinus Torvalds case fmovz_op: 162408a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 162508a07904SRalf Baechle return SIGILL; 162608a07904SRalf Baechle 16271da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] != 0) 16281da177e4SLinus Torvalds return 0; 16291da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16301da177e4SLinus Torvalds break; 16313f7cac41SRalf Baechle 16321da177e4SLinus Torvalds case fmovn_op: 163308a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 163408a07904SRalf Baechle return SIGILL; 163508a07904SRalf Baechle 16361da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] == 0) 16371da177e4SLinus Torvalds return 0; 16381da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16391da177e4SLinus Torvalds break; 16403f7cac41SRalf Baechle 16411da177e4SLinus Torvalds case fabs_op: 16421da177e4SLinus Torvalds handler.u = ieee754sp_abs; 16431da177e4SLinus Torvalds goto scopuop; 16443f7cac41SRalf Baechle 16451da177e4SLinus Torvalds case fneg_op: 16461da177e4SLinus Torvalds handler.u = ieee754sp_neg; 16471da177e4SLinus Torvalds goto scopuop; 16483f7cac41SRalf Baechle 16491da177e4SLinus Torvalds case fmov_op: 16501da177e4SLinus Torvalds /* an easy one */ 16511da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16521da177e4SLinus Torvalds goto copcsr; 16531da177e4SLinus Torvalds 16541da177e4SLinus Torvalds /* binary op on handler */ 16551da177e4SLinus Torvalds scopbop: 16561da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 16571da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 16581da177e4SLinus Torvalds 16591da177e4SLinus Torvalds rv.s = (*handler.b) (fs, ft); 16601da177e4SLinus Torvalds goto copcsr; 16611da177e4SLinus Torvalds scopuop: 16621da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 16631da177e4SLinus Torvalds rv.s = (*handler.u) (fs); 16641da177e4SLinus Torvalds goto copcsr; 16651da177e4SLinus Torvalds copcsr: 1666c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INEXACT)) { 1667c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_inexact); 16681da177e4SLinus Torvalds rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 1669c4103526SDeng-Cheng Zhu } 1670c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_UNDERFLOW)) { 1671c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_underflow); 16721da177e4SLinus Torvalds rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 1673c4103526SDeng-Cheng Zhu } 1674c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_OVERFLOW)) { 1675c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_overflow); 16761da177e4SLinus Torvalds rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 1677c4103526SDeng-Cheng Zhu } 1678c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) { 1679c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_zerodiv); 16801da177e4SLinus Torvalds rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; 1681c4103526SDeng-Cheng Zhu } 1682c4103526SDeng-Cheng Zhu if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { 1683c4103526SDeng-Cheng Zhu MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); 16841da177e4SLinus Torvalds rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 1685c4103526SDeng-Cheng Zhu } 16861da177e4SLinus Torvalds break; 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds /* unary conv ops */ 16891da177e4SLinus Torvalds case fcvts_op: 16901da177e4SLinus Torvalds return SIGILL; /* not defined */ 16911da177e4SLinus Torvalds 16923f7cac41SRalf Baechle case fcvtd_op: 16931da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 16941da177e4SLinus Torvalds rv.d = ieee754dp_fsp(fs); 16951da177e4SLinus Torvalds rfmt = d_fmt; 16961da177e4SLinus Torvalds goto copcsr; 16971da177e4SLinus Torvalds 16983f7cac41SRalf Baechle case fcvtw_op: 16991da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17001da177e4SLinus Torvalds rv.w = ieee754sp_tint(fs); 17011da177e4SLinus Torvalds rfmt = w_fmt; 17021da177e4SLinus Torvalds goto copcsr; 17031da177e4SLinus Torvalds 17041da177e4SLinus Torvalds case fround_op: 17051da177e4SLinus Torvalds case ftrunc_op: 17061da177e4SLinus Torvalds case fceil_op: 17073f7cac41SRalf Baechle case ffloor_op: 17082d83fea7SMaciej W. Rozycki if (!cpu_has_mips_2_3_4_5_r) 170908a07904SRalf Baechle return SIGILL; 171008a07904SRalf Baechle 17113f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 17121da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17132cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 17141da177e4SLinus Torvalds rv.w = ieee754sp_tint(fs); 17151da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 17161da177e4SLinus Torvalds rfmt = w_fmt; 17171da177e4SLinus Torvalds goto copcsr; 17181da177e4SLinus Torvalds 17193f7cac41SRalf Baechle case fcvtl_op: 17202d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 172108a07904SRalf Baechle return SIGILL; 172208a07904SRalf Baechle 17231da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17241da177e4SLinus Torvalds rv.l = ieee754sp_tlong(fs); 17251da177e4SLinus Torvalds rfmt = l_fmt; 17261da177e4SLinus Torvalds goto copcsr; 17271da177e4SLinus Torvalds 17281da177e4SLinus Torvalds case froundl_op: 17291da177e4SLinus Torvalds case ftruncl_op: 17301da177e4SLinus Torvalds case fceill_op: 17313f7cac41SRalf Baechle case ffloorl_op: 17322d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 173308a07904SRalf Baechle return SIGILL; 173408a07904SRalf Baechle 17353f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 17361da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17372cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 17381da177e4SLinus Torvalds rv.l = ieee754sp_tlong(fs); 17391da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 17401da177e4SLinus Torvalds rfmt = l_fmt; 17411da177e4SLinus Torvalds goto copcsr; 17421da177e4SLinus Torvalds 17431da177e4SLinus Torvalds default: 17441da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) >= fcmp_op) { 17451da177e4SLinus Torvalds unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 17462209bcb1SRalf Baechle union ieee754sp fs, ft; 17471da177e4SLinus Torvalds 17481da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17491da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 17501da177e4SLinus Torvalds rv.w = ieee754sp_cmp(fs, ft, 17511da177e4SLinus Torvalds cmptab[cmpop & 0x7], cmpop & 0x8); 17521da177e4SLinus Torvalds rfmt = -1; 17531da177e4SLinus Torvalds if ((cmpop & 0x8) && ieee754_cxtest 17541da177e4SLinus Torvalds (IEEE754_INVALID_OPERATION)) 17551da177e4SLinus Torvalds rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 17561da177e4SLinus Torvalds else 17571da177e4SLinus Torvalds goto copcsr; 17581da177e4SLinus Torvalds 17593f7cac41SRalf Baechle } else 17601da177e4SLinus Torvalds return SIGILL; 17611da177e4SLinus Torvalds break; 17621da177e4SLinus Torvalds } 17631da177e4SLinus Torvalds break; 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds case d_fmt: { 17673f7cac41SRalf Baechle union ieee754dp fs, ft; 17681da177e4SLinus Torvalds union { 17692209bcb1SRalf Baechle union ieee754dp(*b) (union ieee754dp, union ieee754dp); 17702209bcb1SRalf Baechle union ieee754dp(*u) (union ieee754dp); 17711da177e4SLinus Torvalds } handler; 17721da177e4SLinus Torvalds 17731da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 17741da177e4SLinus Torvalds /* binary ops */ 17751da177e4SLinus Torvalds case fadd_op: 17761da177e4SLinus Torvalds handler.b = ieee754dp_add; 17771da177e4SLinus Torvalds goto dcopbop; 17781da177e4SLinus Torvalds case fsub_op: 17791da177e4SLinus Torvalds handler.b = ieee754dp_sub; 17801da177e4SLinus Torvalds goto dcopbop; 17811da177e4SLinus Torvalds case fmul_op: 17821da177e4SLinus Torvalds handler.b = ieee754dp_mul; 17831da177e4SLinus Torvalds goto dcopbop; 17841da177e4SLinus Torvalds case fdiv_op: 17851da177e4SLinus Torvalds handler.b = ieee754dp_div; 17861da177e4SLinus Torvalds goto dcopbop; 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds /* unary ops */ 17891da177e4SLinus Torvalds case fsqrt_op: 179008a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5_r) 179108a07904SRalf Baechle return SIGILL; 179208a07904SRalf Baechle 17931da177e4SLinus Torvalds handler.u = ieee754dp_sqrt; 17941da177e4SLinus Torvalds goto dcopuop; 179508a07904SRalf Baechle /* 179608a07904SRalf Baechle * Note that on some MIPS IV implementations such as the 179708a07904SRalf Baechle * R5000 and R8000 the FSQRT and FRECIP instructions do not 179808a07904SRalf Baechle * achieve full IEEE-754 accuracy - however this emulator does. 179908a07904SRalf Baechle */ 18001da177e4SLinus Torvalds case frsqrt_op: 18012d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 180208a07904SRalf Baechle return SIGILL; 180308a07904SRalf Baechle 18041da177e4SLinus Torvalds handler.u = fpemu_dp_rsqrt; 18051da177e4SLinus Torvalds goto dcopuop; 18061da177e4SLinus Torvalds case frecip_op: 18072d83fea7SMaciej W. Rozycki if (!cpu_has_mips_4_5_64_r2_r6) 180808a07904SRalf Baechle return SIGILL; 180908a07904SRalf Baechle 18101da177e4SLinus Torvalds handler.u = fpemu_dp_recip; 18111da177e4SLinus Torvalds goto dcopuop; 18121da177e4SLinus Torvalds case fmovc_op: 181308a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 181408a07904SRalf Baechle return SIGILL; 181508a07904SRalf Baechle 18161da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 18171da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) != 18181da177e4SLinus Torvalds ((MIPSInst_FT(ir) & 1) != 0)) 18191da177e4SLinus Torvalds return 0; 18201da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18211da177e4SLinus Torvalds break; 18221da177e4SLinus Torvalds case fmovz_op: 182308a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 182408a07904SRalf Baechle return SIGILL; 182508a07904SRalf Baechle 18261da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] != 0) 18271da177e4SLinus Torvalds return 0; 18281da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18291da177e4SLinus Torvalds break; 18301da177e4SLinus Torvalds case fmovn_op: 183108a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 183208a07904SRalf Baechle return SIGILL; 183308a07904SRalf Baechle 18341da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] == 0) 18351da177e4SLinus Torvalds return 0; 18361da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18371da177e4SLinus Torvalds break; 18381da177e4SLinus Torvalds case fabs_op: 18391da177e4SLinus Torvalds handler.u = ieee754dp_abs; 18401da177e4SLinus Torvalds goto dcopuop; 18411da177e4SLinus Torvalds 18421da177e4SLinus Torvalds case fneg_op: 18431da177e4SLinus Torvalds handler.u = ieee754dp_neg; 18441da177e4SLinus Torvalds goto dcopuop; 18451da177e4SLinus Torvalds 18461da177e4SLinus Torvalds case fmov_op: 18471da177e4SLinus Torvalds /* an easy one */ 18481da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18491da177e4SLinus Torvalds goto copcsr; 18501da177e4SLinus Torvalds 18511da177e4SLinus Torvalds /* binary op on handler */ 18523f7cac41SRalf Baechle dcopbop: 18531da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 18541da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 18551da177e4SLinus Torvalds 18561da177e4SLinus Torvalds rv.d = (*handler.b) (fs, ft); 18571da177e4SLinus Torvalds goto copcsr; 18583f7cac41SRalf Baechle dcopuop: 18591da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 18601da177e4SLinus Torvalds rv.d = (*handler.u) (fs); 18611da177e4SLinus Torvalds goto copcsr; 18621da177e4SLinus Torvalds 18633f7cac41SRalf Baechle /* 18643f7cac41SRalf Baechle * unary conv ops 18653f7cac41SRalf Baechle */ 18663f7cac41SRalf Baechle case fcvts_op: 18671da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 18681da177e4SLinus Torvalds rv.s = ieee754sp_fdp(fs); 18691da177e4SLinus Torvalds rfmt = s_fmt; 18701da177e4SLinus Torvalds goto copcsr; 18713f7cac41SRalf Baechle 18721da177e4SLinus Torvalds case fcvtd_op: 18731da177e4SLinus Torvalds return SIGILL; /* not defined */ 18741da177e4SLinus Torvalds 18753f7cac41SRalf Baechle case fcvtw_op: 18761da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 18771da177e4SLinus Torvalds rv.w = ieee754dp_tint(fs); /* wrong */ 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: 188508a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5_r) 188608a07904SRalf Baechle return SIGILL; 188708a07904SRalf Baechle 18883f7cac41SRalf Baechle oldrm = ieee754_csr.rm; 18891da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 18902cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 18911da177e4SLinus Torvalds rv.w = ieee754dp_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 DPFROMREG(fs, MIPSInst_FS(ir)); 19011da177e4SLinus Torvalds rv.l = ieee754dp_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 DPFROMREG(fs, MIPSInst_FS(ir)); 19142cfcf8a8SMaciej W. Rozycki ieee754_csr.rm = MIPSInst_FUNC(ir); 19151da177e4SLinus Torvalds rv.l = ieee754dp_tlong(fs); 19161da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 19171da177e4SLinus Torvalds rfmt = l_fmt; 19181da177e4SLinus Torvalds goto copcsr; 19191da177e4SLinus Torvalds 19201da177e4SLinus Torvalds default: 19211da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) >= fcmp_op) { 19221da177e4SLinus Torvalds unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 19232209bcb1SRalf Baechle union ieee754dp fs, ft; 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19261da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 19271da177e4SLinus Torvalds rv.w = ieee754dp_cmp(fs, ft, 19281da177e4SLinus Torvalds cmptab[cmpop & 0x7], cmpop & 0x8); 19291da177e4SLinus Torvalds rfmt = -1; 19301da177e4SLinus Torvalds if ((cmpop & 0x8) 19311da177e4SLinus Torvalds && 19321da177e4SLinus Torvalds ieee754_cxtest 19331da177e4SLinus Torvalds (IEEE754_INVALID_OPERATION)) 19341da177e4SLinus Torvalds rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 19351da177e4SLinus Torvalds else 19361da177e4SLinus Torvalds goto copcsr; 19371da177e4SLinus Torvalds 19381da177e4SLinus Torvalds } 19391da177e4SLinus Torvalds else { 19401da177e4SLinus Torvalds return SIGILL; 19411da177e4SLinus Torvalds } 19421da177e4SLinus Torvalds break; 19431da177e4SLinus Torvalds } 19441da177e4SLinus Torvalds break; 19451da177e4SLinus Torvalds 19463f7cac41SRalf Baechle case w_fmt: 19471da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 19481da177e4SLinus Torvalds case fcvts_op: 19491da177e4SLinus Torvalds /* convert word to single precision real */ 19501da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 19511da177e4SLinus Torvalds rv.s = ieee754sp_fint(fs.bits); 19521da177e4SLinus Torvalds rfmt = s_fmt; 19531da177e4SLinus Torvalds goto copcsr; 19541da177e4SLinus Torvalds case fcvtd_op: 19551da177e4SLinus Torvalds /* convert word to double precision real */ 19561da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 19571da177e4SLinus Torvalds rv.d = ieee754dp_fint(fs.bits); 19581da177e4SLinus Torvalds rfmt = d_fmt; 19591da177e4SLinus Torvalds goto copcsr; 19601da177e4SLinus Torvalds default: 19611da177e4SLinus Torvalds return SIGILL; 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds break; 19641da177e4SLinus Torvalds } 19651da177e4SLinus Torvalds 19663f7cac41SRalf Baechle case l_fmt: 196708a07904SRalf Baechle 19682d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 196908a07904SRalf Baechle return SIGILL; 197008a07904SRalf Baechle 1971bbd426f5SPaul Burton DIFROMREG(bits, MIPSInst_FS(ir)); 1972bbd426f5SPaul Burton 19731da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 19741da177e4SLinus Torvalds case fcvts_op: 19751da177e4SLinus Torvalds /* convert long to single precision real */ 1976bbd426f5SPaul Burton rv.s = ieee754sp_flong(bits); 19771da177e4SLinus Torvalds rfmt = s_fmt; 19781da177e4SLinus Torvalds goto copcsr; 19791da177e4SLinus Torvalds case fcvtd_op: 19801da177e4SLinus Torvalds /* convert long to double precision real */ 1981bbd426f5SPaul Burton rv.d = ieee754dp_flong(bits); 19821da177e4SLinus Torvalds rfmt = d_fmt; 19831da177e4SLinus Torvalds goto copcsr; 19841da177e4SLinus Torvalds default: 19851da177e4SLinus Torvalds return SIGILL; 19861da177e4SLinus Torvalds } 19871da177e4SLinus Torvalds break; 19881da177e4SLinus Torvalds 19891da177e4SLinus Torvalds default: 19901da177e4SLinus Torvalds return SIGILL; 19911da177e4SLinus Torvalds } 19921da177e4SLinus Torvalds 19931da177e4SLinus Torvalds /* 19941da177e4SLinus Torvalds * Update the fpu CSR register for this operation. 19951da177e4SLinus Torvalds * If an exception is required, generate a tidy SIGFPE exception, 19961da177e4SLinus Torvalds * without updating the result register. 19971da177e4SLinus Torvalds * Note: cause exception bits do not accumulate, they are rewritten 19981da177e4SLinus Torvalds * for each op; only the flag/sticky bits accumulate. 19991da177e4SLinus Torvalds */ 20001da177e4SLinus Torvalds ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 20011da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 20023f7cac41SRalf Baechle /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */ 20031da177e4SLinus Torvalds return SIGFPE; 20041da177e4SLinus Torvalds } 20051da177e4SLinus Torvalds 20061da177e4SLinus Torvalds /* 20071da177e4SLinus Torvalds * Now we can safely write the result back to the register file. 20081da177e4SLinus Torvalds */ 20091da177e4SLinus Torvalds switch (rfmt) { 201008a07904SRalf Baechle case -1: 201108a07904SRalf Baechle 201208a07904SRalf Baechle if (cpu_has_mips_4_5_r) 2013c3b9b945SRob Kendrick cbit = fpucondbit[MIPSInst_FD(ir) >> 2]; 20141da177e4SLinus Torvalds else 201508a07904SRalf Baechle cbit = FPU_CSR_COND; 201608a07904SRalf Baechle if (rv.w) 201708a07904SRalf Baechle ctx->fcr31 |= cbit; 201808a07904SRalf Baechle else 201908a07904SRalf Baechle ctx->fcr31 &= ~cbit; 20201da177e4SLinus Torvalds break; 202108a07904SRalf Baechle 20221da177e4SLinus Torvalds case d_fmt: 20231da177e4SLinus Torvalds DPTOREG(rv.d, MIPSInst_FD(ir)); 20241da177e4SLinus Torvalds break; 20251da177e4SLinus Torvalds case s_fmt: 20261da177e4SLinus Torvalds SPTOREG(rv.s, MIPSInst_FD(ir)); 20271da177e4SLinus Torvalds break; 20281da177e4SLinus Torvalds case w_fmt: 20291da177e4SLinus Torvalds SITOREG(rv.w, MIPSInst_FD(ir)); 20301da177e4SLinus Torvalds break; 20311da177e4SLinus Torvalds case l_fmt: 20322d83fea7SMaciej W. Rozycki if (!cpu_has_mips_3_4_5_64_r2_r6) 203308a07904SRalf Baechle return SIGILL; 203408a07904SRalf Baechle 20351da177e4SLinus Torvalds DITOREG(rv.l, MIPSInst_FD(ir)); 20361da177e4SLinus Torvalds break; 20371da177e4SLinus Torvalds default: 20381da177e4SLinus Torvalds return SIGILL; 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds return 0; 20421da177e4SLinus Torvalds } 20431da177e4SLinus Torvalds 2044e04582b7SAtsushi Nemoto int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 2045515b029dSDavid Daney int has_fpu, void *__user *fault_addr) 20461da177e4SLinus Torvalds { 2047333d1f67SRalf Baechle unsigned long oldepc, prevepc; 2048102cedc3SLeonid Yegoshin struct mm_decoded_insn dec_insn; 2049102cedc3SLeonid Yegoshin u16 instr[4]; 2050102cedc3SLeonid Yegoshin u16 *instr_ptr; 20511da177e4SLinus Torvalds int sig = 0; 20521da177e4SLinus Torvalds 20531da177e4SLinus Torvalds oldepc = xcp->cp0_epc; 20541da177e4SLinus Torvalds do { 20551da177e4SLinus Torvalds prevepc = xcp->cp0_epc; 20561da177e4SLinus Torvalds 2057102cedc3SLeonid Yegoshin if (get_isa16_mode(prevepc) && cpu_has_mmips) { 2058102cedc3SLeonid Yegoshin /* 2059102cedc3SLeonid Yegoshin * Get next 2 microMIPS instructions and convert them 2060102cedc3SLeonid Yegoshin * into 32-bit instructions. 2061102cedc3SLeonid Yegoshin */ 2062102cedc3SLeonid Yegoshin if ((get_user(instr[0], (u16 __user *)msk_isa16_mode(xcp->cp0_epc))) || 2063102cedc3SLeonid Yegoshin (get_user(instr[1], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 2))) || 2064102cedc3SLeonid Yegoshin (get_user(instr[2], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 4))) || 2065102cedc3SLeonid Yegoshin (get_user(instr[3], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 6)))) { 2066b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 20671da177e4SLinus Torvalds return SIGBUS; 20681da177e4SLinus Torvalds } 2069102cedc3SLeonid Yegoshin instr_ptr = instr; 2070102cedc3SLeonid Yegoshin 2071102cedc3SLeonid Yegoshin /* Get first instruction. */ 2072102cedc3SLeonid Yegoshin if (mm_insn_16bit(*instr_ptr)) { 2073102cedc3SLeonid Yegoshin /* Duplicate the half-word. */ 2074102cedc3SLeonid Yegoshin dec_insn.insn = (*instr_ptr << 16) | 2075102cedc3SLeonid Yegoshin (*instr_ptr); 2076102cedc3SLeonid Yegoshin /* 16-bit instruction. */ 2077102cedc3SLeonid Yegoshin dec_insn.pc_inc = 2; 2078102cedc3SLeonid Yegoshin instr_ptr += 1; 2079102cedc3SLeonid Yegoshin } else { 2080102cedc3SLeonid Yegoshin dec_insn.insn = (*instr_ptr << 16) | 2081102cedc3SLeonid Yegoshin *(instr_ptr+1); 2082102cedc3SLeonid Yegoshin /* 32-bit instruction. */ 2083102cedc3SLeonid Yegoshin dec_insn.pc_inc = 4; 2084102cedc3SLeonid Yegoshin instr_ptr += 2; 2085515b029dSDavid Daney } 2086102cedc3SLeonid Yegoshin /* Get second instruction. */ 2087102cedc3SLeonid Yegoshin if (mm_insn_16bit(*instr_ptr)) { 2088102cedc3SLeonid Yegoshin /* Duplicate the half-word. */ 2089102cedc3SLeonid Yegoshin dec_insn.next_insn = (*instr_ptr << 16) | 2090102cedc3SLeonid Yegoshin (*instr_ptr); 2091102cedc3SLeonid Yegoshin /* 16-bit instruction. */ 2092102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 2; 2093102cedc3SLeonid Yegoshin } else { 2094102cedc3SLeonid Yegoshin dec_insn.next_insn = (*instr_ptr << 16) | 2095102cedc3SLeonid Yegoshin *(instr_ptr+1); 2096102cedc3SLeonid Yegoshin /* 32-bit instruction. */ 2097102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 4; 2098102cedc3SLeonid Yegoshin } 2099102cedc3SLeonid Yegoshin dec_insn.micro_mips_mode = 1; 2100102cedc3SLeonid Yegoshin } else { 2101102cedc3SLeonid Yegoshin if ((get_user(dec_insn.insn, 2102102cedc3SLeonid Yegoshin (mips_instruction __user *) xcp->cp0_epc)) || 2103102cedc3SLeonid Yegoshin (get_user(dec_insn.next_insn, 2104102cedc3SLeonid Yegoshin (mips_instruction __user *)(xcp->cp0_epc+4)))) { 2105102cedc3SLeonid Yegoshin MIPS_FPU_EMU_INC_STATS(errors); 2106102cedc3SLeonid Yegoshin return SIGBUS; 2107102cedc3SLeonid Yegoshin } 2108102cedc3SLeonid Yegoshin dec_insn.pc_inc = 4; 2109102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 4; 2110102cedc3SLeonid Yegoshin dec_insn.micro_mips_mode = 0; 2111102cedc3SLeonid Yegoshin } 2112102cedc3SLeonid Yegoshin 2113102cedc3SLeonid Yegoshin if ((dec_insn.insn == 0) || 2114102cedc3SLeonid Yegoshin ((dec_insn.pc_inc == 2) && 2115102cedc3SLeonid Yegoshin ((dec_insn.insn & 0xffff) == MM_NOP16))) 2116102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; /* Skip NOPs */ 21171da177e4SLinus Torvalds else { 2118cd21dfcfSRalf Baechle /* 21192cfcf8a8SMaciej W. Rozycki * The 'ieee754_csr' is an alias of ctx->fcr31. 21202cfcf8a8SMaciej W. Rozycki * No need to copy ctx->fcr31 to ieee754_csr. 2121cd21dfcfSRalf Baechle */ 2122102cedc3SLeonid Yegoshin sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); 21231da177e4SLinus Torvalds } 21241da177e4SLinus Torvalds 2125e04582b7SAtsushi Nemoto if (has_fpu) 21261da177e4SLinus Torvalds break; 21271da177e4SLinus Torvalds if (sig) 21281da177e4SLinus Torvalds break; 21291da177e4SLinus Torvalds 21301da177e4SLinus Torvalds cond_resched(); 21311da177e4SLinus Torvalds } while (xcp->cp0_epc > prevepc); 21321da177e4SLinus Torvalds 21331da177e4SLinus Torvalds /* SIGILL indicates a non-fpu instruction */ 21341da177e4SLinus Torvalds if (sig == SIGILL && xcp->cp0_epc != oldepc) 21353f7cac41SRalf Baechle /* but if EPC has advanced, then ignore it */ 21361da177e4SLinus Torvalds sig = 0; 21371da177e4SLinus Torvalds 21381da177e4SLinus Torvalds return sig; 21391da177e4SLinus Torvalds } 2140