^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Linux/PA-RISC Project (http://www.parisc-linux.org/)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Floating-point emulation code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * linux/arch/math-emu/driver.c.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * decodes and dispatches unimplemented FPU instructions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Copyright (C) 2001 Hewlett-Packard <bame@debian.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/sched/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "float.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "math-emu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define fptpos 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define fpr1pos 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define FPUDEBUG 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* Format of the floating-point exception registers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct exc_reg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned int exception : 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) unsigned int ei : 26;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Macros for grabbing bits of the instruction format from the 'ei'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) field above. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Major opcode 0c and 0e */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define FP0CE_UID(i) (((i) >> 6) & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define FP0CE_CLASS(i) (((i) >> 9) & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define FP0CE_SUBOP(i) (((i) >> 13) & 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define FP0C_FORMAT(i) (((i) >> 11) & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define FP0E_FORMAT(i) (((i) >> 11) & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Major opcode 0c, uid 2 (performance monitoring) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* Major opcode 2e (fused operations). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define FP2E_SUBOP(i) (((i) >> 5) & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define FP2E_FORMAT(i) (((i) >> 11) & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* Major opcode 26 (FMPYSUB) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* Major opcode 06 (FMPYADD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define FPx6_FORMAT(i) ((i) & 0x1f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* Flags and enable bits of the status word. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define FPSW_FLAGS(w) ((w) >> 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define FPSW_ENABLE(w) ((w) & 0x1f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define FPSW_V (1<<4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define FPSW_Z (1<<3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define FPSW_O (1<<2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define FPSW_U (1<<1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define FPSW_I (1<<0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* Handle a floating point exception. Return zero if the faulting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) instruction can be completed successfully. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) handle_fpe(struct pt_regs *regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) extern void printbinary(unsigned long x, int nbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) unsigned int orig_sw, sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int signalcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* need an intermediate copy of float regs because FPU emulation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * code expects an artificial last entry which contains zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * also, the passed in fr registers contain one word that defines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * the fpu type. the fpu type information is constructed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * inside the emulation code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) __u64 frcopy[36];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) memcpy(frcopy, regs->fr, sizeof regs->fr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) frcopy[32] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) memcpy(&orig_sw, frcopy, sizeof(orig_sw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (FPUDEBUG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) printbinary(orig_sw, 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) printk(KERN_DEBUG "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) signalcode = decode_fpu(frcopy, 0x666);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* Status word = FR0L. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) memcpy(&sw, frcopy, sizeof(sw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (FPUDEBUG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) signalcode >> 24, signalcode & 0xffffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) printbinary(sw, 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) printk(KERN_DEBUG "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) memcpy(regs->fr, frcopy, sizeof regs->fr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (signalcode != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) force_sig_fault(signalcode >> 24, signalcode & 0xffffff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) (void __user *) regs->iaoq[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return signalcode ? -1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }