xref: /linux/arch/arm/nwfpe/fpmodule.c (revision 20d0021394c1b070bf04b22c5bc8fdb437edd4c5)
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/config.h>
28 
29 /* XXX */
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 /* XXX */
37 
38 #include "softfloat.h"
39 #include "fpopcode.h"
40 #include "fpmodule.h"
41 #include "fpa11.inl"
42 
43 /* kernel symbols required for signal handling */
44 #ifdef CONFIG_FPE_NWFPE_XP
45 #define NWFPE_BITS "extended"
46 #else
47 #define NWFPE_BITS "double"
48 #endif
49 
50 #ifdef MODULE
51 void 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 
56 extern char fpe_type[];
57 #endif
58 
59 /* kernel function prototypes required */
60 void fp_setup(void);
61 
62 /* external declarations for saved kernel symbols */
63 extern void (*kern_fp_enter)(void);
64 extern void (*fp_init)(union fp_state *);
65 
66 /* Original value of fp_enter from kernel before patched by fpe_init. */
67 static void (*orig_fp_enter)(void);
68 static void (*orig_fp_init)(union fp_state *);
69 
70 /* forward declarations */
71 extern void nwfpe_enter(void);
72 
73 static int __init fpe_init(void)
74 {
75 	if (sizeof(FPA11) > sizeof(union fp_state)) {
76 		printk(KERN_ERR "nwfpe: bad structure size\n");
77 		return -EINVAL;
78 	}
79 
80 	if (sizeof(FPREG) != 12) {
81 		printk(KERN_ERR "nwfpe: bad register size\n");
82 		return -EINVAL;
83 	}
84 	if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
85 		return 0;
86 
87 	/* Display title, version and copyright information. */
88 	printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 ("
89 	       NWFPE_BITS " precision)\n");
90 
91 	/* Save pointer to the old FP handler and then patch ourselves in */
92 	orig_fp_enter = kern_fp_enter;
93 	orig_fp_init = fp_init;
94 	kern_fp_enter = nwfpe_enter;
95 	fp_init = nwfpe_init_fpa;
96 
97 	return 0;
98 }
99 
100 static void __exit fpe_exit(void)
101 {
102 	/* Restore the values we saved earlier. */
103 	kern_fp_enter = orig_fp_enter;
104 	fp_init = orig_fp_init;
105 }
106 
107 /*
108 ScottB:  November 4, 1998
109 
110 Moved this function out of softfloat-specialize into fpmodule.c.
111 This effectively isolates all the changes required for integrating with the
112 Linux kernel into fpmodule.c.  Porting to NetBSD should only require modifying
113 fpmodule.c to integrate with the NetBSD kernel (I hope!).
114 
115 [1/1/99: Not quite true any more unfortunately.  There is Linux-specific
116 code to access data in user space in some other source files at the
117 moment (grep for get_user / put_user calls).  --philb]
118 
119 float_exception_flags is a global variable in SoftFloat.
120 
121 This function is called by the SoftFloat routines to raise a floating
122 point exception.  We check the trap enable byte in the FPSR, and raise
123 a SIGFPE exception if necessary.  If not the relevant bits in the
124 cumulative exceptions flag byte are set and we return.
125 */
126 
127 void float_raise(signed char flags)
128 {
129 	register unsigned int fpsr, cumulativeTraps;
130 
131 #ifdef CONFIG_DEBUG_USER
132 	printk(KERN_DEBUG
133 	       "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",
134 	       current->comm, current->pid, flags,
135 	       __builtin_return_address(0), GET_USERREG()[15]);
136 #endif
137 
138 	/* Keep SoftFloat exception flags up to date.  */
139 	float_exception_flags |= flags;
140 
141 	/* Read fpsr and initialize the cumulativeTraps.  */
142 	fpsr = readFPSR();
143 	cumulativeTraps = 0;
144 
145 	/* For each type of exception, the cumulative trap exception bit is only
146 	   set if the corresponding trap enable bit is not set.  */
147 	if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
148 		cumulativeTraps |= BIT_IXC;
149 	if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
150 		cumulativeTraps |= BIT_UFC;
151 	if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
152 		cumulativeTraps |= BIT_OFC;
153 	if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
154 		cumulativeTraps |= BIT_DZC;
155 	if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
156 		cumulativeTraps |= BIT_IOC;
157 
158 	/* Set the cumulative exceptions flags.  */
159 	if (cumulativeTraps)
160 		writeFPSR(fpsr | cumulativeTraps);
161 
162 	/* Raise an exception if necessary.  */
163 	if (fpsr & (flags << 16))
164 		fp_send_sig(SIGFPE, current, 1);
165 }
166 
167 module_init(fpe_init);
168 module_exit(fpe_exit);
169 
170 MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
171 MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
172 MODULE_LICENSE("GPL");
173