11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * 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., 211da177e4SLinus Torvalds * 59 Temple Place - Suite 330, Boston MA 02111-1307, 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 281da177e4SLinus Torvalds * 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 * 331da177e4SLinus Torvalds * 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> 38*08a07904SRalf 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> 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds #include "ieee754.h" 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* Function which emulates a floating point instruction. */ 551da177e4SLinus Torvalds 56eae89076SAtsushi Nemoto static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, 571da177e4SLinus Torvalds mips_instruction); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds static int fpux_emu(struct pt_regs *, 60515b029dSDavid Daney struct mips_fpu_struct *, mips_instruction, void *__user *); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds /* Control registers */ 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds #define FPCREG_RID 0 /* $0 = revision id */ 651da177e4SLinus Torvalds #define FPCREG_CSR 31 /* $31 = csr */ 661da177e4SLinus Torvalds 6795e8f634SShane McDonald /* Determine rounding mode from the RM bits of the FCSR */ 6895e8f634SShane McDonald #define modeindex(v) ((v) & FPU_CSR_RM) 6995e8f634SShane McDonald 70102cedc3SLeonid Yegoshin /* microMIPS bitfields */ 71102cedc3SLeonid Yegoshin #define MM_POOL32A_MINOR_MASK 0x3f 72102cedc3SLeonid Yegoshin #define MM_POOL32A_MINOR_SHIFT 0x6 73102cedc3SLeonid Yegoshin #define MM_MIPS32_COND_FC 0x30 74102cedc3SLeonid Yegoshin 751da177e4SLinus Torvalds /* Convert Mips rounding mode (0..3) to IEEE library modes. */ 761da177e4SLinus Torvalds static const unsigned char ieee_rm[4] = { 77cd21dfcfSRalf Baechle [FPU_CSR_RN] = IEEE754_RN, 78cd21dfcfSRalf Baechle [FPU_CSR_RZ] = IEEE754_RZ, 79cd21dfcfSRalf Baechle [FPU_CSR_RU] = IEEE754_RU, 80cd21dfcfSRalf Baechle [FPU_CSR_RD] = IEEE754_RD, 81cd21dfcfSRalf Baechle }; 82cd21dfcfSRalf Baechle /* Convert IEEE library modes to Mips rounding mode (0..3). */ 83cd21dfcfSRalf Baechle static const unsigned char mips_rm[4] = { 84cd21dfcfSRalf Baechle [IEEE754_RN] = FPU_CSR_RN, 85cd21dfcfSRalf Baechle [IEEE754_RZ] = FPU_CSR_RZ, 86cd21dfcfSRalf Baechle [IEEE754_RD] = FPU_CSR_RD, 87cd21dfcfSRalf Baechle [IEEE754_RU] = FPU_CSR_RU, 881da177e4SLinus Torvalds }; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* convert condition code register number to csr bit */ 911da177e4SLinus Torvalds static const unsigned int fpucondbit[8] = { 921da177e4SLinus Torvalds FPU_CSR_COND0, 931da177e4SLinus Torvalds FPU_CSR_COND1, 941da177e4SLinus Torvalds FPU_CSR_COND2, 951da177e4SLinus Torvalds FPU_CSR_COND3, 961da177e4SLinus Torvalds FPU_CSR_COND4, 971da177e4SLinus Torvalds FPU_CSR_COND5, 981da177e4SLinus Torvalds FPU_CSR_COND6, 991da177e4SLinus Torvalds FPU_CSR_COND7 1001da177e4SLinus Torvalds }; 1011da177e4SLinus Torvalds 102102cedc3SLeonid Yegoshin /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ 103102cedc3SLeonid Yegoshin static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; 104102cedc3SLeonid Yegoshin 105102cedc3SLeonid Yegoshin /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ 106102cedc3SLeonid Yegoshin static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; 107102cedc3SLeonid Yegoshin static const int sdps_format[] = {16, 17, 22, 0, 0, 0, 0, 0}; 108102cedc3SLeonid Yegoshin static const int dwl_format[] = {17, 20, 21, 0, 0, 0, 0, 0}; 109102cedc3SLeonid Yegoshin static const int swl_format[] = {16, 20, 21, 0, 0, 0, 0, 0}; 110102cedc3SLeonid Yegoshin 111102cedc3SLeonid Yegoshin /* 112102cedc3SLeonid Yegoshin * This functions translates a 32-bit microMIPS instruction 113102cedc3SLeonid Yegoshin * into a 32-bit MIPS32 instruction. Returns 0 on success 114102cedc3SLeonid Yegoshin * and SIGILL otherwise. 115102cedc3SLeonid Yegoshin */ 116102cedc3SLeonid Yegoshin static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) 117102cedc3SLeonid Yegoshin { 118102cedc3SLeonid Yegoshin union mips_instruction insn = *insn_ptr; 119102cedc3SLeonid Yegoshin union mips_instruction mips32_insn = insn; 120102cedc3SLeonid Yegoshin int func, fmt, op; 121102cedc3SLeonid Yegoshin 122102cedc3SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 123102cedc3SLeonid Yegoshin case mm_ldc132_op: 124102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = ldc1_op; 125102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 126102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 127102cedc3SLeonid Yegoshin break; 128102cedc3SLeonid Yegoshin case mm_lwc132_op: 129102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = lwc1_op; 130102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 131102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 132102cedc3SLeonid Yegoshin break; 133102cedc3SLeonid Yegoshin case mm_sdc132_op: 134102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = sdc1_op; 135102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 136102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 137102cedc3SLeonid Yegoshin break; 138102cedc3SLeonid Yegoshin case mm_swc132_op: 139102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.opcode = swc1_op; 140102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rt = insn.mm_i_format.rs; 141102cedc3SLeonid Yegoshin mips32_insn.mm_i_format.rs = insn.mm_i_format.rt; 142102cedc3SLeonid Yegoshin break; 143102cedc3SLeonid Yegoshin case mm_pool32i_op: 144102cedc3SLeonid Yegoshin /* NOTE: offset is << by 1 if in microMIPS mode. */ 145102cedc3SLeonid Yegoshin if ((insn.mm_i_format.rt == mm_bc1f_op) || 146102cedc3SLeonid Yegoshin (insn.mm_i_format.rt == mm_bc1t_op)) { 147102cedc3SLeonid Yegoshin mips32_insn.fb_format.opcode = cop1_op; 148102cedc3SLeonid Yegoshin mips32_insn.fb_format.bc = bc_op; 149102cedc3SLeonid Yegoshin mips32_insn.fb_format.flag = 150102cedc3SLeonid Yegoshin (insn.mm_i_format.rt == mm_bc1t_op) ? 1 : 0; 151102cedc3SLeonid Yegoshin } else 152102cedc3SLeonid Yegoshin return SIGILL; 153102cedc3SLeonid Yegoshin break; 154102cedc3SLeonid Yegoshin case mm_pool32f_op: 155102cedc3SLeonid Yegoshin switch (insn.mm_fp0_format.func) { 156102cedc3SLeonid Yegoshin case mm_32f_01_op: 157102cedc3SLeonid Yegoshin case mm_32f_11_op: 158102cedc3SLeonid Yegoshin case mm_32f_02_op: 159102cedc3SLeonid Yegoshin case mm_32f_12_op: 160102cedc3SLeonid Yegoshin case mm_32f_41_op: 161102cedc3SLeonid Yegoshin case mm_32f_51_op: 162102cedc3SLeonid Yegoshin case mm_32f_42_op: 163102cedc3SLeonid Yegoshin case mm_32f_52_op: 164102cedc3SLeonid Yegoshin op = insn.mm_fp0_format.func; 165102cedc3SLeonid Yegoshin if (op == mm_32f_01_op) 166102cedc3SLeonid Yegoshin func = madd_s_op; 167102cedc3SLeonid Yegoshin else if (op == mm_32f_11_op) 168102cedc3SLeonid Yegoshin func = madd_d_op; 169102cedc3SLeonid Yegoshin else if (op == mm_32f_02_op) 170102cedc3SLeonid Yegoshin func = nmadd_s_op; 171102cedc3SLeonid Yegoshin else if (op == mm_32f_12_op) 172102cedc3SLeonid Yegoshin func = nmadd_d_op; 173102cedc3SLeonid Yegoshin else if (op == mm_32f_41_op) 174102cedc3SLeonid Yegoshin func = msub_s_op; 175102cedc3SLeonid Yegoshin else if (op == mm_32f_51_op) 176102cedc3SLeonid Yegoshin func = msub_d_op; 177102cedc3SLeonid Yegoshin else if (op == mm_32f_42_op) 178102cedc3SLeonid Yegoshin func = nmsub_s_op; 179102cedc3SLeonid Yegoshin else 180102cedc3SLeonid Yegoshin func = nmsub_d_op; 181102cedc3SLeonid Yegoshin mips32_insn.fp6_format.opcode = cop1x_op; 182102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fr = insn.mm_fp6_format.fr; 183102cedc3SLeonid Yegoshin mips32_insn.fp6_format.ft = insn.mm_fp6_format.ft; 184102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fs = insn.mm_fp6_format.fs; 185102cedc3SLeonid Yegoshin mips32_insn.fp6_format.fd = insn.mm_fp6_format.fd; 186102cedc3SLeonid Yegoshin mips32_insn.fp6_format.func = func; 187102cedc3SLeonid Yegoshin break; 188102cedc3SLeonid Yegoshin case mm_32f_10_op: 189102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 190102cedc3SLeonid Yegoshin op = insn.mm_fp5_format.op & 0x7; 191102cedc3SLeonid Yegoshin if (op == mm_ldxc1_op) 192102cedc3SLeonid Yegoshin func = ldxc1_op; 193102cedc3SLeonid Yegoshin else if (op == mm_sdxc1_op) 194102cedc3SLeonid Yegoshin func = sdxc1_op; 195102cedc3SLeonid Yegoshin else if (op == mm_lwxc1_op) 196102cedc3SLeonid Yegoshin func = lwxc1_op; 197102cedc3SLeonid Yegoshin else if (op == mm_swxc1_op) 198102cedc3SLeonid Yegoshin func = swxc1_op; 199102cedc3SLeonid Yegoshin 200102cedc3SLeonid Yegoshin if (func != -1) { 201102cedc3SLeonid Yegoshin mips32_insn.r_format.opcode = cop1x_op; 202102cedc3SLeonid Yegoshin mips32_insn.r_format.rs = 203102cedc3SLeonid Yegoshin insn.mm_fp5_format.base; 204102cedc3SLeonid Yegoshin mips32_insn.r_format.rt = 205102cedc3SLeonid Yegoshin insn.mm_fp5_format.index; 206102cedc3SLeonid Yegoshin mips32_insn.r_format.rd = 0; 207102cedc3SLeonid Yegoshin mips32_insn.r_format.re = insn.mm_fp5_format.fd; 208102cedc3SLeonid Yegoshin mips32_insn.r_format.func = func; 209102cedc3SLeonid Yegoshin } else 210102cedc3SLeonid Yegoshin return SIGILL; 211102cedc3SLeonid Yegoshin break; 212102cedc3SLeonid Yegoshin case mm_32f_40_op: 213102cedc3SLeonid Yegoshin op = -1; /* Invalid */ 214102cedc3SLeonid Yegoshin if (insn.mm_fp2_format.op == mm_fmovt_op) 215102cedc3SLeonid Yegoshin op = 1; 216102cedc3SLeonid Yegoshin else if (insn.mm_fp2_format.op == mm_fmovf_op) 217102cedc3SLeonid Yegoshin op = 0; 218102cedc3SLeonid Yegoshin if (op != -1) { 219102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 220102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 221102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp2_format.fmt]; 222102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 223102cedc3SLeonid Yegoshin (insn.mm_fp2_format.cc<<2) + op; 224102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 225102cedc3SLeonid Yegoshin insn.mm_fp2_format.fs; 226102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 227102cedc3SLeonid Yegoshin insn.mm_fp2_format.fd; 228102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = fmovc_op; 229102cedc3SLeonid Yegoshin } else 230102cedc3SLeonid Yegoshin return SIGILL; 231102cedc3SLeonid Yegoshin break; 232102cedc3SLeonid Yegoshin case mm_32f_60_op: 233102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 234102cedc3SLeonid Yegoshin if (insn.mm_fp0_format.op == mm_fadd_op) 235102cedc3SLeonid Yegoshin func = fadd_op; 236102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fsub_op) 237102cedc3SLeonid Yegoshin func = fsub_op; 238102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fmul_op) 239102cedc3SLeonid Yegoshin func = fmul_op; 240102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fdiv_op) 241102cedc3SLeonid Yegoshin func = fdiv_op; 242102cedc3SLeonid Yegoshin if (func != -1) { 243102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 244102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 245102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp0_format.fmt]; 246102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 247102cedc3SLeonid Yegoshin insn.mm_fp0_format.ft; 248102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 249102cedc3SLeonid Yegoshin insn.mm_fp0_format.fs; 250102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 251102cedc3SLeonid Yegoshin insn.mm_fp0_format.fd; 252102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 253102cedc3SLeonid Yegoshin } else 254102cedc3SLeonid Yegoshin return SIGILL; 255102cedc3SLeonid Yegoshin break; 256102cedc3SLeonid Yegoshin case mm_32f_70_op: 257102cedc3SLeonid Yegoshin func = -1; /* Invalid */ 258102cedc3SLeonid Yegoshin if (insn.mm_fp0_format.op == mm_fmovn_op) 259102cedc3SLeonid Yegoshin func = fmovn_op; 260102cedc3SLeonid Yegoshin else if (insn.mm_fp0_format.op == mm_fmovz_op) 261102cedc3SLeonid Yegoshin func = fmovz_op; 262102cedc3SLeonid Yegoshin if (func != -1) { 263102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 264102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 265102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp0_format.fmt]; 266102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 267102cedc3SLeonid Yegoshin insn.mm_fp0_format.ft; 268102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 269102cedc3SLeonid Yegoshin insn.mm_fp0_format.fs; 270102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 271102cedc3SLeonid Yegoshin insn.mm_fp0_format.fd; 272102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 273102cedc3SLeonid Yegoshin } else 274102cedc3SLeonid Yegoshin return SIGILL; 275102cedc3SLeonid Yegoshin break; 276102cedc3SLeonid Yegoshin case mm_32f_73_op: /* POOL32FXF */ 277102cedc3SLeonid Yegoshin switch (insn.mm_fp1_format.op) { 278102cedc3SLeonid Yegoshin case mm_movf0_op: 279102cedc3SLeonid Yegoshin case mm_movf1_op: 280102cedc3SLeonid Yegoshin case mm_movt0_op: 281102cedc3SLeonid Yegoshin case mm_movt1_op: 282102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 283102cedc3SLeonid Yegoshin mm_movf0_op) 284102cedc3SLeonid Yegoshin op = 0; 285102cedc3SLeonid Yegoshin else 286102cedc3SLeonid Yegoshin op = 1; 287102cedc3SLeonid Yegoshin mips32_insn.r_format.opcode = spec_op; 288102cedc3SLeonid Yegoshin mips32_insn.r_format.rs = insn.mm_fp4_format.fs; 289102cedc3SLeonid Yegoshin mips32_insn.r_format.rt = 290102cedc3SLeonid Yegoshin (insn.mm_fp4_format.cc << 2) + op; 291102cedc3SLeonid Yegoshin mips32_insn.r_format.rd = insn.mm_fp4_format.rt; 292102cedc3SLeonid Yegoshin mips32_insn.r_format.re = 0; 293102cedc3SLeonid Yegoshin mips32_insn.r_format.func = movc_op; 294102cedc3SLeonid Yegoshin break; 295102cedc3SLeonid Yegoshin case mm_fcvtd0_op: 296102cedc3SLeonid Yegoshin case mm_fcvtd1_op: 297102cedc3SLeonid Yegoshin case mm_fcvts0_op: 298102cedc3SLeonid Yegoshin case mm_fcvts1_op: 299102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 300102cedc3SLeonid Yegoshin mm_fcvtd0_op) { 301102cedc3SLeonid Yegoshin func = fcvtd_op; 302102cedc3SLeonid Yegoshin fmt = swl_format[insn.mm_fp3_format.fmt]; 303102cedc3SLeonid Yegoshin } else { 304102cedc3SLeonid Yegoshin func = fcvts_op; 305102cedc3SLeonid Yegoshin fmt = dwl_format[insn.mm_fp3_format.fmt]; 306102cedc3SLeonid Yegoshin } 307102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 308102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = fmt; 309102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 310102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 311102cedc3SLeonid Yegoshin insn.mm_fp3_format.fs; 312102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 313102cedc3SLeonid Yegoshin insn.mm_fp3_format.rt; 314102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 315102cedc3SLeonid Yegoshin break; 316102cedc3SLeonid Yegoshin case mm_fmov0_op: 317102cedc3SLeonid Yegoshin case mm_fmov1_op: 318102cedc3SLeonid Yegoshin case mm_fabs0_op: 319102cedc3SLeonid Yegoshin case mm_fabs1_op: 320102cedc3SLeonid Yegoshin case mm_fneg0_op: 321102cedc3SLeonid Yegoshin case mm_fneg1_op: 322102cedc3SLeonid Yegoshin if ((insn.mm_fp1_format.op & 0x7f) == 323102cedc3SLeonid Yegoshin mm_fmov0_op) 324102cedc3SLeonid Yegoshin func = fmov_op; 325102cedc3SLeonid Yegoshin else if ((insn.mm_fp1_format.op & 0x7f) == 326102cedc3SLeonid Yegoshin mm_fabs0_op) 327102cedc3SLeonid Yegoshin func = fabs_op; 328102cedc3SLeonid Yegoshin else 329102cedc3SLeonid Yegoshin func = fneg_op; 330102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 331102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 332102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp3_format.fmt]; 333102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 334102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 335102cedc3SLeonid Yegoshin insn.mm_fp3_format.fs; 336102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 337102cedc3SLeonid Yegoshin insn.mm_fp3_format.rt; 338102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 339102cedc3SLeonid Yegoshin break; 340102cedc3SLeonid Yegoshin case mm_ffloorl_op: 341102cedc3SLeonid Yegoshin case mm_ffloorw_op: 342102cedc3SLeonid Yegoshin case mm_fceill_op: 343102cedc3SLeonid Yegoshin case mm_fceilw_op: 344102cedc3SLeonid Yegoshin case mm_ftruncl_op: 345102cedc3SLeonid Yegoshin case mm_ftruncw_op: 346102cedc3SLeonid Yegoshin case mm_froundl_op: 347102cedc3SLeonid Yegoshin case mm_froundw_op: 348102cedc3SLeonid Yegoshin case mm_fcvtl_op: 349102cedc3SLeonid Yegoshin case mm_fcvtw_op: 350102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_ffloorl_op) 351102cedc3SLeonid Yegoshin func = ffloorl_op; 352102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ffloorw_op) 353102cedc3SLeonid Yegoshin func = ffloor_op; 354102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fceill_op) 355102cedc3SLeonid Yegoshin func = fceill_op; 356102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fceilw_op) 357102cedc3SLeonid Yegoshin func = fceil_op; 358102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ftruncl_op) 359102cedc3SLeonid Yegoshin func = ftruncl_op; 360102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_ftruncw_op) 361102cedc3SLeonid Yegoshin func = ftrunc_op; 362102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_froundl_op) 363102cedc3SLeonid Yegoshin func = froundl_op; 364102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_froundw_op) 365102cedc3SLeonid Yegoshin func = fround_op; 366102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fcvtl_op) 367102cedc3SLeonid Yegoshin func = fcvtl_op; 368102cedc3SLeonid Yegoshin else 369102cedc3SLeonid Yegoshin func = fcvtw_op; 370102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 371102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 372102cedc3SLeonid Yegoshin sd_format[insn.mm_fp1_format.fmt]; 373102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 374102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 375102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 376102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 377102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 378102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 379102cedc3SLeonid Yegoshin break; 380102cedc3SLeonid Yegoshin case mm_frsqrt_op: 381102cedc3SLeonid Yegoshin case mm_fsqrt_op: 382102cedc3SLeonid Yegoshin case mm_frecip_op: 383102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_frsqrt_op) 384102cedc3SLeonid Yegoshin func = frsqrt_op; 385102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_fsqrt_op) 386102cedc3SLeonid Yegoshin func = fsqrt_op; 387102cedc3SLeonid Yegoshin else 388102cedc3SLeonid Yegoshin func = frecip_op; 389102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 390102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 391102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp1_format.fmt]; 392102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = 0; 393102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = 394102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 395102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = 396102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 397102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = func; 398102cedc3SLeonid Yegoshin break; 399102cedc3SLeonid Yegoshin case mm_mfc1_op: 400102cedc3SLeonid Yegoshin case mm_mtc1_op: 401102cedc3SLeonid Yegoshin case mm_cfc1_op: 402102cedc3SLeonid Yegoshin case mm_ctc1_op: 4039355e59cSSteven J. Hill case mm_mfhc1_op: 4049355e59cSSteven J. Hill case mm_mthc1_op: 405102cedc3SLeonid Yegoshin if (insn.mm_fp1_format.op == mm_mfc1_op) 406102cedc3SLeonid Yegoshin op = mfc_op; 407102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_mtc1_op) 408102cedc3SLeonid Yegoshin op = mtc_op; 409102cedc3SLeonid Yegoshin else if (insn.mm_fp1_format.op == mm_cfc1_op) 410102cedc3SLeonid Yegoshin op = cfc_op; 4119355e59cSSteven J. Hill else if (insn.mm_fp1_format.op == mm_ctc1_op) 412102cedc3SLeonid Yegoshin op = ctc_op; 4139355e59cSSteven J. Hill else if (insn.mm_fp1_format.op == mm_mfhc1_op) 4149355e59cSSteven J. Hill op = mfhc_op; 4159355e59cSSteven J. Hill else 4169355e59cSSteven J. Hill op = mthc_op; 417102cedc3SLeonid Yegoshin mips32_insn.fp1_format.opcode = cop1_op; 418102cedc3SLeonid Yegoshin mips32_insn.fp1_format.op = op; 419102cedc3SLeonid Yegoshin mips32_insn.fp1_format.rt = 420102cedc3SLeonid Yegoshin insn.mm_fp1_format.rt; 421102cedc3SLeonid Yegoshin mips32_insn.fp1_format.fs = 422102cedc3SLeonid Yegoshin insn.mm_fp1_format.fs; 423102cedc3SLeonid Yegoshin mips32_insn.fp1_format.fd = 0; 424102cedc3SLeonid Yegoshin mips32_insn.fp1_format.func = 0; 425102cedc3SLeonid Yegoshin break; 426102cedc3SLeonid Yegoshin default: 427102cedc3SLeonid Yegoshin return SIGILL; 428102cedc3SLeonid Yegoshin } 429102cedc3SLeonid Yegoshin break; 430102cedc3SLeonid Yegoshin case mm_32f_74_op: /* c.cond.fmt */ 431102cedc3SLeonid Yegoshin mips32_insn.fp0_format.opcode = cop1_op; 432102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fmt = 433102cedc3SLeonid Yegoshin sdps_format[insn.mm_fp4_format.fmt]; 434102cedc3SLeonid Yegoshin mips32_insn.fp0_format.ft = insn.mm_fp4_format.rt; 435102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fs = insn.mm_fp4_format.fs; 436102cedc3SLeonid Yegoshin mips32_insn.fp0_format.fd = insn.mm_fp4_format.cc << 2; 437102cedc3SLeonid Yegoshin mips32_insn.fp0_format.func = 438102cedc3SLeonid Yegoshin insn.mm_fp4_format.cond | MM_MIPS32_COND_FC; 439102cedc3SLeonid Yegoshin break; 440102cedc3SLeonid Yegoshin default: 441102cedc3SLeonid Yegoshin return SIGILL; 442102cedc3SLeonid Yegoshin } 443102cedc3SLeonid Yegoshin break; 444102cedc3SLeonid Yegoshin default: 445102cedc3SLeonid Yegoshin return SIGILL; 446102cedc3SLeonid Yegoshin } 447102cedc3SLeonid Yegoshin 448102cedc3SLeonid Yegoshin *insn_ptr = mips32_insn; 449102cedc3SLeonid Yegoshin return 0; 450102cedc3SLeonid Yegoshin } 451102cedc3SLeonid Yegoshin 452102cedc3SLeonid Yegoshin int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, 453102cedc3SLeonid Yegoshin unsigned long *contpc) 454102cedc3SLeonid Yegoshin { 455102cedc3SLeonid Yegoshin union mips_instruction insn = (union mips_instruction)dec_insn.insn; 456102cedc3SLeonid Yegoshin int bc_false = 0; 457102cedc3SLeonid Yegoshin unsigned int fcr31; 458102cedc3SLeonid Yegoshin unsigned int bit; 459102cedc3SLeonid Yegoshin 460fe6d2909SDavid Daney if (!cpu_has_mmips) 461fe6d2909SDavid Daney return 0; 462fe6d2909SDavid Daney 463102cedc3SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 464102cedc3SLeonid Yegoshin case mm_pool32a_op: 465102cedc3SLeonid Yegoshin if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == 466102cedc3SLeonid Yegoshin mm_pool32axf_op) { 467102cedc3SLeonid Yegoshin switch (insn.mm_i_format.simmediate >> 468102cedc3SLeonid Yegoshin MM_POOL32A_MINOR_SHIFT) { 469102cedc3SLeonid Yegoshin case mm_jalr_op: 470102cedc3SLeonid Yegoshin case mm_jalrhb_op: 471102cedc3SLeonid Yegoshin case mm_jalrs_op: 472102cedc3SLeonid Yegoshin case mm_jalrshb_op: 473102cedc3SLeonid Yegoshin if (insn.mm_i_format.rt != 0) /* Not mm_jr */ 474102cedc3SLeonid Yegoshin regs->regs[insn.mm_i_format.rt] = 475102cedc3SLeonid Yegoshin regs->cp0_epc + 476102cedc3SLeonid Yegoshin dec_insn.pc_inc + 477102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 478102cedc3SLeonid Yegoshin *contpc = regs->regs[insn.mm_i_format.rs]; 479102cedc3SLeonid Yegoshin return 1; 480102cedc3SLeonid Yegoshin } 481102cedc3SLeonid Yegoshin } 482102cedc3SLeonid Yegoshin break; 483102cedc3SLeonid Yegoshin case mm_pool32i_op: 484102cedc3SLeonid Yegoshin switch (insn.mm_i_format.rt) { 485102cedc3SLeonid Yegoshin case mm_bltzals_op: 486102cedc3SLeonid Yegoshin case mm_bltzal_op: 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 mm_bltz_op: 492102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.mm_i_format.rs] < 0) 493102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 494102cedc3SLeonid Yegoshin dec_insn.pc_inc + 495102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 496102cedc3SLeonid Yegoshin else 497102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 498102cedc3SLeonid Yegoshin dec_insn.pc_inc + 499102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 500102cedc3SLeonid Yegoshin return 1; 501102cedc3SLeonid Yegoshin case mm_bgezals_op: 502102cedc3SLeonid Yegoshin case mm_bgezal_op: 503102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 504102cedc3SLeonid Yegoshin dec_insn.pc_inc + 505102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 506102cedc3SLeonid Yegoshin /* Fall through */ 507102cedc3SLeonid Yegoshin case mm_bgez_op: 508102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.mm_i_format.rs] >= 0) 509102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 510102cedc3SLeonid Yegoshin dec_insn.pc_inc + 511102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 512102cedc3SLeonid Yegoshin else 513102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 514102cedc3SLeonid Yegoshin dec_insn.pc_inc + 515102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 516102cedc3SLeonid Yegoshin return 1; 517102cedc3SLeonid Yegoshin case mm_blez_op: 518102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.mm_i_format.rs] <= 0) 519102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 520102cedc3SLeonid Yegoshin dec_insn.pc_inc + 521102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 522102cedc3SLeonid Yegoshin else 523102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 524102cedc3SLeonid Yegoshin dec_insn.pc_inc + 525102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 526102cedc3SLeonid Yegoshin return 1; 527102cedc3SLeonid Yegoshin case mm_bgtz_op: 528102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.mm_i_format.rs] <= 0) 529102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 530102cedc3SLeonid Yegoshin dec_insn.pc_inc + 531102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 532102cedc3SLeonid Yegoshin else 533102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 534102cedc3SLeonid Yegoshin dec_insn.pc_inc + 535102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 536102cedc3SLeonid Yegoshin return 1; 537102cedc3SLeonid Yegoshin case mm_bc2f_op: 538102cedc3SLeonid Yegoshin case mm_bc1f_op: 539102cedc3SLeonid Yegoshin bc_false = 1; 540102cedc3SLeonid Yegoshin /* Fall through */ 541102cedc3SLeonid Yegoshin case mm_bc2t_op: 542102cedc3SLeonid Yegoshin case mm_bc1t_op: 543102cedc3SLeonid Yegoshin preempt_disable(); 544102cedc3SLeonid Yegoshin if (is_fpu_owner()) 545102cedc3SLeonid Yegoshin asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); 546102cedc3SLeonid Yegoshin else 547102cedc3SLeonid Yegoshin fcr31 = current->thread.fpu.fcr31; 548102cedc3SLeonid Yegoshin preempt_enable(); 549102cedc3SLeonid Yegoshin 550102cedc3SLeonid Yegoshin if (bc_false) 551102cedc3SLeonid Yegoshin fcr31 = ~fcr31; 552102cedc3SLeonid Yegoshin 553102cedc3SLeonid Yegoshin bit = (insn.mm_i_format.rs >> 2); 554102cedc3SLeonid Yegoshin bit += (bit != 0); 555102cedc3SLeonid Yegoshin bit += 23; 556102cedc3SLeonid Yegoshin if (fcr31 & (1 << bit)) 557102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 558102cedc3SLeonid Yegoshin dec_insn.pc_inc + 559102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 560102cedc3SLeonid Yegoshin else 561102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 562102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 563102cedc3SLeonid Yegoshin return 1; 564102cedc3SLeonid Yegoshin } 565102cedc3SLeonid Yegoshin break; 566102cedc3SLeonid Yegoshin case mm_pool16c_op: 567102cedc3SLeonid Yegoshin switch (insn.mm_i_format.rt) { 568102cedc3SLeonid Yegoshin case mm_jalr16_op: 569102cedc3SLeonid Yegoshin case mm_jalrs16_op: 570102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 571102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 572102cedc3SLeonid Yegoshin /* Fall through */ 573102cedc3SLeonid Yegoshin case mm_jr16_op: 574102cedc3SLeonid Yegoshin *contpc = regs->regs[insn.mm_i_format.rs]; 575102cedc3SLeonid Yegoshin return 1; 576102cedc3SLeonid Yegoshin } 577102cedc3SLeonid Yegoshin break; 578102cedc3SLeonid Yegoshin case mm_beqz16_op: 579102cedc3SLeonid Yegoshin if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) 580102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 581102cedc3SLeonid Yegoshin dec_insn.pc_inc + 582102cedc3SLeonid Yegoshin (insn.mm_b1_format.simmediate << 1); 583102cedc3SLeonid Yegoshin else 584102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 585102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 586102cedc3SLeonid Yegoshin return 1; 587102cedc3SLeonid Yegoshin case mm_bnez16_op: 588102cedc3SLeonid Yegoshin if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) 589102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 590102cedc3SLeonid Yegoshin dec_insn.pc_inc + 591102cedc3SLeonid Yegoshin (insn.mm_b1_format.simmediate << 1); 592102cedc3SLeonid Yegoshin else 593102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 594102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 595102cedc3SLeonid Yegoshin return 1; 596102cedc3SLeonid Yegoshin case mm_b16_op: 597102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + dec_insn.pc_inc + 598102cedc3SLeonid Yegoshin (insn.mm_b0_format.simmediate << 1); 599102cedc3SLeonid Yegoshin return 1; 600102cedc3SLeonid Yegoshin case mm_beq32_op: 601102cedc3SLeonid Yegoshin if (regs->regs[insn.mm_i_format.rs] == 602102cedc3SLeonid Yegoshin regs->regs[insn.mm_i_format.rt]) 603102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 604102cedc3SLeonid Yegoshin dec_insn.pc_inc + 605102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 606102cedc3SLeonid Yegoshin else 607102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 608102cedc3SLeonid Yegoshin dec_insn.pc_inc + 609102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 610102cedc3SLeonid Yegoshin return 1; 611102cedc3SLeonid Yegoshin case mm_bne32_op: 612102cedc3SLeonid Yegoshin if (regs->regs[insn.mm_i_format.rs] != 613102cedc3SLeonid Yegoshin regs->regs[insn.mm_i_format.rt]) 614102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 615102cedc3SLeonid Yegoshin dec_insn.pc_inc + 616102cedc3SLeonid Yegoshin (insn.mm_i_format.simmediate << 1); 617102cedc3SLeonid Yegoshin else 618102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 619102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 620102cedc3SLeonid Yegoshin return 1; 621102cedc3SLeonid Yegoshin case mm_jalx32_op: 622102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 623102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 624102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + dec_insn.pc_inc; 625102cedc3SLeonid Yegoshin *contpc >>= 28; 626102cedc3SLeonid Yegoshin *contpc <<= 28; 627102cedc3SLeonid Yegoshin *contpc |= (insn.j_format.target << 2); 628102cedc3SLeonid Yegoshin return 1; 629102cedc3SLeonid Yegoshin case mm_jals32_op: 630102cedc3SLeonid Yegoshin case mm_jal32_op: 631102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 632102cedc3SLeonid Yegoshin dec_insn.pc_inc + dec_insn.next_pc_inc; 633102cedc3SLeonid Yegoshin /* Fall through */ 634102cedc3SLeonid Yegoshin case mm_j32_op: 635102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + dec_insn.pc_inc; 636102cedc3SLeonid Yegoshin *contpc >>= 27; 637102cedc3SLeonid Yegoshin *contpc <<= 27; 638102cedc3SLeonid Yegoshin *contpc |= (insn.j_format.target << 1); 639102cedc3SLeonid Yegoshin set_isa16_mode(*contpc); 640102cedc3SLeonid Yegoshin return 1; 641102cedc3SLeonid Yegoshin } 642102cedc3SLeonid Yegoshin return 0; 643102cedc3SLeonid Yegoshin } 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds /* 6461da177e4SLinus Torvalds * Redundant with logic already in kernel/branch.c, 6471da177e4SLinus Torvalds * embedded in compute_return_epc. At some point, 6481da177e4SLinus Torvalds * a single subroutine should be used across both 6491da177e4SLinus Torvalds * modules. 6501da177e4SLinus Torvalds */ 651102cedc3SLeonid Yegoshin static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, 652102cedc3SLeonid Yegoshin unsigned long *contpc) 6531da177e4SLinus Torvalds { 654102cedc3SLeonid Yegoshin union mips_instruction insn = (union mips_instruction)dec_insn.insn; 655102cedc3SLeonid Yegoshin unsigned int fcr31; 656102cedc3SLeonid Yegoshin unsigned int bit = 0; 657102cedc3SLeonid Yegoshin 658102cedc3SLeonid Yegoshin switch (insn.i_format.opcode) { 6591da177e4SLinus Torvalds case spec_op: 660102cedc3SLeonid Yegoshin switch (insn.r_format.func) { 6611da177e4SLinus Torvalds case jalr_op: 662102cedc3SLeonid Yegoshin regs->regs[insn.r_format.rd] = 663102cedc3SLeonid Yegoshin regs->cp0_epc + dec_insn.pc_inc + 664102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 665102cedc3SLeonid Yegoshin /* Fall through */ 6661da177e4SLinus Torvalds case jr_op: 667102cedc3SLeonid Yegoshin *contpc = regs->regs[insn.r_format.rs]; 6681da177e4SLinus Torvalds return 1; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds break; 6711da177e4SLinus Torvalds case bcond_op: 672102cedc3SLeonid Yegoshin switch (insn.i_format.rt) { 6731da177e4SLinus Torvalds case bltzal_op: 6741da177e4SLinus Torvalds case bltzall_op: 675102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 676102cedc3SLeonid Yegoshin dec_insn.pc_inc + 677102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 678102cedc3SLeonid Yegoshin /* Fall through */ 679102cedc3SLeonid Yegoshin case bltz_op: 680102cedc3SLeonid Yegoshin case bltzl_op: 681102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] < 0) 682102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 683102cedc3SLeonid Yegoshin dec_insn.pc_inc + 684102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 685102cedc3SLeonid Yegoshin else 686102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 687102cedc3SLeonid Yegoshin dec_insn.pc_inc + 688102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 6891da177e4SLinus Torvalds return 1; 690102cedc3SLeonid Yegoshin case bgezal_op: 691102cedc3SLeonid Yegoshin case bgezall_op: 692102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 693102cedc3SLeonid Yegoshin dec_insn.pc_inc + 694102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 695102cedc3SLeonid Yegoshin /* Fall through */ 696102cedc3SLeonid Yegoshin case bgez_op: 697102cedc3SLeonid Yegoshin case bgezl_op: 698102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] >= 0) 699102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 700102cedc3SLeonid Yegoshin dec_insn.pc_inc + 701102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 702102cedc3SLeonid Yegoshin else 703102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 704102cedc3SLeonid Yegoshin dec_insn.pc_inc + 705102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 706102cedc3SLeonid Yegoshin return 1; 7071da177e4SLinus Torvalds } 7081da177e4SLinus Torvalds break; 7091da177e4SLinus Torvalds case jalx_op: 710102cedc3SLeonid Yegoshin set_isa16_mode(bit); 711102cedc3SLeonid Yegoshin case jal_op: 712102cedc3SLeonid Yegoshin regs->regs[31] = regs->cp0_epc + 713102cedc3SLeonid Yegoshin dec_insn.pc_inc + 714102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 715102cedc3SLeonid Yegoshin /* Fall through */ 716102cedc3SLeonid Yegoshin case j_op: 717102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + dec_insn.pc_inc; 718102cedc3SLeonid Yegoshin *contpc >>= 28; 719102cedc3SLeonid Yegoshin *contpc <<= 28; 720102cedc3SLeonid Yegoshin *contpc |= (insn.j_format.target << 2); 721102cedc3SLeonid Yegoshin /* Set microMIPS mode bit: XOR for jalx. */ 722102cedc3SLeonid Yegoshin *contpc ^= bit; 7231da177e4SLinus Torvalds return 1; 724102cedc3SLeonid Yegoshin case beq_op: 725102cedc3SLeonid Yegoshin case beql_op: 726102cedc3SLeonid Yegoshin if (regs->regs[insn.i_format.rs] == 727102cedc3SLeonid Yegoshin regs->regs[insn.i_format.rt]) 728102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 729102cedc3SLeonid Yegoshin dec_insn.pc_inc + 730102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 731102cedc3SLeonid Yegoshin else 732102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 733102cedc3SLeonid Yegoshin dec_insn.pc_inc + 734102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 735102cedc3SLeonid Yegoshin return 1; 736102cedc3SLeonid Yegoshin case bne_op: 737102cedc3SLeonid Yegoshin case bnel_op: 738102cedc3SLeonid Yegoshin if (regs->regs[insn.i_format.rs] != 739102cedc3SLeonid Yegoshin regs->regs[insn.i_format.rt]) 740102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 741102cedc3SLeonid Yegoshin dec_insn.pc_inc + 742102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 743102cedc3SLeonid Yegoshin else 744102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 745102cedc3SLeonid Yegoshin dec_insn.pc_inc + 746102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 747102cedc3SLeonid Yegoshin return 1; 748102cedc3SLeonid Yegoshin case blez_op: 749102cedc3SLeonid Yegoshin case blezl_op: 750102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] <= 0) 751102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 752102cedc3SLeonid Yegoshin dec_insn.pc_inc + 753102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 754102cedc3SLeonid Yegoshin else 755102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 756102cedc3SLeonid Yegoshin dec_insn.pc_inc + 757102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 758102cedc3SLeonid Yegoshin return 1; 759102cedc3SLeonid Yegoshin case bgtz_op: 760102cedc3SLeonid Yegoshin case bgtzl_op: 761102cedc3SLeonid Yegoshin if ((long)regs->regs[insn.i_format.rs] > 0) 762102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 763102cedc3SLeonid Yegoshin dec_insn.pc_inc + 764102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 765102cedc3SLeonid Yegoshin else 766102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 767102cedc3SLeonid Yegoshin dec_insn.pc_inc + 768102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 769102cedc3SLeonid Yegoshin return 1; 770c26d4219SDavid Daney #ifdef CONFIG_CPU_CAVIUM_OCTEON 771c26d4219SDavid Daney case lwc2_op: /* This is bbit0 on Octeon */ 772c26d4219SDavid Daney if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0) 773c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 774c26d4219SDavid Daney else 775c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 776c26d4219SDavid Daney return 1; 777c26d4219SDavid Daney case ldc2_op: /* This is bbit032 on Octeon */ 778c26d4219SDavid Daney if ((regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) == 0) 779c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 780c26d4219SDavid Daney else 781c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 782c26d4219SDavid Daney return 1; 783c26d4219SDavid Daney case swc2_op: /* This is bbit1 on Octeon */ 784c26d4219SDavid Daney if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) 785c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 786c26d4219SDavid Daney else 787c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 788c26d4219SDavid Daney return 1; 789c26d4219SDavid Daney case sdc2_op: /* This is bbit132 on Octeon */ 790c26d4219SDavid Daney if (regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) 791c26d4219SDavid Daney *contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2); 792c26d4219SDavid Daney else 793c26d4219SDavid Daney *contpc = regs->cp0_epc + 8; 794c26d4219SDavid Daney return 1; 795c26d4219SDavid Daney #endif 7961da177e4SLinus Torvalds case cop0_op: 7971da177e4SLinus Torvalds case cop1_op: 7981da177e4SLinus Torvalds case cop2_op: 7991da177e4SLinus Torvalds case cop1x_op: 800102cedc3SLeonid Yegoshin if (insn.i_format.rs == bc_op) { 801102cedc3SLeonid Yegoshin preempt_disable(); 802102cedc3SLeonid Yegoshin if (is_fpu_owner()) 803102cedc3SLeonid Yegoshin asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); 804102cedc3SLeonid Yegoshin else 805102cedc3SLeonid Yegoshin fcr31 = current->thread.fpu.fcr31; 806102cedc3SLeonid Yegoshin preempt_enable(); 807102cedc3SLeonid Yegoshin 808102cedc3SLeonid Yegoshin bit = (insn.i_format.rt >> 2); 809102cedc3SLeonid Yegoshin bit += (bit != 0); 810102cedc3SLeonid Yegoshin bit += 23; 811102cedc3SLeonid Yegoshin switch (insn.i_format.rt & 3) { 812102cedc3SLeonid Yegoshin case 0: /* bc1f */ 813102cedc3SLeonid Yegoshin case 2: /* bc1fl */ 814102cedc3SLeonid Yegoshin if (~fcr31 & (1 << bit)) 815102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 816102cedc3SLeonid Yegoshin dec_insn.pc_inc + 817102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 818102cedc3SLeonid Yegoshin else 819102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 820102cedc3SLeonid Yegoshin dec_insn.pc_inc + 821102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 822102cedc3SLeonid Yegoshin return 1; 823102cedc3SLeonid Yegoshin case 1: /* bc1t */ 824102cedc3SLeonid Yegoshin case 3: /* bc1tl */ 825102cedc3SLeonid Yegoshin if (fcr31 & (1 << bit)) 826102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 827102cedc3SLeonid Yegoshin dec_insn.pc_inc + 828102cedc3SLeonid Yegoshin (insn.i_format.simmediate << 2); 829102cedc3SLeonid Yegoshin else 830102cedc3SLeonid Yegoshin *contpc = regs->cp0_epc + 831102cedc3SLeonid Yegoshin dec_insn.pc_inc + 832102cedc3SLeonid Yegoshin dec_insn.next_pc_inc; 8331da177e4SLinus Torvalds return 1; 8341da177e4SLinus Torvalds } 835102cedc3SLeonid Yegoshin } 836102cedc3SLeonid Yegoshin break; 837102cedc3SLeonid Yegoshin } 8381da177e4SLinus Torvalds return 0; 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* 8421da177e4SLinus Torvalds * In the Linux kernel, we support selection of FPR format on the 843da0bac33SDavid Daney * basis of the Status.FR bit. If an FPU is not present, the FR bit 844da0bac33SDavid Daney * is hardwired to zero, which would imply a 32-bit FPU even for 845597ce172SPaul Burton * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS. 84651d943f0SRalf Baechle * FPU emu is slow and bulky and optimizing this function offers fairly 84751d943f0SRalf Baechle * sizeable benefits so we try to be clever and make this function return 84851d943f0SRalf Baechle * a constant whenever possible, that is on 64-bit kernels without O32 849597ce172SPaul Burton * compatibility enabled and on 32-bit without 64-bit FPU support. 8501da177e4SLinus Torvalds */ 851da0bac33SDavid Daney static inline int cop1_64bit(struct pt_regs *xcp) 852da0bac33SDavid Daney { 853*08a07904SRalf Baechle if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) 85451d943f0SRalf Baechle return 1; 855*08a07904SRalf Baechle else if (config_enabled(CONFIG_32BIT) && 856*08a07904SRalf Baechle !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) 857da0bac33SDavid Daney return 0; 858*08a07904SRalf Baechle 859597ce172SPaul Burton return !test_thread_flag(TIF_32BIT_FPREGS); 860da0bac33SDavid Daney } 8611da177e4SLinus Torvalds 86247fa0c02SRalf Baechle #define SIFROMREG(si, x) \ 86347fa0c02SRalf Baechle do { \ 864bbd426f5SPaul Burton if (cop1_64bit(xcp)) \ 865bbd426f5SPaul Burton (si) = get_fpr32(&ctx->fpr[x], 0); \ 866bbd426f5SPaul Burton else \ 867bbd426f5SPaul Burton (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ 868bbd426f5SPaul Burton } while (0) 869da0bac33SDavid Daney 87047fa0c02SRalf Baechle #define SITOREG(si, x) \ 87147fa0c02SRalf Baechle do { \ 872ef1c47afSPaul Burton if (cop1_64bit(xcp)) { \ 873ef1c47afSPaul Burton unsigned i; \ 874bbd426f5SPaul Burton set_fpr32(&ctx->fpr[x], 0, si); \ 875ef1c47afSPaul Burton for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ 876ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], i, 0); \ 877ef1c47afSPaul Burton } else { \ 878bbd426f5SPaul Burton set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \ 879ef1c47afSPaul Burton } \ 880bbd426f5SPaul Burton } while (0) 8811da177e4SLinus Torvalds 882bbd426f5SPaul Burton #define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) 883ef1c47afSPaul Burton 88447fa0c02SRalf Baechle #define SITOHREG(si, x) \ 88547fa0c02SRalf Baechle do { \ 886ef1c47afSPaul Burton unsigned i; \ 887ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], 1, si); \ 888ef1c47afSPaul Burton for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ 889ef1c47afSPaul Burton set_fpr32(&ctx->fpr[x], i, 0); \ 890ef1c47afSPaul Burton } while (0) 8911ac94400SLeonid Yegoshin 892bbd426f5SPaul Burton #define DIFROMREG(di, x) \ 893bbd426f5SPaul Burton ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) 894bbd426f5SPaul Burton 89547fa0c02SRalf Baechle #define DITOREG(di, x) \ 89647fa0c02SRalf Baechle do { \ 897ef1c47afSPaul Burton unsigned fpr, i; \ 898ef1c47afSPaul Burton fpr = (x) & ~(cop1_64bit(xcp) == 0); \ 899ef1c47afSPaul Burton set_fpr64(&ctx->fpr[fpr], 0, di); \ 900ef1c47afSPaul Burton for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \ 901ef1c47afSPaul Burton set_fpr64(&ctx->fpr[fpr], i, 0); \ 902ef1c47afSPaul Burton } while (0) 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) 9051da177e4SLinus Torvalds #define SPTOREG(sp, x) SITOREG((sp).bits, x) 9061da177e4SLinus Torvalds #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) 9071da177e4SLinus Torvalds #define DPTOREG(dp, x) DITOREG((dp).bits, x) 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds /* 9101da177e4SLinus Torvalds * Emulate the single floating point instruction pointed at by EPC. 9111da177e4SLinus Torvalds * Two instructions if the instruction is in a branch delay slot. 9121da177e4SLinus Torvalds */ 9131da177e4SLinus Torvalds 914515b029dSDavid Daney static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 915102cedc3SLeonid Yegoshin struct mm_decoded_insn dec_insn, void *__user *fault_addr) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds mips_instruction ir; 918102cedc3SLeonid Yegoshin unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; 9191da177e4SLinus Torvalds unsigned int cond; 920102cedc3SLeonid Yegoshin int pc_inc; 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds /* XXX NEC Vr54xx bug workaround */ 923e7e9cae5SRalf Baechle if (delay_slot(xcp)) { 924102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 925102cedc3SLeonid Yegoshin if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) 926e7e9cae5SRalf Baechle clear_delay_slot(xcp); 927102cedc3SLeonid Yegoshin } else { 928102cedc3SLeonid Yegoshin if (!isBranchInstr(xcp, dec_insn, &contpc)) 929e7e9cae5SRalf Baechle clear_delay_slot(xcp); 930102cedc3SLeonid Yegoshin } 931102cedc3SLeonid Yegoshin } 9321da177e4SLinus Torvalds 933e7e9cae5SRalf Baechle if (delay_slot(xcp)) { 9341da177e4SLinus Torvalds /* 9351da177e4SLinus Torvalds * The instruction to be emulated is in a branch delay slot 9361da177e4SLinus Torvalds * which means that we have to emulate the branch instruction 9371da177e4SLinus Torvalds * BEFORE we do the cop1 instruction. 9381da177e4SLinus Torvalds * 9391da177e4SLinus Torvalds * This branch could be a COP1 branch, but in that case we 9401da177e4SLinus Torvalds * would have had a trap for that instruction, and would not 9411da177e4SLinus Torvalds * come through this route. 9421da177e4SLinus Torvalds * 9431da177e4SLinus Torvalds * Linux MIPS branch emulator operates on context, updating the 9441da177e4SLinus Torvalds * cp0_epc. 9451da177e4SLinus Torvalds */ 946102cedc3SLeonid Yegoshin ir = dec_insn.next_insn; /* process delay slot instr */ 947102cedc3SLeonid Yegoshin pc_inc = dec_insn.next_pc_inc; 948333d1f67SRalf Baechle } else { 949102cedc3SLeonid Yegoshin ir = dec_insn.insn; /* process current instr */ 950102cedc3SLeonid Yegoshin pc_inc = dec_insn.pc_inc; 951102cedc3SLeonid Yegoshin } 952102cedc3SLeonid Yegoshin 953102cedc3SLeonid Yegoshin /* 954102cedc3SLeonid Yegoshin * Since microMIPS FPU instructios are a subset of MIPS32 FPU 955102cedc3SLeonid Yegoshin * instructions, we want to convert microMIPS FPU instructions 956102cedc3SLeonid Yegoshin * into MIPS32 instructions so that we could reuse all of the 957102cedc3SLeonid Yegoshin * FPU emulation code. 958102cedc3SLeonid Yegoshin * 959102cedc3SLeonid Yegoshin * NOTE: We cannot do this for branch instructions since they 960102cedc3SLeonid Yegoshin * are not a subset. Example: Cannot emulate a 16-bit 961102cedc3SLeonid Yegoshin * aligned target address with a MIPS32 instruction. 962102cedc3SLeonid Yegoshin */ 963102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 964102cedc3SLeonid Yegoshin /* 965102cedc3SLeonid Yegoshin * If next instruction is a 16-bit instruction, then it 966102cedc3SLeonid Yegoshin * it cannot be a FPU instruction. This could happen 967102cedc3SLeonid Yegoshin * since we can be called for non-FPU instructions. 968102cedc3SLeonid Yegoshin */ 969102cedc3SLeonid Yegoshin if ((pc_inc == 2) || 970102cedc3SLeonid Yegoshin (microMIPS32_to_MIPS32((union mips_instruction *)&ir) 971102cedc3SLeonid Yegoshin == SIGILL)) 972102cedc3SLeonid Yegoshin return SIGILL; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds emul: 976a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); 977b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(emulated); 9781da177e4SLinus Torvalds switch (MIPSInst_OPCODE(ir)) { 9791da177e4SLinus Torvalds case ldc1_op:{ 9803fccc015SRalf Baechle u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 9811da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 9821da177e4SLinus Torvalds u64 val; 9831da177e4SLinus Torvalds 984b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 985515b029dSDavid Daney 986515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u64))) { 987b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 988515b029dSDavid Daney *fault_addr = va; 9891da177e4SLinus Torvalds return SIGBUS; 9901da177e4SLinus Torvalds } 991515b029dSDavid Daney if (__get_user(val, va)) { 992515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 993515b029dSDavid Daney *fault_addr = va; 994515b029dSDavid Daney return SIGSEGV; 995515b029dSDavid Daney } 9961da177e4SLinus Torvalds DITOREG(val, MIPSInst_RT(ir)); 9971da177e4SLinus Torvalds break; 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds case sdc1_op:{ 10013fccc015SRalf Baechle u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10021da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 10031da177e4SLinus Torvalds u64 val; 10041da177e4SLinus Torvalds 1005b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 10061da177e4SLinus Torvalds DIFROMREG(val, MIPSInst_RT(ir)); 1007515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { 1008b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1009515b029dSDavid Daney *fault_addr = va; 10101da177e4SLinus Torvalds return SIGBUS; 10111da177e4SLinus Torvalds } 1012515b029dSDavid Daney if (__put_user(val, va)) { 1013515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1014515b029dSDavid Daney *fault_addr = va; 1015515b029dSDavid Daney return SIGSEGV; 1016515b029dSDavid Daney } 10171da177e4SLinus Torvalds break; 10181da177e4SLinus Torvalds } 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds case lwc1_op:{ 10213fccc015SRalf Baechle u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10221da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 10231da177e4SLinus Torvalds u32 val; 10241da177e4SLinus Torvalds 1025b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1026515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u32))) { 1027b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1028515b029dSDavid Daney *fault_addr = va; 10291da177e4SLinus Torvalds return SIGBUS; 10301da177e4SLinus Torvalds } 1031515b029dSDavid Daney if (__get_user(val, va)) { 1032515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1033515b029dSDavid Daney *fault_addr = va; 1034515b029dSDavid Daney return SIGSEGV; 1035515b029dSDavid Daney } 10361da177e4SLinus Torvalds SITOREG(val, MIPSInst_RT(ir)); 10371da177e4SLinus Torvalds break; 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds case swc1_op:{ 10413fccc015SRalf Baechle u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + 10421da177e4SLinus Torvalds MIPSInst_SIMM(ir)); 10431da177e4SLinus Torvalds u32 val; 10441da177e4SLinus Torvalds 1045b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 10461da177e4SLinus Torvalds SIFROMREG(val, MIPSInst_RT(ir)); 1047515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { 1048b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1049515b029dSDavid Daney *fault_addr = va; 10501da177e4SLinus Torvalds return SIGBUS; 10511da177e4SLinus Torvalds } 1052515b029dSDavid Daney if (__put_user(val, va)) { 1053515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1054515b029dSDavid Daney *fault_addr = va; 1055515b029dSDavid Daney return SIGSEGV; 1056515b029dSDavid Daney } 10571da177e4SLinus Torvalds break; 10581da177e4SLinus Torvalds } 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds case cop1_op: 10611da177e4SLinus Torvalds switch (MIPSInst_RS(ir)) { 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds case dmfc_op: 1064*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 1065*08a07904SRalf Baechle return SIGILL; 1066*08a07904SRalf Baechle 10671da177e4SLinus Torvalds /* copregister fs -> gpr[rt] */ 10681da177e4SLinus Torvalds if (MIPSInst_RT(ir) != 0) { 10691da177e4SLinus Torvalds DIFROMREG(xcp->regs[MIPSInst_RT(ir)], 10701da177e4SLinus Torvalds MIPSInst_RD(ir)); 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds break; 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds case dmtc_op: 1075*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 1076*08a07904SRalf Baechle return SIGILL; 1077*08a07904SRalf Baechle 10781da177e4SLinus Torvalds /* copregister fs <- rt */ 10791da177e4SLinus Torvalds DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 10801da177e4SLinus Torvalds break; 10811da177e4SLinus Torvalds 10821ac94400SLeonid Yegoshin case mfhc_op: 10831ac94400SLeonid Yegoshin if (!cpu_has_mips_r2) 10841ac94400SLeonid Yegoshin goto sigill; 10851ac94400SLeonid Yegoshin 10861ac94400SLeonid Yegoshin /* copregister rd -> gpr[rt] */ 10871ac94400SLeonid Yegoshin if (MIPSInst_RT(ir) != 0) { 10881ac94400SLeonid Yegoshin SIFROMHREG(xcp->regs[MIPSInst_RT(ir)], 10891ac94400SLeonid Yegoshin MIPSInst_RD(ir)); 10901ac94400SLeonid Yegoshin } 10911ac94400SLeonid Yegoshin break; 10921ac94400SLeonid Yegoshin 10931ac94400SLeonid Yegoshin case mthc_op: 10941ac94400SLeonid Yegoshin if (!cpu_has_mips_r2) 10951ac94400SLeonid Yegoshin goto sigill; 10961ac94400SLeonid Yegoshin 10971ac94400SLeonid Yegoshin /* copregister rd <- gpr[rt] */ 10981ac94400SLeonid Yegoshin SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 10991ac94400SLeonid Yegoshin break; 11001ac94400SLeonid Yegoshin 11011da177e4SLinus Torvalds case mfc_op: 11021da177e4SLinus Torvalds /* copregister rd -> gpr[rt] */ 11031da177e4SLinus Torvalds if (MIPSInst_RT(ir) != 0) { 11041da177e4SLinus Torvalds SIFROMREG(xcp->regs[MIPSInst_RT(ir)], 11051da177e4SLinus Torvalds MIPSInst_RD(ir)); 11061da177e4SLinus Torvalds } 11071da177e4SLinus Torvalds break; 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds case mtc_op: 11101da177e4SLinus Torvalds /* copregister rd <- rt */ 11111da177e4SLinus Torvalds SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); 11121da177e4SLinus Torvalds break; 11131da177e4SLinus Torvalds 11141da177e4SLinus Torvalds case cfc_op:{ 11151da177e4SLinus Torvalds /* cop control register rd -> gpr[rt] */ 11161da177e4SLinus Torvalds u32 value; 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds if (MIPSInst_RD(ir) == FPCREG_CSR) { 11191da177e4SLinus Torvalds value = ctx->fcr31; 11203f135530SShane McDonald value = (value & ~FPU_CSR_RM) | 11213f135530SShane McDonald mips_rm[modeindex(value)]; 11221da177e4SLinus Torvalds #ifdef CSRTRACE 11231da177e4SLinus Torvalds printk("%p gpr[%d]<-csr=%08x\n", 1124333d1f67SRalf Baechle (void *) (xcp->cp0_epc), 11251da177e4SLinus Torvalds MIPSInst_RT(ir), value); 11261da177e4SLinus Torvalds #endif 11271da177e4SLinus Torvalds } 11281da177e4SLinus Torvalds else if (MIPSInst_RD(ir) == FPCREG_RID) 11291da177e4SLinus Torvalds value = 0; 11301da177e4SLinus Torvalds else 11311da177e4SLinus Torvalds value = 0; 11321da177e4SLinus Torvalds if (MIPSInst_RT(ir)) 11331da177e4SLinus Torvalds xcp->regs[MIPSInst_RT(ir)] = value; 11341da177e4SLinus Torvalds break; 11351da177e4SLinus Torvalds } 11361da177e4SLinus Torvalds 11371da177e4SLinus Torvalds case ctc_op:{ 11381da177e4SLinus Torvalds /* copregister rd <- rt */ 11391da177e4SLinus Torvalds u32 value; 11401da177e4SLinus Torvalds 11411da177e4SLinus Torvalds if (MIPSInst_RT(ir) == 0) 11421da177e4SLinus Torvalds value = 0; 11431da177e4SLinus Torvalds else 11441da177e4SLinus Torvalds value = xcp->regs[MIPSInst_RT(ir)]; 11451da177e4SLinus Torvalds 11461da177e4SLinus Torvalds /* we only have one writable control reg 11471da177e4SLinus Torvalds */ 11481da177e4SLinus Torvalds if (MIPSInst_RD(ir) == FPCREG_CSR) { 11491da177e4SLinus Torvalds #ifdef CSRTRACE 11501da177e4SLinus Torvalds printk("%p gpr[%d]->csr=%08x\n", 1151333d1f67SRalf Baechle (void *) (xcp->cp0_epc), 11521da177e4SLinus Torvalds MIPSInst_RT(ir), value); 11531da177e4SLinus Torvalds #endif 115495e8f634SShane McDonald 115595e8f634SShane McDonald /* 115695e8f634SShane McDonald * Don't write reserved bits, 115795e8f634SShane McDonald * and convert to ieee library modes 115895e8f634SShane McDonald */ 115995e8f634SShane McDonald ctx->fcr31 = (value & 116095e8f634SShane McDonald ~(FPU_CSR_RSVD | FPU_CSR_RM)) | 116195e8f634SShane McDonald ieee_rm[modeindex(value)]; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 11641da177e4SLinus Torvalds return SIGFPE; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds break; 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds case bc_op:{ 1170*08a07904SRalf Baechle unsigned int cbit; 11711da177e4SLinus Torvalds int likely = 0; 11721da177e4SLinus Torvalds 1173e7e9cae5SRalf Baechle if (delay_slot(xcp)) 11741da177e4SLinus Torvalds return SIGILL; 11751da177e4SLinus Torvalds 1176*08a07904SRalf Baechle if (cpu_has_mips_4_5_r) 1177*08a07904SRalf Baechle cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; 1178*08a07904SRalf Baechle else 1179*08a07904SRalf Baechle cbit = FPU_CSR_COND; 1180*08a07904SRalf Baechle cond = ctx->fcr31 & cbit; 1181*08a07904SRalf Baechle 11821da177e4SLinus Torvalds switch (MIPSInst_RT(ir) & 3) { 11831da177e4SLinus Torvalds case bcfl_op: 11841da177e4SLinus Torvalds likely = 1; 11851da177e4SLinus Torvalds case bcf_op: 11861da177e4SLinus Torvalds cond = !cond; 11871da177e4SLinus Torvalds break; 11881da177e4SLinus Torvalds case bctl_op: 11891da177e4SLinus Torvalds likely = 1; 11901da177e4SLinus Torvalds case bct_op: 11911da177e4SLinus Torvalds break; 11921da177e4SLinus Torvalds default: 11931da177e4SLinus Torvalds /* thats an illegal instruction */ 11941da177e4SLinus Torvalds return SIGILL; 11951da177e4SLinus Torvalds } 11961da177e4SLinus Torvalds 1197e7e9cae5SRalf Baechle set_delay_slot(xcp); 11981da177e4SLinus Torvalds if (cond) { 11991da177e4SLinus Torvalds /* branch taken: emulate dslot 12001da177e4SLinus Torvalds * instruction 12011da177e4SLinus Torvalds */ 1202102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; 12031da177e4SLinus Torvalds 1204102cedc3SLeonid Yegoshin contpc = MIPSInst_SIMM(ir); 1205102cedc3SLeonid Yegoshin ir = dec_insn.next_insn; 1206102cedc3SLeonid Yegoshin if (dec_insn.micro_mips_mode) { 1207102cedc3SLeonid Yegoshin contpc = (xcp->cp0_epc + (contpc << 1)); 1208102cedc3SLeonid Yegoshin 1209102cedc3SLeonid Yegoshin /* If 16-bit instruction, not FPU. */ 1210102cedc3SLeonid Yegoshin if ((dec_insn.next_pc_inc == 2) || 1211102cedc3SLeonid Yegoshin (microMIPS32_to_MIPS32((union mips_instruction *)&ir) == SIGILL)) { 1212102cedc3SLeonid Yegoshin 1213102cedc3SLeonid Yegoshin /* 1214102cedc3SLeonid Yegoshin * Since this instruction will 1215102cedc3SLeonid Yegoshin * be put on the stack with 1216102cedc3SLeonid Yegoshin * 32-bit words, get around 1217102cedc3SLeonid Yegoshin * this problem by putting a 1218102cedc3SLeonid Yegoshin * NOP16 as the second one. 1219102cedc3SLeonid Yegoshin */ 1220102cedc3SLeonid Yegoshin if (dec_insn.next_pc_inc == 2) 1221102cedc3SLeonid Yegoshin ir = (ir & (~0xffff)) | MM_NOP16; 1222102cedc3SLeonid Yegoshin 1223102cedc3SLeonid Yegoshin /* 1224102cedc3SLeonid Yegoshin * Single step the non-CP1 1225102cedc3SLeonid Yegoshin * instruction in the dslot. 1226102cedc3SLeonid Yegoshin */ 1227102cedc3SLeonid Yegoshin return mips_dsemul(xcp, ir, contpc); 1228515b029dSDavid Daney } 1229102cedc3SLeonid Yegoshin } else 1230102cedc3SLeonid Yegoshin contpc = (xcp->cp0_epc + (contpc << 2)); 12311da177e4SLinus Torvalds 12321da177e4SLinus Torvalds switch (MIPSInst_OPCODE(ir)) { 12331da177e4SLinus Torvalds case lwc1_op: 1234*08a07904SRalf Baechle goto emul; 12351da177e4SLinus Torvalds case swc1_op: 1236*08a07904SRalf Baechle goto emul; 12371da177e4SLinus Torvalds case ldc1_op: 12381da177e4SLinus Torvalds case sdc1_op: 1239*08a07904SRalf Baechle if (cpu_has_mips_2_3_4_5 || 1240*08a07904SRalf Baechle cpu_has_mips64) 1241*08a07904SRalf Baechle goto emul; 1242*08a07904SRalf Baechle 1243*08a07904SRalf Baechle return SIGILL; 1244*08a07904SRalf Baechle goto emul; 12451da177e4SLinus Torvalds case cop1_op: 1246*08a07904SRalf Baechle goto emul; 12471da177e4SLinus Torvalds case cop1x_op: 1248*08a07904SRalf Baechle if (cpu_has_mips_4_5 || cpu_has_mips64) 12491da177e4SLinus Torvalds /* its one of ours */ 12501da177e4SLinus Torvalds goto emul; 1251*08a07904SRalf Baechle 1252*08a07904SRalf Baechle return SIGILL; 12531da177e4SLinus Torvalds case spec_op: 1254*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1255*08a07904SRalf Baechle return SIGILL; 1256*08a07904SRalf Baechle 12571da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) == movc_op) 12581da177e4SLinus Torvalds goto emul; 12591da177e4SLinus Torvalds break; 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds /* 12631da177e4SLinus Torvalds * Single step the non-cp1 12641da177e4SLinus Torvalds * instruction in the dslot 12651da177e4SLinus Torvalds */ 1266e70dfc10SAtsushi Nemoto return mips_dsemul(xcp, ir, contpc); 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds else { 12691da177e4SLinus Torvalds /* branch not taken */ 12701da177e4SLinus Torvalds if (likely) { 12711da177e4SLinus Torvalds /* 12721da177e4SLinus Torvalds * branch likely nullifies 12731da177e4SLinus Torvalds * dslot if not taken 12741da177e4SLinus Torvalds */ 1275102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; 1276102cedc3SLeonid Yegoshin contpc += dec_insn.pc_inc; 12771da177e4SLinus Torvalds /* 12781da177e4SLinus Torvalds * else continue & execute 12791da177e4SLinus Torvalds * dslot as normal insn 12801da177e4SLinus Torvalds */ 12811da177e4SLinus Torvalds } 12821da177e4SLinus Torvalds } 12831da177e4SLinus Torvalds break; 12841da177e4SLinus Torvalds } 12851da177e4SLinus Torvalds 12861da177e4SLinus Torvalds default: 12871da177e4SLinus Torvalds if (!(MIPSInst_RS(ir) & 0x10)) 12881da177e4SLinus Torvalds return SIGILL; 12891da177e4SLinus Torvalds { 12901da177e4SLinus Torvalds int sig; 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds /* a real fpu computation instruction */ 12931da177e4SLinus Torvalds if ((sig = fpu_emu(xcp, ctx, ir))) 12941da177e4SLinus Torvalds return sig; 12951da177e4SLinus Torvalds } 12961da177e4SLinus Torvalds } 12971da177e4SLinus Torvalds break; 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds case cop1x_op:{ 1300*08a07904SRalf Baechle int sig; 1301*08a07904SRalf Baechle 1302*08a07904SRalf Baechle if (!cpu_has_mips_4_5 && !cpu_has_mips64) 1303*08a07904SRalf Baechle return SIGILL; 1304*08a07904SRalf Baechle 1305*08a07904SRalf Baechle sig = fpux_emu(xcp, ctx, ir, fault_addr); 1306515b029dSDavid Daney if (sig) 13071da177e4SLinus Torvalds return sig; 13081da177e4SLinus Torvalds break; 13091da177e4SLinus Torvalds } 13101da177e4SLinus Torvalds 13111da177e4SLinus Torvalds case spec_op: 1312*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1313*08a07904SRalf Baechle return SIGILL; 1314*08a07904SRalf Baechle 13151da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) != movc_op) 13161da177e4SLinus Torvalds return SIGILL; 13171da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_RT(ir) >> 2]; 13181da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0)) 13191da177e4SLinus Torvalds xcp->regs[MIPSInst_RD(ir)] = 13201da177e4SLinus Torvalds xcp->regs[MIPSInst_RS(ir)]; 13211da177e4SLinus Torvalds break; 13221da177e4SLinus Torvalds default: 13231ac94400SLeonid Yegoshin sigill: 13241da177e4SLinus Torvalds return SIGILL; 13251da177e4SLinus Torvalds } 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds /* we did it !! */ 1328e70dfc10SAtsushi Nemoto xcp->cp0_epc = contpc; 1329e7e9cae5SRalf Baechle clear_delay_slot(xcp); 1330333d1f67SRalf Baechle 13311da177e4SLinus Torvalds return 0; 13321da177e4SLinus Torvalds } 13331da177e4SLinus Torvalds 13341da177e4SLinus Torvalds /* 13351da177e4SLinus Torvalds * Conversion table from MIPS compare ops 48-63 13361da177e4SLinus Torvalds * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig); 13371da177e4SLinus Torvalds */ 13381da177e4SLinus Torvalds static const unsigned char cmptab[8] = { 13391da177e4SLinus Torvalds 0, /* cmp_0 (sig) cmp_sf */ 13401da177e4SLinus Torvalds IEEE754_CUN, /* cmp_un (sig) cmp_ngle */ 13411da177e4SLinus Torvalds IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */ 13421da177e4SLinus Torvalds IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */ 13431da177e4SLinus Torvalds IEEE754_CLT, /* cmp_olt (sig) cmp_lt */ 13441da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */ 13451da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */ 13461da177e4SLinus Torvalds IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ 13471da177e4SLinus Torvalds }; 13481da177e4SLinus Torvalds 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds /* 13511da177e4SLinus Torvalds * Additional MIPS4 instructions 13521da177e4SLinus Torvalds */ 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds #define DEF3OP(name, p, f1, f2, f3) \ 135547fa0c02SRalf Baechle static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ 135647fa0c02SRalf Baechle union ieee754##p s, union ieee754##p t) \ 13571da177e4SLinus Torvalds { \ 1358cd21dfcfSRalf Baechle struct _ieee754_csr ieee754_csr_save; \ 13591da177e4SLinus Torvalds s = f1(s, t); \ 13601da177e4SLinus Torvalds ieee754_csr_save = ieee754_csr; \ 13611da177e4SLinus Torvalds s = f2(s, r); \ 13621da177e4SLinus Torvalds ieee754_csr_save.cx |= ieee754_csr.cx; \ 13631da177e4SLinus Torvalds ieee754_csr_save.sx |= ieee754_csr.sx; \ 13641da177e4SLinus Torvalds s = f3(s); \ 13651da177e4SLinus Torvalds ieee754_csr.cx |= ieee754_csr_save.cx; \ 13661da177e4SLinus Torvalds ieee754_csr.sx |= ieee754_csr_save.sx; \ 13671da177e4SLinus Torvalds return s; \ 13681da177e4SLinus Torvalds } 13691da177e4SLinus Torvalds 13702209bcb1SRalf Baechle static union ieee754dp fpemu_dp_recip(union ieee754dp d) 13711da177e4SLinus Torvalds { 13721da177e4SLinus Torvalds return ieee754dp_div(ieee754dp_one(0), d); 13731da177e4SLinus Torvalds } 13741da177e4SLinus Torvalds 13752209bcb1SRalf Baechle static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d) 13761da177e4SLinus Torvalds { 13771da177e4SLinus Torvalds return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds 13802209bcb1SRalf Baechle static union ieee754sp fpemu_sp_recip(union ieee754sp s) 13811da177e4SLinus Torvalds { 13821da177e4SLinus Torvalds return ieee754sp_div(ieee754sp_one(0), s); 13831da177e4SLinus Torvalds } 13841da177e4SLinus Torvalds 13852209bcb1SRalf Baechle static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s) 13861da177e4SLinus Torvalds { 13871da177e4SLinus Torvalds return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds 13901da177e4SLinus Torvalds DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, ); 13911da177e4SLinus Torvalds DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, ); 13921da177e4SLinus Torvalds DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); 13931da177e4SLinus Torvalds DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); 13941da177e4SLinus Torvalds DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, ); 13951da177e4SLinus Torvalds DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, ); 13961da177e4SLinus Torvalds DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); 13971da177e4SLinus Torvalds DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); 13981da177e4SLinus Torvalds 1399eae89076SAtsushi Nemoto static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 1400515b029dSDavid Daney mips_instruction ir, void *__user *fault_addr) 14011da177e4SLinus Torvalds { 14021da177e4SLinus Torvalds unsigned rcsr = 0; /* resulting csr */ 14031da177e4SLinus Torvalds 1404b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(cp1xops); 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds switch (MIPSInst_FMA_FFMT(ir)) { 14071da177e4SLinus Torvalds case s_fmt:{ /* 0 */ 14081da177e4SLinus Torvalds 14092209bcb1SRalf Baechle union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); 14102209bcb1SRalf Baechle union ieee754sp fd, fr, fs, ft; 14113fccc015SRalf Baechle u32 __user *va; 14121da177e4SLinus Torvalds u32 val; 14131da177e4SLinus Torvalds 14141da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 14151da177e4SLinus Torvalds case lwxc1_op: 14163fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 14171da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 14181da177e4SLinus Torvalds 1419b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1420515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u32))) { 1421b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1422515b029dSDavid Daney *fault_addr = va; 14231da177e4SLinus Torvalds return SIGBUS; 14241da177e4SLinus Torvalds } 1425515b029dSDavid Daney if (__get_user(val, va)) { 1426515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1427515b029dSDavid Daney *fault_addr = va; 1428515b029dSDavid Daney return SIGSEGV; 1429515b029dSDavid Daney } 14301da177e4SLinus Torvalds SITOREG(val, MIPSInst_FD(ir)); 14311da177e4SLinus Torvalds break; 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds case swxc1_op: 14343fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 14351da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 14361da177e4SLinus Torvalds 1437b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 14381da177e4SLinus Torvalds 14391da177e4SLinus Torvalds SIFROMREG(val, MIPSInst_FS(ir)); 1440515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { 1441515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1442515b029dSDavid Daney *fault_addr = va; 1443515b029dSDavid Daney return SIGBUS; 1444515b029dSDavid Daney } 14451da177e4SLinus Torvalds if (put_user(val, va)) { 1446b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1447515b029dSDavid Daney *fault_addr = va; 1448515b029dSDavid Daney return SIGSEGV; 14491da177e4SLinus Torvalds } 14501da177e4SLinus Torvalds break; 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds case madd_s_op: 14531da177e4SLinus Torvalds handler = fpemu_sp_madd; 14541da177e4SLinus Torvalds goto scoptop; 14551da177e4SLinus Torvalds case msub_s_op: 14561da177e4SLinus Torvalds handler = fpemu_sp_msub; 14571da177e4SLinus Torvalds goto scoptop; 14581da177e4SLinus Torvalds case nmadd_s_op: 14591da177e4SLinus Torvalds handler = fpemu_sp_nmadd; 14601da177e4SLinus Torvalds goto scoptop; 14611da177e4SLinus Torvalds case nmsub_s_op: 14621da177e4SLinus Torvalds handler = fpemu_sp_nmsub; 14631da177e4SLinus Torvalds goto scoptop; 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds scoptop: 14661da177e4SLinus Torvalds SPFROMREG(fr, MIPSInst_FR(ir)); 14671da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 14681da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 14691da177e4SLinus Torvalds fd = (*handler) (fr, fs, ft); 14701da177e4SLinus Torvalds SPTOREG(fd, MIPSInst_FD(ir)); 14711da177e4SLinus Torvalds 14721da177e4SLinus Torvalds copcsr: 14731da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_INEXACT)) 14741da177e4SLinus Torvalds rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 14751da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_UNDERFLOW)) 14761da177e4SLinus Torvalds rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 14771da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_OVERFLOW)) 14781da177e4SLinus Torvalds rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 14791da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) 14801da177e4SLinus Torvalds rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 14811da177e4SLinus Torvalds 14821da177e4SLinus Torvalds ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 14831da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 14841da177e4SLinus Torvalds /*printk ("SIGFPE: fpu csr = %08x\n", 14851da177e4SLinus Torvalds ctx->fcr31); */ 14861da177e4SLinus Torvalds return SIGFPE; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds break; 14901da177e4SLinus Torvalds 14911da177e4SLinus Torvalds default: 14921da177e4SLinus Torvalds return SIGILL; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds break; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds case d_fmt:{ /* 1 */ 14982209bcb1SRalf Baechle union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); 14992209bcb1SRalf Baechle union ieee754dp fd, fr, fs, ft; 15003fccc015SRalf Baechle u64 __user *va; 15011da177e4SLinus Torvalds u64 val; 15021da177e4SLinus Torvalds 15031da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 15041da177e4SLinus Torvalds case ldxc1_op: 15053fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 15061da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 15071da177e4SLinus Torvalds 1508b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(loads); 1509515b029dSDavid Daney if (!access_ok(VERIFY_READ, va, sizeof(u64))) { 1510b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1511515b029dSDavid Daney *fault_addr = va; 15121da177e4SLinus Torvalds return SIGBUS; 15131da177e4SLinus Torvalds } 1514515b029dSDavid Daney if (__get_user(val, va)) { 1515515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1516515b029dSDavid Daney *fault_addr = va; 1517515b029dSDavid Daney return SIGSEGV; 1518515b029dSDavid Daney } 15191da177e4SLinus Torvalds DITOREG(val, MIPSInst_FD(ir)); 15201da177e4SLinus Torvalds break; 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds case sdxc1_op: 15233fccc015SRalf Baechle va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] + 15241da177e4SLinus Torvalds xcp->regs[MIPSInst_FT(ir)]); 15251da177e4SLinus Torvalds 1526b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(stores); 15271da177e4SLinus Torvalds DIFROMREG(val, MIPSInst_FS(ir)); 1528515b029dSDavid Daney if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { 1529b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1530515b029dSDavid Daney *fault_addr = va; 15311da177e4SLinus Torvalds return SIGBUS; 15321da177e4SLinus Torvalds } 1533515b029dSDavid Daney if (__put_user(val, va)) { 1534515b029dSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 1535515b029dSDavid Daney *fault_addr = va; 1536515b029dSDavid Daney return SIGSEGV; 1537515b029dSDavid Daney } 15381da177e4SLinus Torvalds break; 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds case madd_d_op: 15411da177e4SLinus Torvalds handler = fpemu_dp_madd; 15421da177e4SLinus Torvalds goto dcoptop; 15431da177e4SLinus Torvalds case msub_d_op: 15441da177e4SLinus Torvalds handler = fpemu_dp_msub; 15451da177e4SLinus Torvalds goto dcoptop; 15461da177e4SLinus Torvalds case nmadd_d_op: 15471da177e4SLinus Torvalds handler = fpemu_dp_nmadd; 15481da177e4SLinus Torvalds goto dcoptop; 15491da177e4SLinus Torvalds case nmsub_d_op: 15501da177e4SLinus Torvalds handler = fpemu_dp_nmsub; 15511da177e4SLinus Torvalds goto dcoptop; 15521da177e4SLinus Torvalds 15531da177e4SLinus Torvalds dcoptop: 15541da177e4SLinus Torvalds DPFROMREG(fr, MIPSInst_FR(ir)); 15551da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 15561da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 15571da177e4SLinus Torvalds fd = (*handler) (fr, fs, ft); 15581da177e4SLinus Torvalds DPTOREG(fd, MIPSInst_FD(ir)); 15591da177e4SLinus Torvalds goto copcsr; 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds default: 15621da177e4SLinus Torvalds return SIGILL; 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds break; 15651da177e4SLinus Torvalds } 15661da177e4SLinus Torvalds 156751061b88SDeng-Cheng Zhu case 0x3: 156851061b88SDeng-Cheng Zhu if (MIPSInst_FUNC(ir) != pfetch_op) 15691da177e4SLinus Torvalds return SIGILL; 157051061b88SDeng-Cheng Zhu 15711da177e4SLinus Torvalds /* ignore prefx operation */ 15721da177e4SLinus Torvalds break; 15731da177e4SLinus Torvalds 15741da177e4SLinus Torvalds default: 15751da177e4SLinus Torvalds return SIGILL; 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds return 0; 15791da177e4SLinus Torvalds } 15801da177e4SLinus Torvalds 15811da177e4SLinus Torvalds 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds /* 15841da177e4SLinus Torvalds * Emulate a single COP1 arithmetic instruction. 15851da177e4SLinus Torvalds */ 1586eae89076SAtsushi Nemoto static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 15871da177e4SLinus Torvalds mips_instruction ir) 15881da177e4SLinus Torvalds { 15891da177e4SLinus Torvalds int rfmt; /* resulting format */ 15901da177e4SLinus Torvalds unsigned rcsr = 0; /* resulting csr */ 15911da177e4SLinus Torvalds unsigned cond; 15921da177e4SLinus Torvalds union { 15932209bcb1SRalf Baechle union ieee754dp d; 15942209bcb1SRalf Baechle union ieee754sp s; 15951da177e4SLinus Torvalds int w; 15961da177e4SLinus Torvalds s64 l; 15971da177e4SLinus Torvalds } rv; /* resulting value */ 15981da177e4SLinus Torvalds 1599b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(cp1ops); 16001da177e4SLinus Torvalds switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { 16011da177e4SLinus Torvalds case s_fmt:{ /* 0 */ 16021da177e4SLinus Torvalds union { 16032209bcb1SRalf Baechle union ieee754sp(*b) (union ieee754sp, union ieee754sp); 16042209bcb1SRalf Baechle union ieee754sp(*u) (union ieee754sp); 16051da177e4SLinus Torvalds } handler; 16061da177e4SLinus Torvalds 16071da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 16081da177e4SLinus Torvalds /* binary ops */ 16091da177e4SLinus Torvalds case fadd_op: 16101da177e4SLinus Torvalds handler.b = ieee754sp_add; 16111da177e4SLinus Torvalds goto scopbop; 16121da177e4SLinus Torvalds case fsub_op: 16131da177e4SLinus Torvalds handler.b = ieee754sp_sub; 16141da177e4SLinus Torvalds goto scopbop; 16151da177e4SLinus Torvalds case fmul_op: 16161da177e4SLinus Torvalds handler.b = ieee754sp_mul; 16171da177e4SLinus Torvalds goto scopbop; 16181da177e4SLinus Torvalds case fdiv_op: 16191da177e4SLinus Torvalds handler.b = ieee754sp_div; 16201da177e4SLinus Torvalds goto scopbop; 16211da177e4SLinus Torvalds 16221da177e4SLinus Torvalds /* unary ops */ 16231da177e4SLinus Torvalds case fsqrt_op: 1624*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1625*08a07904SRalf Baechle return SIGILL; 1626*08a07904SRalf Baechle 16271da177e4SLinus Torvalds handler.u = ieee754sp_sqrt; 16281da177e4SLinus Torvalds goto scopuop; 1629*08a07904SRalf Baechle /* 1630*08a07904SRalf Baechle * Note that on some MIPS IV implementations such as the 1631*08a07904SRalf Baechle * R5000 and R8000 the FSQRT and FRECIP instructions do not 1632*08a07904SRalf Baechle * achieve full IEEE-754 accuracy - however this emulator does. 1633*08a07904SRalf Baechle */ 16341da177e4SLinus Torvalds case frsqrt_op: 1635*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r2) 1636*08a07904SRalf Baechle return SIGILL; 1637*08a07904SRalf Baechle 16381da177e4SLinus Torvalds handler.u = fpemu_sp_rsqrt; 16391da177e4SLinus Torvalds goto scopuop; 16401da177e4SLinus Torvalds case frecip_op: 1641*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r2) 1642*08a07904SRalf Baechle return SIGILL; 1643*08a07904SRalf Baechle 16441da177e4SLinus Torvalds handler.u = fpemu_sp_recip; 16451da177e4SLinus Torvalds goto scopuop; 1646*08a07904SRalf Baechle 16471da177e4SLinus Torvalds case fmovc_op: 1648*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1649*08a07904SRalf Baechle return SIGILL; 1650*08a07904SRalf Baechle 16511da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 16521da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) != 16531da177e4SLinus Torvalds ((MIPSInst_FT(ir) & 1) != 0)) 16541da177e4SLinus Torvalds return 0; 16551da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16561da177e4SLinus Torvalds break; 16571da177e4SLinus Torvalds case fmovz_op: 1658*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1659*08a07904SRalf Baechle return SIGILL; 1660*08a07904SRalf Baechle 16611da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] != 0) 16621da177e4SLinus Torvalds return 0; 16631da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16641da177e4SLinus Torvalds break; 16651da177e4SLinus Torvalds case fmovn_op: 1666*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1667*08a07904SRalf Baechle return SIGILL; 1668*08a07904SRalf Baechle 16691da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] == 0) 16701da177e4SLinus Torvalds return 0; 16711da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16721da177e4SLinus Torvalds break; 16731da177e4SLinus Torvalds case fabs_op: 16741da177e4SLinus Torvalds handler.u = ieee754sp_abs; 16751da177e4SLinus Torvalds goto scopuop; 16761da177e4SLinus Torvalds case fneg_op: 16771da177e4SLinus Torvalds handler.u = ieee754sp_neg; 16781da177e4SLinus Torvalds goto scopuop; 16791da177e4SLinus Torvalds case fmov_op: 16801da177e4SLinus Torvalds /* an easy one */ 16811da177e4SLinus Torvalds SPFROMREG(rv.s, MIPSInst_FS(ir)); 16821da177e4SLinus Torvalds goto copcsr; 16831da177e4SLinus Torvalds 16841da177e4SLinus Torvalds /* binary op on handler */ 16851da177e4SLinus Torvalds scopbop: 16861da177e4SLinus Torvalds { 16872209bcb1SRalf Baechle union ieee754sp fs, ft; 16881da177e4SLinus Torvalds 16891da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 16901da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 16911da177e4SLinus Torvalds 16921da177e4SLinus Torvalds rv.s = (*handler.b) (fs, ft); 16931da177e4SLinus Torvalds goto copcsr; 16941da177e4SLinus Torvalds } 16951da177e4SLinus Torvalds scopuop: 16961da177e4SLinus Torvalds { 16972209bcb1SRalf Baechle union ieee754sp fs; 16981da177e4SLinus Torvalds 16991da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17001da177e4SLinus Torvalds rv.s = (*handler.u) (fs); 17011da177e4SLinus Torvalds goto copcsr; 17021da177e4SLinus Torvalds } 17031da177e4SLinus Torvalds copcsr: 17041da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_INEXACT)) 17051da177e4SLinus Torvalds rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; 17061da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_UNDERFLOW)) 17071da177e4SLinus Torvalds rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; 17081da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_OVERFLOW)) 17091da177e4SLinus Torvalds rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; 17101da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) 17111da177e4SLinus Torvalds rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; 17121da177e4SLinus Torvalds if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) 17131da177e4SLinus Torvalds rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 17141da177e4SLinus Torvalds break; 17151da177e4SLinus Torvalds 17161da177e4SLinus Torvalds /* unary conv ops */ 17171da177e4SLinus Torvalds case fcvts_op: 17181da177e4SLinus Torvalds return SIGILL; /* not defined */ 17191da177e4SLinus Torvalds case fcvtd_op:{ 17202209bcb1SRalf Baechle union ieee754sp fs; 17211da177e4SLinus Torvalds 17221da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17231da177e4SLinus Torvalds rv.d = ieee754dp_fsp(fs); 17241da177e4SLinus Torvalds rfmt = d_fmt; 17251da177e4SLinus Torvalds goto copcsr; 17261da177e4SLinus Torvalds } 17271da177e4SLinus Torvalds case fcvtw_op:{ 17282209bcb1SRalf Baechle union ieee754sp fs; 17291da177e4SLinus Torvalds 17301da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17311da177e4SLinus Torvalds rv.w = ieee754sp_tint(fs); 17321da177e4SLinus Torvalds rfmt = w_fmt; 17331da177e4SLinus Torvalds goto copcsr; 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 17361da177e4SLinus Torvalds case fround_op: 17371da177e4SLinus Torvalds case ftrunc_op: 17381da177e4SLinus Torvalds case fceil_op: 17391da177e4SLinus Torvalds case ffloor_op:{ 17401da177e4SLinus Torvalds unsigned int oldrm = ieee754_csr.rm; 17412209bcb1SRalf Baechle union ieee754sp fs; 17421da177e4SLinus Torvalds 1743*08a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64) 1744*08a07904SRalf Baechle return SIGILL; 1745*08a07904SRalf Baechle 17461da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17473f135530SShane McDonald ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; 17481da177e4SLinus Torvalds rv.w = ieee754sp_tint(fs); 17491da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 17501da177e4SLinus Torvalds rfmt = w_fmt; 17511da177e4SLinus Torvalds goto copcsr; 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds 17541da177e4SLinus Torvalds case fcvtl_op:{ 17552209bcb1SRalf Baechle union ieee754sp fs; 17561da177e4SLinus Torvalds 1757*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 1758*08a07904SRalf Baechle return SIGILL; 1759*08a07904SRalf Baechle 17601da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17611da177e4SLinus Torvalds rv.l = ieee754sp_tlong(fs); 17621da177e4SLinus Torvalds rfmt = l_fmt; 17631da177e4SLinus Torvalds goto copcsr; 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds case froundl_op: 17671da177e4SLinus Torvalds case ftruncl_op: 17681da177e4SLinus Torvalds case fceill_op: 17691da177e4SLinus Torvalds case ffloorl_op:{ 17701da177e4SLinus Torvalds unsigned int oldrm = ieee754_csr.rm; 17712209bcb1SRalf Baechle union ieee754sp fs; 17721da177e4SLinus Torvalds 1773*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 1774*08a07904SRalf Baechle return SIGILL; 1775*08a07904SRalf Baechle 17761da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17773f135530SShane McDonald ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; 17781da177e4SLinus Torvalds rv.l = ieee754sp_tlong(fs); 17791da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 17801da177e4SLinus Torvalds rfmt = l_fmt; 17811da177e4SLinus Torvalds goto copcsr; 17821da177e4SLinus Torvalds } 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds default: 17851da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) >= fcmp_op) { 17861da177e4SLinus Torvalds unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 17872209bcb1SRalf Baechle union ieee754sp fs, ft; 17881da177e4SLinus Torvalds 17891da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 17901da177e4SLinus Torvalds SPFROMREG(ft, MIPSInst_FT(ir)); 17911da177e4SLinus Torvalds rv.w = ieee754sp_cmp(fs, ft, 17921da177e4SLinus Torvalds cmptab[cmpop & 0x7], cmpop & 0x8); 17931da177e4SLinus Torvalds rfmt = -1; 17941da177e4SLinus Torvalds if ((cmpop & 0x8) && ieee754_cxtest 17951da177e4SLinus Torvalds (IEEE754_INVALID_OPERATION)) 17961da177e4SLinus Torvalds rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 17971da177e4SLinus Torvalds else 17981da177e4SLinus Torvalds goto copcsr; 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds } 18011da177e4SLinus Torvalds else { 18021da177e4SLinus Torvalds return SIGILL; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds break; 18051da177e4SLinus Torvalds } 18061da177e4SLinus Torvalds break; 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds 18091da177e4SLinus Torvalds case d_fmt:{ 18101da177e4SLinus Torvalds union { 18112209bcb1SRalf Baechle union ieee754dp(*b) (union ieee754dp, union ieee754dp); 18122209bcb1SRalf Baechle union ieee754dp(*u) (union ieee754dp); 18131da177e4SLinus Torvalds } handler; 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 18161da177e4SLinus Torvalds /* binary ops */ 18171da177e4SLinus Torvalds case fadd_op: 18181da177e4SLinus Torvalds handler.b = ieee754dp_add; 18191da177e4SLinus Torvalds goto dcopbop; 18201da177e4SLinus Torvalds case fsub_op: 18211da177e4SLinus Torvalds handler.b = ieee754dp_sub; 18221da177e4SLinus Torvalds goto dcopbop; 18231da177e4SLinus Torvalds case fmul_op: 18241da177e4SLinus Torvalds handler.b = ieee754dp_mul; 18251da177e4SLinus Torvalds goto dcopbop; 18261da177e4SLinus Torvalds case fdiv_op: 18271da177e4SLinus Torvalds handler.b = ieee754dp_div; 18281da177e4SLinus Torvalds goto dcopbop; 18291da177e4SLinus Torvalds 18301da177e4SLinus Torvalds /* unary ops */ 18311da177e4SLinus Torvalds case fsqrt_op: 1832*08a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5_r) 1833*08a07904SRalf Baechle return SIGILL; 1834*08a07904SRalf Baechle 18351da177e4SLinus Torvalds handler.u = ieee754dp_sqrt; 18361da177e4SLinus Torvalds goto dcopuop; 1837*08a07904SRalf Baechle /* 1838*08a07904SRalf Baechle * Note that on some MIPS IV implementations such as the 1839*08a07904SRalf Baechle * R5000 and R8000 the FSQRT and FRECIP instructions do not 1840*08a07904SRalf Baechle * achieve full IEEE-754 accuracy - however this emulator does. 1841*08a07904SRalf Baechle */ 18421da177e4SLinus Torvalds case frsqrt_op: 1843*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r2) 1844*08a07904SRalf Baechle return SIGILL; 1845*08a07904SRalf Baechle 18461da177e4SLinus Torvalds handler.u = fpemu_dp_rsqrt; 18471da177e4SLinus Torvalds goto dcopuop; 18481da177e4SLinus Torvalds case frecip_op: 1849*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r2) 1850*08a07904SRalf Baechle return SIGILL; 1851*08a07904SRalf Baechle 18521da177e4SLinus Torvalds handler.u = fpemu_dp_recip; 18531da177e4SLinus Torvalds goto dcopuop; 18541da177e4SLinus Torvalds case fmovc_op: 1855*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1856*08a07904SRalf Baechle return SIGILL; 1857*08a07904SRalf Baechle 18581da177e4SLinus Torvalds cond = fpucondbit[MIPSInst_FT(ir) >> 2]; 18591da177e4SLinus Torvalds if (((ctx->fcr31 & cond) != 0) != 18601da177e4SLinus Torvalds ((MIPSInst_FT(ir) & 1) != 0)) 18611da177e4SLinus Torvalds return 0; 18621da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18631da177e4SLinus Torvalds break; 18641da177e4SLinus Torvalds case fmovz_op: 1865*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1866*08a07904SRalf Baechle return SIGILL; 1867*08a07904SRalf Baechle 18681da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] != 0) 18691da177e4SLinus Torvalds return 0; 18701da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18711da177e4SLinus Torvalds break; 18721da177e4SLinus Torvalds case fmovn_op: 1873*08a07904SRalf Baechle if (!cpu_has_mips_4_5_r) 1874*08a07904SRalf Baechle return SIGILL; 1875*08a07904SRalf Baechle 18761da177e4SLinus Torvalds if (xcp->regs[MIPSInst_FT(ir)] == 0) 18771da177e4SLinus Torvalds return 0; 18781da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18791da177e4SLinus Torvalds break; 18801da177e4SLinus Torvalds case fabs_op: 18811da177e4SLinus Torvalds handler.u = ieee754dp_abs; 18821da177e4SLinus Torvalds goto dcopuop; 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds case fneg_op: 18851da177e4SLinus Torvalds handler.u = ieee754dp_neg; 18861da177e4SLinus Torvalds goto dcopuop; 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds case fmov_op: 18891da177e4SLinus Torvalds /* an easy one */ 18901da177e4SLinus Torvalds DPFROMREG(rv.d, MIPSInst_FS(ir)); 18911da177e4SLinus Torvalds goto copcsr; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds /* binary op on handler */ 18941da177e4SLinus Torvalds dcopbop:{ 18952209bcb1SRalf Baechle union ieee754dp fs, ft; 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 18981da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 18991da177e4SLinus Torvalds 19001da177e4SLinus Torvalds rv.d = (*handler.b) (fs, ft); 19011da177e4SLinus Torvalds goto copcsr; 19021da177e4SLinus Torvalds } 19031da177e4SLinus Torvalds dcopuop:{ 19042209bcb1SRalf Baechle union ieee754dp fs; 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19071da177e4SLinus Torvalds rv.d = (*handler.u) (fs); 19081da177e4SLinus Torvalds goto copcsr; 19091da177e4SLinus Torvalds } 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds /* unary conv ops */ 19121da177e4SLinus Torvalds case fcvts_op:{ 19132209bcb1SRalf Baechle union ieee754dp fs; 19141da177e4SLinus Torvalds 19151da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19161da177e4SLinus Torvalds rv.s = ieee754sp_fdp(fs); 19171da177e4SLinus Torvalds rfmt = s_fmt; 19181da177e4SLinus Torvalds goto copcsr; 19191da177e4SLinus Torvalds } 19201da177e4SLinus Torvalds case fcvtd_op: 19211da177e4SLinus Torvalds return SIGILL; /* not defined */ 19221da177e4SLinus Torvalds 19231da177e4SLinus Torvalds case fcvtw_op:{ 19242209bcb1SRalf Baechle union ieee754dp fs; 19251da177e4SLinus Torvalds 19261da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19271da177e4SLinus Torvalds rv.w = ieee754dp_tint(fs); /* wrong */ 19281da177e4SLinus Torvalds rfmt = w_fmt; 19291da177e4SLinus Torvalds goto copcsr; 19301da177e4SLinus Torvalds } 19311da177e4SLinus Torvalds 19321da177e4SLinus Torvalds case fround_op: 19331da177e4SLinus Torvalds case ftrunc_op: 19341da177e4SLinus Torvalds case fceil_op: 19351da177e4SLinus Torvalds case ffloor_op:{ 19361da177e4SLinus Torvalds unsigned int oldrm = ieee754_csr.rm; 19372209bcb1SRalf Baechle union ieee754dp fs; 19381da177e4SLinus Torvalds 1939*08a07904SRalf Baechle if (!cpu_has_mips_2_3_4_5_r) 1940*08a07904SRalf Baechle return SIGILL; 1941*08a07904SRalf Baechle 19421da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19433f135530SShane McDonald ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; 19441da177e4SLinus Torvalds rv.w = ieee754dp_tint(fs); 19451da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 19461da177e4SLinus Torvalds rfmt = w_fmt; 19471da177e4SLinus Torvalds goto copcsr; 19481da177e4SLinus Torvalds } 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds case fcvtl_op:{ 19512209bcb1SRalf Baechle union ieee754dp fs; 19521da177e4SLinus Torvalds 1953*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 1954*08a07904SRalf Baechle return SIGILL; 1955*08a07904SRalf Baechle 19561da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19571da177e4SLinus Torvalds rv.l = ieee754dp_tlong(fs); 19581da177e4SLinus Torvalds rfmt = l_fmt; 19591da177e4SLinus Torvalds goto copcsr; 19601da177e4SLinus Torvalds } 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds case froundl_op: 19631da177e4SLinus Torvalds case ftruncl_op: 19641da177e4SLinus Torvalds case fceill_op: 19651da177e4SLinus Torvalds case ffloorl_op:{ 19661da177e4SLinus Torvalds unsigned int oldrm = ieee754_csr.rm; 19672209bcb1SRalf Baechle union ieee754dp fs; 19681da177e4SLinus Torvalds 1969*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 1970*08a07904SRalf Baechle return SIGILL; 1971*08a07904SRalf Baechle 19721da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19733f135530SShane McDonald ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; 19741da177e4SLinus Torvalds rv.l = ieee754dp_tlong(fs); 19751da177e4SLinus Torvalds ieee754_csr.rm = oldrm; 19761da177e4SLinus Torvalds rfmt = l_fmt; 19771da177e4SLinus Torvalds goto copcsr; 19781da177e4SLinus Torvalds } 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds default: 19811da177e4SLinus Torvalds if (MIPSInst_FUNC(ir) >= fcmp_op) { 19821da177e4SLinus Torvalds unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; 19832209bcb1SRalf Baechle union ieee754dp fs, ft; 19841da177e4SLinus Torvalds 19851da177e4SLinus Torvalds DPFROMREG(fs, MIPSInst_FS(ir)); 19861da177e4SLinus Torvalds DPFROMREG(ft, MIPSInst_FT(ir)); 19871da177e4SLinus Torvalds rv.w = ieee754dp_cmp(fs, ft, 19881da177e4SLinus Torvalds cmptab[cmpop & 0x7], cmpop & 0x8); 19891da177e4SLinus Torvalds rfmt = -1; 19901da177e4SLinus Torvalds if ((cmpop & 0x8) 19911da177e4SLinus Torvalds && 19921da177e4SLinus Torvalds ieee754_cxtest 19931da177e4SLinus Torvalds (IEEE754_INVALID_OPERATION)) 19941da177e4SLinus Torvalds rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; 19951da177e4SLinus Torvalds else 19961da177e4SLinus Torvalds goto copcsr; 19971da177e4SLinus Torvalds 19981da177e4SLinus Torvalds } 19991da177e4SLinus Torvalds else { 20001da177e4SLinus Torvalds return SIGILL; 20011da177e4SLinus Torvalds } 20021da177e4SLinus Torvalds break; 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds break; 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 20071da177e4SLinus Torvalds case w_fmt:{ 20082209bcb1SRalf Baechle union ieee754sp fs; 20091da177e4SLinus Torvalds 20101da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 20111da177e4SLinus Torvalds case fcvts_op: 20121da177e4SLinus Torvalds /* convert word to single precision real */ 20131da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 20141da177e4SLinus Torvalds rv.s = ieee754sp_fint(fs.bits); 20151da177e4SLinus Torvalds rfmt = s_fmt; 20161da177e4SLinus Torvalds goto copcsr; 20171da177e4SLinus Torvalds case fcvtd_op: 20181da177e4SLinus Torvalds /* convert word to double precision real */ 20191da177e4SLinus Torvalds SPFROMREG(fs, MIPSInst_FS(ir)); 20201da177e4SLinus Torvalds rv.d = ieee754dp_fint(fs.bits); 20211da177e4SLinus Torvalds rfmt = d_fmt; 20221da177e4SLinus Torvalds goto copcsr; 20231da177e4SLinus Torvalds default: 20241da177e4SLinus Torvalds return SIGILL; 20251da177e4SLinus Torvalds } 20261da177e4SLinus Torvalds break; 20271da177e4SLinus Torvalds } 20281da177e4SLinus Torvalds 20291da177e4SLinus Torvalds case l_fmt:{ 2030bbd426f5SPaul Burton u64 bits; 2031*08a07904SRalf Baechle 2032*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 2033*08a07904SRalf Baechle return SIGILL; 2034*08a07904SRalf Baechle 2035bbd426f5SPaul Burton DIFROMREG(bits, MIPSInst_FS(ir)); 2036bbd426f5SPaul Burton 20371da177e4SLinus Torvalds switch (MIPSInst_FUNC(ir)) { 20381da177e4SLinus Torvalds case fcvts_op: 20391da177e4SLinus Torvalds /* convert long to single precision real */ 2040bbd426f5SPaul Burton rv.s = ieee754sp_flong(bits); 20411da177e4SLinus Torvalds rfmt = s_fmt; 20421da177e4SLinus Torvalds goto copcsr; 20431da177e4SLinus Torvalds case fcvtd_op: 20441da177e4SLinus Torvalds /* convert long to double precision real */ 2045bbd426f5SPaul Burton rv.d = ieee754dp_flong(bits); 20461da177e4SLinus Torvalds rfmt = d_fmt; 20471da177e4SLinus Torvalds goto copcsr; 20481da177e4SLinus Torvalds default: 20491da177e4SLinus Torvalds return SIGILL; 20501da177e4SLinus Torvalds } 20511da177e4SLinus Torvalds break; 20521da177e4SLinus Torvalds } 20531da177e4SLinus Torvalds 20541da177e4SLinus Torvalds default: 20551da177e4SLinus Torvalds return SIGILL; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds 20581da177e4SLinus Torvalds /* 20591da177e4SLinus Torvalds * Update the fpu CSR register for this operation. 20601da177e4SLinus Torvalds * If an exception is required, generate a tidy SIGFPE exception, 20611da177e4SLinus Torvalds * without updating the result register. 20621da177e4SLinus Torvalds * Note: cause exception bits do not accumulate, they are rewritten 20631da177e4SLinus Torvalds * for each op; only the flag/sticky bits accumulate. 20641da177e4SLinus Torvalds */ 20651da177e4SLinus Torvalds ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 20661da177e4SLinus Torvalds if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 20671da177e4SLinus Torvalds /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ 20681da177e4SLinus Torvalds return SIGFPE; 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds 20711da177e4SLinus Torvalds /* 20721da177e4SLinus Torvalds * Now we can safely write the result back to the register file. 20731da177e4SLinus Torvalds */ 20741da177e4SLinus Torvalds switch (rfmt) { 2075*08a07904SRalf Baechle unsigned int cbit; 2076*08a07904SRalf Baechle case -1: 2077*08a07904SRalf Baechle 2078*08a07904SRalf Baechle if (cpu_has_mips_4_5_r) 2079*08a07904SRalf Baechle cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; 20801da177e4SLinus Torvalds else 2081*08a07904SRalf Baechle cbit = FPU_CSR_COND; 2082*08a07904SRalf Baechle if (rv.w) 2083*08a07904SRalf Baechle ctx->fcr31 |= cbit; 2084*08a07904SRalf Baechle else 2085*08a07904SRalf Baechle ctx->fcr31 &= ~cbit; 20861da177e4SLinus Torvalds break; 2087*08a07904SRalf Baechle 20881da177e4SLinus Torvalds case d_fmt: 20891da177e4SLinus Torvalds DPTOREG(rv.d, MIPSInst_FD(ir)); 20901da177e4SLinus Torvalds break; 20911da177e4SLinus Torvalds case s_fmt: 20921da177e4SLinus Torvalds SPTOREG(rv.s, MIPSInst_FD(ir)); 20931da177e4SLinus Torvalds break; 20941da177e4SLinus Torvalds case w_fmt: 20951da177e4SLinus Torvalds SITOREG(rv.w, MIPSInst_FD(ir)); 20961da177e4SLinus Torvalds break; 20971da177e4SLinus Torvalds case l_fmt: 2098*08a07904SRalf Baechle if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) 2099*08a07904SRalf Baechle return SIGILL; 2100*08a07904SRalf Baechle 21011da177e4SLinus Torvalds DITOREG(rv.l, MIPSInst_FD(ir)); 21021da177e4SLinus Torvalds break; 21031da177e4SLinus Torvalds default: 21041da177e4SLinus Torvalds return SIGILL; 21051da177e4SLinus Torvalds } 21061da177e4SLinus Torvalds 21071da177e4SLinus Torvalds return 0; 21081da177e4SLinus Torvalds } 21091da177e4SLinus Torvalds 2110e04582b7SAtsushi Nemoto int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, 2111515b029dSDavid Daney int has_fpu, void *__user *fault_addr) 21121da177e4SLinus Torvalds { 2113333d1f67SRalf Baechle unsigned long oldepc, prevepc; 2114102cedc3SLeonid Yegoshin struct mm_decoded_insn dec_insn; 2115102cedc3SLeonid Yegoshin u16 instr[4]; 2116102cedc3SLeonid Yegoshin u16 *instr_ptr; 21171da177e4SLinus Torvalds int sig = 0; 21181da177e4SLinus Torvalds 21191da177e4SLinus Torvalds oldepc = xcp->cp0_epc; 21201da177e4SLinus Torvalds do { 21211da177e4SLinus Torvalds prevepc = xcp->cp0_epc; 21221da177e4SLinus Torvalds 2123102cedc3SLeonid Yegoshin if (get_isa16_mode(prevepc) && cpu_has_mmips) { 2124102cedc3SLeonid Yegoshin /* 2125102cedc3SLeonid Yegoshin * Get next 2 microMIPS instructions and convert them 2126102cedc3SLeonid Yegoshin * into 32-bit instructions. 2127102cedc3SLeonid Yegoshin */ 2128102cedc3SLeonid Yegoshin if ((get_user(instr[0], (u16 __user *)msk_isa16_mode(xcp->cp0_epc))) || 2129102cedc3SLeonid Yegoshin (get_user(instr[1], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 2))) || 2130102cedc3SLeonid Yegoshin (get_user(instr[2], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 4))) || 2131102cedc3SLeonid Yegoshin (get_user(instr[3], (u16 __user *)msk_isa16_mode(xcp->cp0_epc + 6)))) { 2132b6ee75edSDavid Daney MIPS_FPU_EMU_INC_STATS(errors); 21331da177e4SLinus Torvalds return SIGBUS; 21341da177e4SLinus Torvalds } 2135102cedc3SLeonid Yegoshin instr_ptr = instr; 2136102cedc3SLeonid Yegoshin 2137102cedc3SLeonid Yegoshin /* Get first instruction. */ 2138102cedc3SLeonid Yegoshin if (mm_insn_16bit(*instr_ptr)) { 2139102cedc3SLeonid Yegoshin /* Duplicate the half-word. */ 2140102cedc3SLeonid Yegoshin dec_insn.insn = (*instr_ptr << 16) | 2141102cedc3SLeonid Yegoshin (*instr_ptr); 2142102cedc3SLeonid Yegoshin /* 16-bit instruction. */ 2143102cedc3SLeonid Yegoshin dec_insn.pc_inc = 2; 2144102cedc3SLeonid Yegoshin instr_ptr += 1; 2145102cedc3SLeonid Yegoshin } else { 2146102cedc3SLeonid Yegoshin dec_insn.insn = (*instr_ptr << 16) | 2147102cedc3SLeonid Yegoshin *(instr_ptr+1); 2148102cedc3SLeonid Yegoshin /* 32-bit instruction. */ 2149102cedc3SLeonid Yegoshin dec_insn.pc_inc = 4; 2150102cedc3SLeonid Yegoshin instr_ptr += 2; 2151515b029dSDavid Daney } 2152102cedc3SLeonid Yegoshin /* Get second instruction. */ 2153102cedc3SLeonid Yegoshin if (mm_insn_16bit(*instr_ptr)) { 2154102cedc3SLeonid Yegoshin /* Duplicate the half-word. */ 2155102cedc3SLeonid Yegoshin dec_insn.next_insn = (*instr_ptr << 16) | 2156102cedc3SLeonid Yegoshin (*instr_ptr); 2157102cedc3SLeonid Yegoshin /* 16-bit instruction. */ 2158102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 2; 2159102cedc3SLeonid Yegoshin } else { 2160102cedc3SLeonid Yegoshin dec_insn.next_insn = (*instr_ptr << 16) | 2161102cedc3SLeonid Yegoshin *(instr_ptr+1); 2162102cedc3SLeonid Yegoshin /* 32-bit instruction. */ 2163102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 4; 2164102cedc3SLeonid Yegoshin } 2165102cedc3SLeonid Yegoshin dec_insn.micro_mips_mode = 1; 2166102cedc3SLeonid Yegoshin } else { 2167102cedc3SLeonid Yegoshin if ((get_user(dec_insn.insn, 2168102cedc3SLeonid Yegoshin (mips_instruction __user *) xcp->cp0_epc)) || 2169102cedc3SLeonid Yegoshin (get_user(dec_insn.next_insn, 2170102cedc3SLeonid Yegoshin (mips_instruction __user *)(xcp->cp0_epc+4)))) { 2171102cedc3SLeonid Yegoshin MIPS_FPU_EMU_INC_STATS(errors); 2172102cedc3SLeonid Yegoshin return SIGBUS; 2173102cedc3SLeonid Yegoshin } 2174102cedc3SLeonid Yegoshin dec_insn.pc_inc = 4; 2175102cedc3SLeonid Yegoshin dec_insn.next_pc_inc = 4; 2176102cedc3SLeonid Yegoshin dec_insn.micro_mips_mode = 0; 2177102cedc3SLeonid Yegoshin } 2178102cedc3SLeonid Yegoshin 2179102cedc3SLeonid Yegoshin if ((dec_insn.insn == 0) || 2180102cedc3SLeonid Yegoshin ((dec_insn.pc_inc == 2) && 2181102cedc3SLeonid Yegoshin ((dec_insn.insn & 0xffff) == MM_NOP16))) 2182102cedc3SLeonid Yegoshin xcp->cp0_epc += dec_insn.pc_inc; /* Skip NOPs */ 21831da177e4SLinus Torvalds else { 2184cd21dfcfSRalf Baechle /* 2185cd21dfcfSRalf Baechle * The 'ieee754_csr' is an alias of 2186cd21dfcfSRalf Baechle * ctx->fcr31. No need to copy ctx->fcr31 to 2187cd21dfcfSRalf Baechle * ieee754_csr. But ieee754_csr.rm is ieee 2188cd21dfcfSRalf Baechle * library modes. (not mips rounding mode) 2189cd21dfcfSRalf Baechle */ 2190cd21dfcfSRalf Baechle /* convert to ieee library modes */ 2191cd21dfcfSRalf Baechle ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; 2192102cedc3SLeonid Yegoshin sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); 2193cd21dfcfSRalf Baechle /* revert to mips rounding mode */ 2194cd21dfcfSRalf Baechle ieee754_csr.rm = mips_rm[ieee754_csr.rm]; 21951da177e4SLinus Torvalds } 21961da177e4SLinus Torvalds 2197e04582b7SAtsushi Nemoto if (has_fpu) 21981da177e4SLinus Torvalds break; 21991da177e4SLinus Torvalds if (sig) 22001da177e4SLinus Torvalds break; 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds cond_resched(); 22031da177e4SLinus Torvalds } while (xcp->cp0_epc > prevepc); 22041da177e4SLinus Torvalds 22051da177e4SLinus Torvalds /* SIGILL indicates a non-fpu instruction */ 22061da177e4SLinus Torvalds if (sig == SIGILL && xcp->cp0_epc != oldepc) 22071da177e4SLinus Torvalds /* but if epc has advanced, then ignore it */ 22081da177e4SLinus Torvalds sig = 0; 22091da177e4SLinus Torvalds 22101da177e4SLinus Torvalds return sig; 22111da177e4SLinus Torvalds } 2212