^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <asm/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "sfp-util.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <math-emu/soft-fp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <math-emu/single.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <math-emu/double.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define OPC_PAL 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define OPC_INTA 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define OPC_INTL 0x11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define OPC_INTS 0x12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define OPC_INTM 0x13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define OPC_FLTC 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define OPC_FLTV 0x15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define OPC_FLTI 0x16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define OPC_FLTL 0x17
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define OPC_MISC 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define OPC_JSR 0x1a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define FOP_SRC_S 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define FOP_SRC_T 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define FOP_SRC_Q 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define FOP_FNC_ADDx 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define FOP_FNC_CVTQL 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define FOP_FNC_SUBx 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define FOP_FNC_MULx 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define FOP_FNC_DIVx 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define FOP_FNC_CMPxUN 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define FOP_FNC_CMPxEQ 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define FOP_FNC_CMPxLT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define FOP_FNC_CMPxLE 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define FOP_FNC_SQRTx 11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define FOP_FNC_CVTxS 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define FOP_FNC_CVTxT 14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define FOP_FNC_CVTxQ 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define MISC_TRAPB 0x0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define MISC_EXCB 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) extern unsigned long alpha_read_fp_reg (unsigned long reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) MODULE_DESCRIPTION("FP Software completion module");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) extern long (*alpha_fp_emul) (unsigned long pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static long (*save_emul_imprecise)(struct pt_regs *, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static long (*save_emul) (unsigned long pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) long do_alpha_fp_emul(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int init_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) save_emul_imprecise = alpha_fp_emul_imprecise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) save_emul = alpha_fp_emul;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) alpha_fp_emul = do_alpha_fp_emul;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void cleanup_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) alpha_fp_emul_imprecise = save_emul_imprecise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) alpha_fp_emul = save_emul;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #undef alpha_fp_emul_imprecise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #undef alpha_fp_emul
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define alpha_fp_emul do_alpha_fp_emul
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #endif /* MODULE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * Emulate the floating point instruction at address PC. Returns -1 if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * instruction to be emulated is illegal (such as with the opDEC trap), else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * the SI_CODE for a SIGFPE signal, else 0 if everything's ok.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * Notice that the kernel does not and cannot use FP regs. This is good
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * because it means that instead of saving/restoring all fp regs, we simply
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * stick the result of the operation into the appropriate register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) alpha_fp_emul (unsigned long pc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) FP_DECL_EX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) unsigned long fa, fb, fc, func, mode, src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) unsigned long res, va, vb, vc, swcr, fpcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) __u32 insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) long si_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) get_user(insn, (__u32 __user *)pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) fc = (insn >> 0) & 0x1f; /* destination register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) fb = (insn >> 16) & 0x1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) fa = (insn >> 21) & 0x1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) func = (insn >> 5) & 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) src = (insn >> 9) & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) mode = (insn >> 11) & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) fpcr = rdfpcr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) swcr = swcr_update_status(current_thread_info()->ieee_state, fpcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (mode == 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* Dynamic -- get rounding mode from fpcr. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) switch (src) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) case FOP_SRC_S:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) va = alpha_read_fp_reg_s(fa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) vb = alpha_read_fp_reg_s(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) FP_UNPACK_SP(SA, &va);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) FP_UNPACK_SP(SB, &vb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) switch (func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) case FOP_FNC_SUBx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) FP_SUB_S(SR, SA, SB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) case FOP_FNC_ADDx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) FP_ADD_S(SR, SA, SB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case FOP_FNC_MULx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) FP_MUL_S(SR, SA, SB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) case FOP_FNC_DIVx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) FP_DIV_S(SR, SA, SB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) case FOP_FNC_SQRTx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) FP_SQRT_S(SR, SB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) goto bad_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case FOP_SRC_T:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) va = alpha_read_fp_reg(fa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) vb = alpha_read_fp_reg(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if ((func & ~3) == FOP_FNC_CMPxUN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) FP_UNPACK_RAW_DP(DA, &va);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) FP_UNPACK_RAW_DP(DB, &vb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (!DA_e && !_FP_FRAC_ZEROP_1(DA)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) FP_SET_EXCEPTION(FP_EX_DENORM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (FP_DENORM_ZERO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) _FP_FRAC_SET_1(DA, _FP_ZEROFRAC_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (!DB_e && !_FP_FRAC_ZEROP_1(DB)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) FP_SET_EXCEPTION(FP_EX_DENORM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (FP_DENORM_ZERO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) _FP_FRAC_SET_1(DB, _FP_ZEROFRAC_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) FP_CMP_D(res, DA, DB, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) vc = 0x4000000000000000UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* CMPTEQ, CMPTUN don't trap on QNaN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) while CMPTLT and CMPTLE do */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (res == 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) && ((func & 3) >= 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) || FP_ISSIGNAN_D(DA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) || FP_ISSIGNAN_D(DB))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) FP_SET_EXCEPTION(FP_EX_INVALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) switch (func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) case FOP_FNC_CMPxEQ: if (res) vc = 0; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) case FOP_FNC_CMPxLT: if (res != -1) vc = 0; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) case FOP_FNC_CMPxLE: if ((long)res > 0) vc = 0; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) goto done_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) FP_UNPACK_DP(DA, &va);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) FP_UNPACK_DP(DB, &vb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) switch (func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case FOP_FNC_SUBx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) FP_SUB_D(DR, DA, DB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case FOP_FNC_ADDx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) FP_ADD_D(DR, DA, DB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) case FOP_FNC_MULx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) FP_MUL_D(DR, DA, DB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) case FOP_FNC_DIVx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) FP_DIV_D(DR, DA, DB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) case FOP_FNC_SQRTx:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) FP_SQRT_D(DR, DB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) case FOP_FNC_CVTxS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* It is irritating that DEC encoded CVTST with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) SRC == T_floating. It is also interesting that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) the bit used to tell the two apart is /U... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (insn & 0x2000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) FP_CONV(S,D,1,1,SR,DB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) vb = alpha_read_fp_reg_s(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) FP_UNPACK_SP(SB, &vb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) DR_c = DB_c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) DR_s = DB_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) DR_e = DB_e + (1024 - 128);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) DR_f = SB_f << (52 - 23);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) case FOP_FNC_CVTxQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (DB_c == FP_CLS_NAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /* AAHB Table B-2 says QNaN should not trigger INV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) vc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) FP_TO_INT_ROUND_D(vc, DB, 64, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) goto done_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) goto bad_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) case FOP_SRC_Q:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) vb = alpha_read_fp_reg(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) switch (func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) case FOP_FNC_CVTQL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* Notice: We can get here only due to an integer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) overflow. Such overflows are reported as invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ops. We return the result the hw would have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) computed. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) vc = ((vb & 0xc0000000) << 32 | /* sign and msb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) (vb & 0x3fffffff) << 29); /* rest of the int */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) FP_SET_EXCEPTION (FP_EX_INVALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto done_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) case FOP_FNC_CVTxS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) FP_FROM_INT_S(SR, ((long)vb), 64, long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) goto pack_s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) case FOP_FNC_CVTxT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) FP_FROM_INT_D(DR, ((long)vb), 64, long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) goto pack_d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) goto bad_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) goto bad_insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) pack_s:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) FP_PACK_SP(&vc, SR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) vc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) alpha_write_fp_reg_s(fc, vc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) pack_d:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) FP_PACK_DP(&vc, DR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if ((_fex & FP_EX_UNDERFLOW) && (swcr & IEEE_MAP_UMZ))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) vc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) done_d:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) alpha_write_fp_reg(fc, vc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * Take the appropriate action for each possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * floating-point result:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * - Set the appropriate bits in the FPCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * - If the specified exception is enabled in the FPCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * return. The caller (entArith) will dispatch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * the appropriate signal to the translated program.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * In addition, properly track the exception state in software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * as described in the Alpha Architecture Handbook section 4.7.7.3.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (_fex) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* Record exceptions in software control word. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) current_thread_info()->ieee_state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* Update hardware control register. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) fpcr |= ieee_swcr_to_fpcr(swcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) wrfpcr(fpcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /* Do we generate a signal? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) _fex = _fex & swcr & IEEE_TRAP_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) si_code = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (_fex) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (_fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (_fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (_fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (_fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (_fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (_fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return si_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* We used to write the destination register here, but DEC FORTRAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) requires that the result *always* be written... so we do the write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) immediately after the operations above. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) bad_insn:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) insn, pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) unsigned long trigger_pc = regs->pc - 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) unsigned long insn, opcode, rc, si_code = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * Turn off the bits corresponding to registers that are the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * target of instructions that set bits in the exception
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * summary register. We have some slack doing this because a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * register that is the target of a trapping instruction can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * be written at most once in the trap shadow.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * bound the trap shadow, so we need not look any further than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * up to the first occurrence of such an instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) while (write_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) get_user(insn, (__u32 __user *)(trigger_pc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) opcode = insn >> 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) rc = insn & 0x1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) switch (opcode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) case OPC_PAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) case OPC_JSR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) case 0x30 ... 0x3f: /* branches */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) goto egress;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) case OPC_MISC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) switch (insn & 0xffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) case MISC_TRAPB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) case MISC_EXCB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) goto egress;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) case OPC_INTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) case OPC_INTL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) case OPC_INTS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) case OPC_INTM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) write_mask &= ~(1UL << rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) case OPC_FLTC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) case OPC_FLTV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) case OPC_FLTI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) case OPC_FLTL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) write_mask &= ~(1UL << (rc + 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (!write_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) /* Re-execute insns in the trap-shadow. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) regs->pc = trigger_pc + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) si_code = alpha_fp_emul(trigger_pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) goto egress;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) trigger_pc -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) egress:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return si_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }