1 /* 2 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 3 * 4 * Floating-point emulation code 5 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 /* 22 * linux/arch/math-emu/driver.c.c 23 * 24 * decodes and dispatches unimplemented FPU instructions 25 * 26 * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org> 27 * Copyright (C) 2001 Hewlett-Packard <bame@debian.org> 28 */ 29 30 #include <linux/sched/signal.h> 31 32 #include "float.h" 33 #include "math-emu.h" 34 35 36 #define fptpos 31 37 #define fpr1pos 10 38 #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) 39 40 #define FPUDEBUG 0 41 42 /* Format of the floating-point exception registers. */ 43 struct exc_reg { 44 unsigned int exception : 6; 45 unsigned int ei : 26; 46 }; 47 48 /* Macros for grabbing bits of the instruction format from the 'ei' 49 field above. */ 50 /* Major opcode 0c and 0e */ 51 #define FP0CE_UID(i) (((i) >> 6) & 3) 52 #define FP0CE_CLASS(i) (((i) >> 9) & 3) 53 #define FP0CE_SUBOP(i) (((i) >> 13) & 7) 54 #define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */ 55 #define FP0C_FORMAT(i) (((i) >> 11) & 3) 56 #define FP0E_FORMAT(i) (((i) >> 11) & 1) 57 58 /* Major opcode 0c, uid 2 (performance monitoring) */ 59 #define FPPM_SUBOP(i) (((i) >> 9) & 0x1f) 60 61 /* Major opcode 2e (fused operations). */ 62 #define FP2E_SUBOP(i) (((i) >> 5) & 1) 63 #define FP2E_FORMAT(i) (((i) >> 11) & 1) 64 65 /* Major opcode 26 (FMPYSUB) */ 66 /* Major opcode 06 (FMPYADD) */ 67 #define FPx6_FORMAT(i) ((i) & 0x1f) 68 69 /* Flags and enable bits of the status word. */ 70 #define FPSW_FLAGS(w) ((w) >> 27) 71 #define FPSW_ENABLE(w) ((w) & 0x1f) 72 #define FPSW_V (1<<4) 73 #define FPSW_Z (1<<3) 74 #define FPSW_O (1<<2) 75 #define FPSW_U (1<<1) 76 #define FPSW_I (1<<0) 77 78 /* Handle a floating point exception. Return zero if the faulting 79 instruction can be completed successfully. */ 80 int 81 handle_fpe(struct pt_regs *regs) 82 { 83 extern void printbinary(unsigned long x, int nbits); 84 struct siginfo si; 85 unsigned int orig_sw, sw; 86 int signalcode; 87 /* need an intermediate copy of float regs because FPU emulation 88 * code expects an artificial last entry which contains zero 89 * 90 * also, the passed in fr registers contain one word that defines 91 * the fpu type. the fpu type information is constructed 92 * inside the emulation code 93 */ 94 __u64 frcopy[36]; 95 96 memcpy(frcopy, regs->fr, sizeof regs->fr); 97 frcopy[32] = 0; 98 99 memcpy(&orig_sw, frcopy, sizeof(orig_sw)); 100 101 if (FPUDEBUG) { 102 printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n "); 103 printbinary(orig_sw, 32); 104 printk(KERN_DEBUG "\n"); 105 } 106 107 signalcode = decode_fpu(frcopy, 0x666); 108 109 /* Status word = FR0L. */ 110 memcpy(&sw, frcopy, sizeof(sw)); 111 if (FPUDEBUG) { 112 printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n", 113 signalcode >> 24, signalcode & 0xffffff); 114 printbinary(sw, 32); 115 printk(KERN_DEBUG "\n"); 116 } 117 118 memcpy(regs->fr, frcopy, sizeof regs->fr); 119 if (signalcode != 0) { 120 si.si_signo = signalcode >> 24; 121 si.si_errno = 0; 122 si.si_code = signalcode & 0xffffff; 123 si.si_addr = (void __user *) regs->iaoq[0]; 124 force_sig_info(si.si_signo, &si, current); 125 return -1; 126 } 127 128 return signalcode ? -1 : 0; 129 } 130