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