1 // SPDX-License-Identifier: GPL-2.0-only 1 2 #include <linux/module.h> 3 #include <linux/types.h> 4 #include <linux/kernel.h> 5 #include <linux/sched.h> 6 #include <asm/ptrace.h> 7 #include <asm/fpu.h> 8 9 #include <linux/uaccess.h> 10 11 #include "sfp-util.h" 12 #include <math-emu/soft-fp.h> 13 #include <math-emu/single.h> 14 #include <math-emu/double.h> 15 16 #define OPC_PAL 0x00 17 #define OPC_INTA 0x10 18 #define OPC_INTL 0x11 19 #define OPC_INTS 0x12 20 #define OPC_INTM 0x13 21 #define OPC_FLTC 0x14 22 #define OPC_FLTV 0x15 23 #define OPC_FLTI 0x16 24 #define OPC_FLTL 0x17 25 #define OPC_MISC 0x18 26 #define OPC_JSR 0x1a 27 28 #define FOP_SRC_S 0 29 #define FOP_SRC_T 2 30 #define FOP_SRC_Q 3 31 32 #define FOP_FNC_ADDx 0 33 #define FOP_FNC_CVTQL 0 34 #define FOP_FNC_SUBx 1 35 #define FOP_FNC_MULx 2 36 #define FOP_FNC_DIVx 3 37 #define FOP_FNC_CMPxUN 4 38 #define FOP_FNC_CMPxEQ 5 39 #define FOP_FNC_CMPxLT 6 40 #define FOP_FNC_CMPxLE 7 41 #define FOP_FNC_SQRTx 11 42 #define FOP_FNC_CVTxS 12 43 #define FOP_FNC_CVTxT 14 44 #define FOP_FNC_CVTxQ 15 45 46 #define MISC_TRAPB 0x0000 47 #define MISC_EXCB 0x0400 48 49 #ifdef MODULE 50 51 MODULE_DESCRIPTION("FP Software completion mod 52 MODULE_LICENSE("GPL v2"); 53 54 extern long (*alpha_fp_emul_imprecise)(struct 55 extern long (*alpha_fp_emul) (unsigned long pc 56 57 static long (*save_emul_imprecise)(struct pt_r 58 static long (*save_emul) (unsigned long pc); 59 60 long do_alpha_fp_emul_imprecise(struct pt_regs 61 long do_alpha_fp_emul(unsigned long); 62 63 static int alpha_fp_emul_init_module(void) 64 { 65 save_emul_imprecise = alpha_fp_emul_im 66 save_emul = alpha_fp_emul; 67 alpha_fp_emul_imprecise = do_alpha_fp_ 68 alpha_fp_emul = do_alpha_fp_emul; 69 return 0; 70 } 71 module_init(alpha_fp_emul_init_module); 72 73 static void alpha_fp_emul_cleanup_module(void) 74 { 75 alpha_fp_emul_imprecise = save_emul_im 76 alpha_fp_emul = save_emul; 77 } 78 module_exit(alpha_fp_emul_cleanup_module); 79 80 #undef alpha_fp_emul_imprecise 81 #define alpha_fp_emul_imprecise do_alp 82 #undef alpha_fp_emul 83 #define alpha_fp_emul do_alp 84 85 #endif /* MODULE */ 86 87 88 /* 89 * Emulate the floating point instruction at a 90 * instruction to be emulated is illegal (such 91 * the SI_CODE for a SIGFPE signal, else 0 if 92 * 93 * Notice that the kernel does not and cannot 94 * because it means that instead of saving/res 95 * stick the result of the operation into the 96 */ 97 long 98 alpha_fp_emul (unsigned long pc) 99 { 100 FP_DECL_EX; 101 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_ 102 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_ 103 104 unsigned long fa, fb, fc, func, mode, 105 unsigned long res, va, vb, vc, swcr, f 106 __u32 insn; 107 long si_code; 108 109 get_user(insn, (__u32 __user *)pc); 110 fc = (insn >> 0) & 0x1f; /* des 111 fb = (insn >> 16) & 0x1f; 112 fa = (insn >> 21) & 0x1f; 113 func = (insn >> 5) & 0xf; 114 src = (insn >> 9) & 0x3; 115 mode = (insn >> 11) & 0x3; 116 117 fpcr = rdfpcr(); 118 swcr = swcr_update_status(current_thre 119 120 if (mode == 3) { 121 /* Dynamic -- get rounding mod 122 mode = (fpcr >> FPCR_DYN_SHIFT 123 } 124 125 switch (src) { 126 case FOP_SRC_S: 127 va = alpha_read_fp_reg_s(fa); 128 vb = alpha_read_fp_reg_s(fb); 129 130 FP_UNPACK_SP(SA, &va); 131 FP_UNPACK_SP(SB, &vb); 132 133 switch (func) { 134 case FOP_FNC_SUBx: 135 FP_SUB_S(SR, SA, SB); 136 goto pack_s; 137 138 case FOP_FNC_ADDx: 139 FP_ADD_S(SR, SA, SB); 140 goto pack_s; 141 142 case FOP_FNC_MULx: 143 FP_MUL_S(SR, SA, SB); 144 goto pack_s; 145 146 case FOP_FNC_DIVx: 147 FP_DIV_S(SR, SA, SB); 148 goto pack_s; 149 150 case FOP_FNC_SQRTx: 151 FP_SQRT_S(SR, SB); 152 goto pack_s; 153 } 154 goto bad_insn; 155 156 case FOP_SRC_T: 157 va = alpha_read_fp_reg(fa); 158 vb = alpha_read_fp_reg(fb); 159 160 if ((func & ~3) == FOP_FNC_CMP 161 FP_UNPACK_RAW_DP(DA, & 162 FP_UNPACK_RAW_DP(DB, & 163 if (!DA_e && !_FP_FRAC 164 FP_SET_EXCEPTI 165 if (FP_DENORM_ 166 _FP_FR 167 } 168 if (!DB_e && !_FP_FRAC 169 FP_SET_EXCEPTI 170 if (FP_DENORM_ 171 _FP_FR 172 } 173 FP_CMP_D(res, DA, DB, 174 vc = 0x400000000000000 175 /* CMPTEQ, CMPTUN don' 176 while CMPTLT and CM 177 if (res == 3 178 && ((func & 3) >= 179 || FP_ISSIGNAN 180 || FP_ISSIGNAN 181 FP_SET_EXCEPTI 182 } 183 switch (func) { 184 case FOP_FNC_CMPxUN: i 185 case FOP_FNC_CMPxEQ: i 186 case FOP_FNC_CMPxLT: i 187 case FOP_FNC_CMPxLE: i 188 } 189 goto done_d; 190 } 191 192 FP_UNPACK_DP(DA, &va); 193 FP_UNPACK_DP(DB, &vb); 194 195 switch (func) { 196 case FOP_FNC_SUBx: 197 FP_SUB_D(DR, DA, DB); 198 goto pack_d; 199 200 case FOP_FNC_ADDx: 201 FP_ADD_D(DR, DA, DB); 202 goto pack_d; 203 204 case FOP_FNC_MULx: 205 FP_MUL_D(DR, DA, DB); 206 goto pack_d; 207 208 case FOP_FNC_DIVx: 209 FP_DIV_D(DR, DA, DB); 210 goto pack_d; 211 212 case FOP_FNC_SQRTx: 213 FP_SQRT_D(DR, DB); 214 goto pack_d; 215 216 case FOP_FNC_CVTxS: 217 /* It is irritating th 218 SRC == T_floating. 219 the bit used to tel 220 if (insn & 0x2000) { 221 FP_CONV(S,D,1, 222 goto pack_s; 223 } else { 224 vb = alpha_rea 225 FP_UNPACK_SP(S 226 DR_c = DB_c; 227 DR_s = DB_s; 228 DR_e = DB_e + 229 DR_f = SB_f << 230 goto pack_d; 231 } 232 233 case FOP_FNC_CVTxQ: 234 if (DB_c == FP_CLS_NAN 235 && (_FP_FRAC_HIGH_ 236 /* AAHB Table B-2 sa 237 vc = 0; 238 } else 239 FP_TO_INT_ROUN 240 goto done_d; 241 } 242 goto bad_insn; 243 244 case FOP_SRC_Q: 245 vb = alpha_read_fp_reg(fb); 246 247 switch (func) { 248 case FOP_FNC_CVTQL: 249 /* Notice: We can get 250 overflow. Such ove 251 ops. We return the 252 computed. */ 253 vc = ((vb & 0xc0000000 254 (vb & 0x3fffffff 255 FP_SET_EXCEPTION (FP_E 256 goto done_d; 257 258 case FOP_FNC_CVTxS: 259 FP_FROM_INT_S(SR, ((lo 260 goto pack_s; 261 262 case FOP_FNC_CVTxT: 263 FP_FROM_INT_D(DR, ((lo 264 goto pack_d; 265 } 266 goto bad_insn; 267 } 268 goto bad_insn; 269 270 pack_s: 271 FP_PACK_SP(&vc, SR); 272 if ((_fex & FP_EX_UNDERFLOW) && (swcr 273 vc = 0; 274 alpha_write_fp_reg_s(fc, vc); 275 goto done; 276 277 pack_d: 278 FP_PACK_DP(&vc, DR); 279 if ((_fex & FP_EX_UNDERFLOW) && (swcr 280 vc = 0; 281 done_d: 282 alpha_write_fp_reg(fc, vc); 283 goto done; 284 285 /* 286 * Take the appropriate action for eac 287 * floating-point result: 288 * 289 * - Set the appropriate bits in 290 * - If the specified exception i 291 * return. The caller (entArit 292 * the appropriate signal to th 293 * 294 * In addition, properly track the exc 295 * as described in the Alpha Architect 296 */ 297 done: 298 if (_fex) { 299 /* Record exceptions in softwa 300 swcr |= (_fex << IEEE_STATUS_T 301 current_thread_info()->ieee_st 302 |= (_fex << IEEE_STATUS_TO_E 303 304 /* Update hardware control reg 305 fpcr &= (~FPCR_MASK | FPCR_DYN 306 fpcr |= ieee_swcr_to_fpcr(swcr 307 wrfpcr(fpcr); 308 309 /* Do we generate a signal? * 310 _fex = _fex & swcr & IEEE_TRAP 311 si_code = 0; 312 if (_fex) { 313 if (_fex & IEEE_TRAP_E 314 if (_fex & IEEE_TRAP_E 315 if (_fex & IEEE_TRAP_E 316 if (_fex & IEEE_TRAP_E 317 if (_fex & IEEE_TRAP_E 318 if (_fex & IEEE_TRAP_E 319 } 320 321 return si_code; 322 } 323 324 /* We used to write the destination re 325 requires that the result *always* b 326 immediately after the operations ab 327 328 return 0; 329 330 bad_insn: 331 printk(KERN_ERR "alpha_fp_emul: Invali 332 insn, pc); 333 return -1; 334 } 335 336 long 337 alpha_fp_emul_imprecise (struct pt_regs *regs, 338 { 339 unsigned long trigger_pc = regs->pc - 340 unsigned long insn, opcode, rc, si_cod 341 342 /* 343 * Turn off the bits corresponding to 344 * target of instructions that set bit 345 * summary register. We have some sla 346 * register that is the target of a tr 347 * be written at most once in the trap 348 * 349 * Branches, jumps, TRAPBs, EXCBs and 350 * bound the trap shadow, so we need n 351 * up to the first occurrence of such 352 */ 353 while (write_mask) { 354 get_user(insn, (__u32 __user * 355 opcode = insn >> 26; 356 rc = insn & 0x1f; 357 358 switch (opcode) { 359 case OPC_PAL: 360 case OPC_JSR: 361 case 0x30 ... 0x3f: 362 goto egress; 363 364 case OPC_MISC: 365 switch (insn & 0xffff) 366 case MISC_TRAPB: 367 case MISC_EXCB: 368 goto egress; 369 370 default: 371 break; 372 } 373 break; 374 375 case OPC_INTA: 376 case OPC_INTL: 377 case OPC_INTS: 378 case OPC_INTM: 379 write_mask &= ~(1UL << 380 break; 381 382 case OPC_FLTC: 383 case OPC_FLTV: 384 case OPC_FLTI: 385 case OPC_FLTL: 386 write_mask &= ~(1UL << 387 break; 388 } 389 if (!write_mask) { 390 /* Re-execute insns in 391 regs->pc = trigger_pc 392 si_code = alpha_fp_emu 393 goto egress; 394 } 395 trigger_pc -= 4; 396 } 397 398 egress: 399 return si_code; 400 } 401
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.