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