1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "fpa11.h"
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28
29
30#include <linux/errno.h>
31#include <linux/types.h>
32#include <linux/kernel.h>
33#include <linux/signal.h>
34#include <linux/sched.h>
35#include <linux/init.h>
36
37#include <asm/thread_notify.h>
38
39#include "softfloat.h"
40#include "fpopcode.h"
41#include "fpmodule.h"
42#include "fpa11.inl"
43
44
45#ifdef CONFIG_FPE_NWFPE_XP
46#define NWFPE_BITS "extended"
47#else
48#define NWFPE_BITS "double"
49#endif
50
51#ifdef MODULE
52void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
53#else
54#define fp_send_sig send_sig
55#define kern_fp_enter fp_enter
56
57extern char fpe_type[];
58#endif
59
60static int nwfpe_notify(struct notifier_block *self, unsigned long cmd, void *v)
61{
62 struct thread_info *thread = v;
63
64 if (cmd == THREAD_NOTIFY_FLUSH)
65 nwfpe_init_fpa(&thread->fpstate);
66
67 return NOTIFY_DONE;
68}
69
70static struct notifier_block nwfpe_notifier_block = {
71 .notifier_call = nwfpe_notify,
72};
73
74
75void fp_setup(void);
76
77
78extern void (*kern_fp_enter)(void);
79
80
81static void (*orig_fp_enter)(void);
82
83
84extern void nwfpe_enter(void);
85
86static int __init fpe_init(void)
87{
88 if (sizeof(FPA11) > sizeof(union fp_state)) {
89 printk(KERN_ERR "nwfpe: bad structure size\n");
90 return -EINVAL;
91 }
92
93 if (sizeof(FPREG) != 12) {
94 printk(KERN_ERR "nwfpe: bad register size\n");
95 return -EINVAL;
96 }
97 if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
98 return 0;
99
100
101 printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 ("
102 NWFPE_BITS " precision)\n");
103
104 thread_register_notifier(&nwfpe_notifier_block);
105
106
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 thread_unregister_notifier(&nwfpe_notifier_block);
116
117 kern_fp_enter = orig_fp_enter;
118}
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138#ifdef CONFIG_DEBUG_USER
139
140static int debug = ~BIT_IXC;
141#endif
142
143void float_raise(signed char flags)
144{
145 register unsigned int fpsr, cumulativeTraps;
146
147#ifdef CONFIG_DEBUG_USER
148 if (flags & debug)
149 printk(KERN_DEBUG
150 "NWFPE: %s[%d] takes exception %08x at %pf from %08lx\n",
151 current->comm, current->pid, flags,
152 __builtin_return_address(0), GET_USERREG()->ARM_pc);
153#endif
154
155
156 fpsr = readFPSR();
157 cumulativeTraps = 0;
158
159
160
161 if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
162 cumulativeTraps |= BIT_IXC;
163 if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
164 cumulativeTraps |= BIT_UFC;
165 if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
166 cumulativeTraps |= BIT_OFC;
167 if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
168 cumulativeTraps |= BIT_DZC;
169 if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
170 cumulativeTraps |= BIT_IOC;
171
172
173 if (cumulativeTraps)
174 writeFPSR(fpsr | cumulativeTraps);
175
176
177 if (fpsr & (flags << 16))
178 fp_send_sig(SIGFPE, current, 1);
179}
180
181module_init(fpe_init);
182module_exit(fpe_exit);
183
184MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
185MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
186MODULE_LICENSE("GPL");
187
188#ifdef CONFIG_DEBUG_USER
189module_param(debug, int, 0644);
190#endif
191