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