| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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.h> | 
|  | 31 | #include "float.h" | 
|  | 32 | #include "math-emu.h" | 
|  | 33 |  | 
|  | 34 |  | 
|  | 35 | #define fptpos 31 | 
|  | 36 | #define fpr1pos 10 | 
|  | 37 | #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) | 
|  | 38 |  | 
|  | 39 | #define FPUDEBUG 0 | 
|  | 40 |  | 
|  | 41 | /* Format of the floating-point exception registers. */ | 
|  | 42 | struct exc_reg { | 
|  | 43 | unsigned int exception : 6; | 
|  | 44 | unsigned int ei : 26; | 
|  | 45 | }; | 
|  | 46 |  | 
|  | 47 | /* Macros for grabbing bits of the instruction format from the 'ei' | 
|  | 48 | field above. */ | 
|  | 49 | /* Major opcode 0c and 0e */ | 
|  | 50 | #define FP0CE_UID(i) (((i) >> 6) & 3) | 
|  | 51 | #define FP0CE_CLASS(i) (((i) >> 9) & 3) | 
|  | 52 | #define FP0CE_SUBOP(i) (((i) >> 13) & 7) | 
|  | 53 | #define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */ | 
|  | 54 | #define FP0C_FORMAT(i) (((i) >> 11) & 3) | 
|  | 55 | #define FP0E_FORMAT(i) (((i) >> 11) & 1) | 
|  | 56 |  | 
|  | 57 | /* Major opcode 0c, uid 2 (performance monitoring) */ | 
|  | 58 | #define FPPM_SUBOP(i) (((i) >> 9) & 0x1f) | 
|  | 59 |  | 
|  | 60 | /* Major opcode 2e (fused operations).   */ | 
|  | 61 | #define FP2E_SUBOP(i)  (((i) >> 5) & 1) | 
|  | 62 | #define FP2E_FORMAT(i) (((i) >> 11) & 1) | 
|  | 63 |  | 
|  | 64 | /* Major opcode 26 (FMPYSUB) */ | 
|  | 65 | /* Major opcode 06 (FMPYADD) */ | 
|  | 66 | #define FPx6_FORMAT(i) ((i) & 0x1f) | 
|  | 67 |  | 
|  | 68 | /* Flags and enable bits of the status word. */ | 
|  | 69 | #define FPSW_FLAGS(w) ((w) >> 27) | 
|  | 70 | #define FPSW_ENABLE(w) ((w) & 0x1f) | 
|  | 71 | #define FPSW_V (1<<4) | 
|  | 72 | #define FPSW_Z (1<<3) | 
|  | 73 | #define FPSW_O (1<<2) | 
|  | 74 | #define FPSW_U (1<<1) | 
|  | 75 | #define FPSW_I (1<<0) | 
|  | 76 |  | 
|  | 77 | /* Handle a floating point exception.  Return zero if the faulting | 
|  | 78 | instruction can be completed successfully. */ | 
|  | 79 | int | 
|  | 80 | handle_fpe(struct pt_regs *regs) | 
|  | 81 | { | 
|  | 82 | extern void printbinary(unsigned long x, int nbits); | 
|  | 83 | struct siginfo si; | 
|  | 84 | unsigned int orig_sw, sw; | 
|  | 85 | int signalcode; | 
|  | 86 | /* need an intermediate copy of float regs because FPU emulation | 
|  | 87 | * code expects an artificial last entry which contains zero | 
|  | 88 | * | 
|  | 89 | * also, the passed in fr registers contain one word that defines | 
|  | 90 | * the fpu type. the fpu type information is constructed | 
|  | 91 | * inside the emulation code | 
|  | 92 | */ | 
|  | 93 | __u64 frcopy[36]; | 
|  | 94 |  | 
|  | 95 | memcpy(frcopy, regs->fr, sizeof regs->fr); | 
|  | 96 | frcopy[32] = 0; | 
|  | 97 |  | 
|  | 98 | memcpy(&orig_sw, frcopy, sizeof(orig_sw)); | 
|  | 99 |  | 
|  | 100 | if (FPUDEBUG) { | 
|  | 101 | printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n   "); | 
|  | 102 | printbinary(orig_sw, 32); | 
|  | 103 | printk(KERN_DEBUG "\n"); | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | signalcode = decode_fpu(frcopy, 0x666); | 
|  | 107 |  | 
|  | 108 | /* Status word = FR0L. */ | 
|  | 109 | memcpy(&sw, frcopy, sizeof(sw)); | 
|  | 110 | if (FPUDEBUG) { | 
|  | 111 | printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n", | 
|  | 112 | signalcode >> 24, signalcode & 0xffffff); | 
|  | 113 | printbinary(sw, 32); | 
|  | 114 | printk(KERN_DEBUG "\n"); | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | memcpy(regs->fr, frcopy, sizeof regs->fr); | 
|  | 118 | if (signalcode != 0) { | 
|  | 119 | si.si_signo = signalcode >> 24; | 
|  | 120 | si.si_errno = 0; | 
|  | 121 | si.si_code = signalcode & 0xffffff; | 
|  | 122 | si.si_addr = (void __user *) regs->iaoq[0]; | 
|  | 123 | force_sig_info(si.si_signo, &si, current); | 
|  | 124 | return -1; | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | return signalcode ? -1 : 0; | 
|  | 128 | } |