0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "fpa11.h"
0013
0014 #include <linux/module.h>
0015 #include <linux/moduleparam.h>
0016
0017
0018 #include <linux/errno.h>
0019 #include <linux/types.h>
0020 #include <linux/kernel.h>
0021 #include <linux/signal.h>
0022 #include <linux/sched/signal.h>
0023 #include <linux/init.h>
0024
0025 #include <asm/thread_notify.h>
0026
0027 #include "softfloat.h"
0028 #include "fpopcode.h"
0029 #include "fpmodule.h"
0030 #include "fpa11.inl"
0031
0032
0033 #ifdef CONFIG_FPE_NWFPE_XP
0034 #define NWFPE_BITS "extended"
0035 #else
0036 #define NWFPE_BITS "double"
0037 #endif
0038
0039 #ifdef MODULE
0040 void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
0041 #else
0042 #define fp_send_sig send_sig
0043 #define kern_fp_enter fp_enter
0044
0045 extern char fpe_type[];
0046 #endif
0047
0048 static int nwfpe_notify(struct notifier_block *self, unsigned long cmd, void *v)
0049 {
0050 struct thread_info *thread = v;
0051
0052 if (cmd == THREAD_NOTIFY_FLUSH)
0053 nwfpe_init_fpa(&thread->fpstate);
0054
0055 return NOTIFY_DONE;
0056 }
0057
0058 static struct notifier_block nwfpe_notifier_block = {
0059 .notifier_call = nwfpe_notify,
0060 };
0061
0062
0063 void fp_setup(void);
0064
0065
0066 extern void (*kern_fp_enter)(void);
0067
0068
0069 static void (*orig_fp_enter)(void);
0070
0071
0072 extern void nwfpe_enter(void);
0073
0074 static int __init fpe_init(void)
0075 {
0076 if (sizeof(FPA11) > sizeof(union fp_state)) {
0077 pr_err("nwfpe: bad structure size\n");
0078 return -EINVAL;
0079 }
0080
0081 if (sizeof(FPREG) != 12) {
0082 pr_err("nwfpe: bad register size\n");
0083 return -EINVAL;
0084 }
0085 if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
0086 return 0;
0087
0088
0089 pr_info("NetWinder Floating Point Emulator V0.97 ("
0090 NWFPE_BITS " precision)\n");
0091
0092 thread_register_notifier(&nwfpe_notifier_block);
0093
0094
0095 orig_fp_enter = kern_fp_enter;
0096 kern_fp_enter = nwfpe_enter;
0097
0098 return 0;
0099 }
0100
0101 static void __exit fpe_exit(void)
0102 {
0103 thread_unregister_notifier(&nwfpe_notifier_block);
0104
0105 kern_fp_enter = orig_fp_enter;
0106 }
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 #ifdef CONFIG_DEBUG_USER
0127
0128 static int debug = ~BIT_IXC;
0129 #endif
0130
0131 void float_raise(signed char flags)
0132 {
0133 register unsigned int fpsr, cumulativeTraps;
0134
0135 #ifdef CONFIG_DEBUG_USER
0136 if (flags & debug)
0137 printk(KERN_DEBUG
0138 "NWFPE: %s[%d] takes exception %08x at %ps from %08lx\n",
0139 current->comm, current->pid, flags,
0140 __builtin_return_address(0), GET_USERREG()->ARM_pc);
0141 #endif
0142
0143
0144 fpsr = readFPSR();
0145 cumulativeTraps = 0;
0146
0147
0148
0149 if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
0150 cumulativeTraps |= BIT_IXC;
0151 if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
0152 cumulativeTraps |= BIT_UFC;
0153 if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
0154 cumulativeTraps |= BIT_OFC;
0155 if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
0156 cumulativeTraps |= BIT_DZC;
0157 if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
0158 cumulativeTraps |= BIT_IOC;
0159
0160
0161 if (cumulativeTraps)
0162 writeFPSR(fpsr | cumulativeTraps);
0163
0164
0165 if (fpsr & (flags << 16))
0166 fp_send_sig(SIGFPE, current, 1);
0167 }
0168
0169 module_init(fpe_init);
0170 module_exit(fpe_exit);
0171
0172 MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
0173 MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
0174 MODULE_LICENSE("GPL");
0175
0176 #ifdef CONFIG_DEBUG_USER
0177 module_param(debug, int, 0644);
0178 #endif