1 2/* 3 NetWinder Floating Point Emulator 4 (c) Rebel.com, 1998-1999 5 (c) Philip Blundell, 1998-1999 6 7 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22*/ 23 24#include "fpa11.h" 25 26#include <linux/module.h> 27#include <linux/version.h> 28#include <linux/config.h> 29 30#include <linux/types.h> 31#include <linux/kernel.h> 32#include <linux/signal.h> 33#include <linux/sched.h> 34#include <linux/init.h> 35 36#include "softfloat.h" 37#include "fpopcode.h" 38#include "fpmodule.h" 39#include "fpa11.inl" 40 41/* kernel symbols required for signal handling */ 42typedef struct task_struct* PTASK; 43 44#ifdef MODULE 45void fp_send_sig(unsigned long sig, PTASK p, int priv); 46#if LINUX_VERSION_CODE > 0x20115 47MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>"); 48MODULE_DESCRIPTION("NWFPE floating point emulator"); 49#endif 50 51#else 52#define fp_send_sig send_sig 53#define kern_fp_enter fp_enter 54 55extern char fpe_type[]; 56#endif 57 58/* kernel function prototypes required */ 59void fp_setup(void); 60 61/* external declarations for saved kernel symbols */ 62extern void (*kern_fp_enter)(void); 63 64/* Original value of fp_enter from kernel before patched by fpe_init. */ 65static void (*orig_fp_enter)(void); 66 67/* forward declarations */ 68extern void nwfpe_enter(void); 69 70#ifdef MODULE 71/* 72 * Return 0 if we can be unloaded. This can only happen if 73 * kern_fp_enter is still pointing at nwfpe_enter 74 */ 75static int fpe_unload(void) 76{ 77 return (kern_fp_enter == nwfpe_enter) ? 0 : 1; 78} 79#endif 80 81static int __init fpe_init(void) 82{ 83 if (sizeof(FPA11) > sizeof(union fp_state)) { 84 printk(KERN_ERR "nwfpe: bad structure size\n"); 85 return -EINVAL; 86 } 87 88 if (sizeof(FPREG) != 12) { 89 printk(KERN_ERR "nwfpe: bad register size\n"); 90 return -EINVAL; 91 } 92 93#ifdef MODULE 94 if (!mod_member_present(&__this_module, can_unload)) 95 return -EINVAL; 96 __this_module.can_unload = fpe_unload; 97#else 98 if (fpe_type[0] && strcmp(fpe_type, "nwfpe")) 99 return 0; 100#endif 101 102 /* Display title, version and copyright information. */ 103 printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " 104 "(c) 1998-1999 Rebel.com\n"); 105 106 /* Save pointer to the old FP handler and then patch ourselves in */ 107 orig_fp_enter = kern_fp_enter; 108 kern_fp_enter = nwfpe_enter; 109 110 return 0; 111} 112 113static void __exit fpe_exit(void) 114{ 115 /* Restore the values we saved earlier. */ 116 kern_fp_enter = orig_fp_enter; 117} 118 119/* 120ScottB: November 4, 1998 121 122Moved this function out of softfloat-specialize into fpmodule.c. 123This effectively isolates all the changes required for integrating with the 124Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying 125fpmodule.c to integrate with the NetBSD kernel (I hope!). 126 127[1/1/99: Not quite true any more unfortunately. There is Linux-specific 128code to access data in user space in some other source files at the 129moment (grep for get_user / put_user calls). --philb] 130 131float_exception_flags is a global variable in SoftFloat. 132 133This function is called by the SoftFloat routines to raise a floating 134point exception. We check the trap enable byte in the FPSR, and raise 135a SIGFPE exception if necessary. If not the relevant bits in the 136cumulative exceptions flag byte are set and we return. 137*/ 138 139void float_raise(signed char flags) 140{ 141 register unsigned int fpsr, cumulativeTraps; 142 143#ifdef CONFIG_DEBUG_USER 144 printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", 145 current->comm, current->pid, flags, 146 __builtin_return_address(0), GET_USERREG()[15]); 147#endif 148 149 /* Keep SoftFloat exception flags up to date. */ 150 float_exception_flags |= flags; 151 152 /* Read fpsr and initialize the cumulativeTraps. */ 153 fpsr = readFPSR(); 154 cumulativeTraps = 0; 155 156 /* For each type of exception, the cumulative trap exception bit is only 157 set if the corresponding trap enable bit is not set. */ 158 if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) 159 cumulativeTraps |= BIT_IXC; 160 if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) 161 cumulativeTraps |= BIT_UFC; 162 if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) 163 cumulativeTraps |= BIT_OFC; 164 if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) 165 cumulativeTraps |= BIT_DZC; 166 if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) 167 cumulativeTraps |= BIT_IOC; 168 169 /* Set the cumulative exceptions flags. */ 170 if (cumulativeTraps) 171 writeFPSR(fpsr | cumulativeTraps); 172 173 /* Raise an exception if necessary. */ 174 if (fpsr & (flags << 16)) 175 fp_send_sig(SIGFPE, current, 1); 176} 177 178module_init(fpe_init); 179module_exit(fpe_exit); 180