This source file includes following definitions.
- math_emulate
- __math_abort
- math_emulate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include <linux/config.h>
27
28 #ifdef CONFIG_MATH_EMULATION
29
30 #include <linux/signal.h>
31
32 #include "fpu_system.h"
33 #include "fpu_emu.h"
34 #include "exception.h"
35 #include "control_w.h"
36
37 #include <asm/segment.h>
38
39
40 #define __BAD__ Un_impl
41
42 #ifndef NO_UNDOC_CODE
43
44
45
46
47
48
49 #define _d9_d8_ fstp_i
50 #define _dc_d0_ fcom_st
51 #define _dc_d8_ fcompst
52 #define _dd_c8_ fxch_i
53 #define _de_d0_ fcompst
54 #define _df_c0_ ffreep
55 #define _df_c8_ fxch_i
56 #define _df_d0_ fstp_i
57 #define _df_d8_ fstp_i
58
59 static FUNC st_instr_table[64] = {
60 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
61 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
62 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
63 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
64 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
65 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
66 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
67 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
68 };
69
70 #else
71
72 static FUNC st_instr_table[64] = {
73 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
74 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
75 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
76 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
77 fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
78 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
79 fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
80 fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
81 };
82
83 #endif NO_UNDOC_CODE
84
85
86 #define _NONE_ 0
87 #define _REG0_ 1
88 #define _REGI_ 2
89 #define _REGi_ 0
90 #define _PUSH_ 3
91 #define _null_ 4
92
93 #ifndef NO_UNDOC_CODE
94
95
96
97 static unsigned char type_table[64] = {
98 _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _REGi_,
99 _REGI_, _REGI_, _null_, _null_, _REGI_, _REGI_, _REGI_, _REGI_,
100 _REGI_, _NONE_, _null_, _null_, _REGI_, _REG0_, _REGI_, _REG0_,
101 _REGI_, _REG0_, _null_, _null_, _REGI_, _REG0_, _REGI_, _REG0_,
102 _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
103 _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
104 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
105 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
106 };
107
108 #else
109
110 static unsigned char type_table[64] = {
111 _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _null_,
112 _REGI_, _REGI_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
113 _REGI_, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
114 _REGI_, _null_, _null_, _null_, _null_, _REG0_, _REGI_, _null_,
115 _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
116 _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
117 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
118 _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
119 };
120
121 #endif NO_UNDOC_CODE
122
123
124
125
126 unsigned char FPU_rm;
127 char FPU_st0_tag;
128 FPU_REG *FPU_st0_ptr;
129
130 #ifdef PARANOID
131 char emulating=0;
132 #endif PARANOID
133
134 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
135
136
137 void math_emulate(long arg)
138 {
139 unsigned char FPU_modrm;
140 unsigned short code;
141
142 #ifdef PARANOID
143 if ( emulating )
144 {
145 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
146 }
147 RE_ENTRANT_CHECK_ON
148 #endif PARANOID
149
150 if (!current->used_math)
151 {
152 finit();
153 current->used_math = 1;
154 control_word = 0x037f;
155 status_word = 0x0000;
156 }
157
158 FPU_info = (struct info *) &arg;
159
160
161 if (FPU_EFLAGS & 0x00020000)
162 {
163 FPU_ORIG_EIP = FPU_EIP;
164 math_abort(FPU_info,SIGILL);
165 }
166
167
168 if (FPU_CS != 0x000f)
169 {
170 printk("math_emulate: %04x:%08x\n",FPU_CS,FPU_EIP);
171 panic("Math emulation needed in kernel");
172 }
173
174 FPU_lookahead = 1;
175 if (current->flags & PF_PTRACED)
176 FPU_lookahead = 0;
177 do_another:
178
179 FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
180
181 RE_ENTRANT_CHECK_OFF
182 code = get_fs_word((unsigned short *) FPU_EIP);
183 RE_ENTRANT_CHECK_ON
184
185 if ( (code & 0xff) == 0x66 )
186 {
187 FPU_EIP++;
188 RE_ENTRANT_CHECK_OFF
189 code = get_fs_word((unsigned short *) FPU_EIP);
190 RE_ENTRANT_CHECK_ON
191 }
192 FPU_EIP += 2;
193
194 FPU_modrm = code >> 8;
195 FPU_rm = FPU_modrm & 7;
196
197 if ( FPU_modrm < 0300 )
198 {
199
200 get_address(FPU_modrm);
201 if ( !(code & 1) )
202 {
203 switch ( (code >> 1) & 3 )
204 {
205 case 0:
206 reg_load_single();
207 break;
208 case 1:
209 reg_load_int32();
210 break;
211 case 2:
212 reg_load_double();
213 break;
214 case 3:
215 reg_load_int16();
216 break;
217 }
218
219
220
221 FPU_st0_ptr = &st(0);
222 FPU_st0_tag = FPU_st0_ptr->tag;
223 if ( NOT_EMPTY_0 )
224 {
225 switch ( (FPU_modrm >> 3) & 7 )
226 {
227 case 0:
228 reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
229 break;
230 case 1:
231 reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
232 break;
233 case 2:
234 compare_st_data();
235 goto no_precision_adjust;
236 break;
237 case 3:
238 compare_st_data();
239 pop();
240 goto no_precision_adjust;
241 break;
242 case 4:
243 reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
244 break;
245 case 5:
246 reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
247 break;
248 case 6:
249 reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
250 break;
251 case 7:
252 reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
253 break;
254 }
255 PRECISION_ADJUST(FPU_st0_ptr);
256 no_precision_adjust:
257 ;
258 }
259 else
260 stack_underflow();
261 }
262 else
263 {
264 load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
265 }
266
267 data_operand_offset = (unsigned long)FPU_data_address;
268 }
269 else
270 {
271
272 unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
273 FPU_st0_ptr = &st(0);
274 FPU_st0_tag = FPU_st0_ptr->tag;
275 switch ( type_table[(int) instr_index] )
276 {
277 case _NONE_:
278 break;
279 case _REG0_:
280 if ( !NOT_EMPTY_0 )
281 {
282 stack_underflow();
283 goto instruction_done;
284 }
285 break;
286 case _REGI_:
287 if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
288 {
289 stack_underflow();
290 goto instruction_done;
291 }
292 break;
293 case _PUSH_:
294 break;
295 case _null_:
296 Un_impl();
297 goto instruction_done;
298 default:
299 EXCEPTION(EX_INTERNAL|0x111);
300 goto instruction_done;
301 }
302 (*st_instr_table[(int) instr_index])();
303 }
304
305 instruction_done:
306
307 ip_offset = FPU_entry_eip;
308 bswapw(code);
309 *(1 + (unsigned short *)&cs_selector) = code & 0x7ff;
310
311 if (FPU_lookahead && !need_resched)
312 {
313 unsigned char next;
314 skip_fwait:
315 RE_ENTRANT_CHECK_OFF
316 next = get_fs_byte((unsigned char *) FPU_EIP);
317 RE_ENTRANT_CHECK_ON
318 test_for_fp:
319 if ( (next & 0xf8) == 0xd8 )
320 {
321 goto do_another;
322 }
323 if ( next == 0x9b )
324 { FPU_EIP++; goto skip_fwait; }
325 if ( next == 0x66 )
326 {
327 RE_ENTRANT_CHECK_OFF
328 next = get_fs_byte((unsigned char *) (FPU_EIP+1));
329 RE_ENTRANT_CHECK_ON
330 if ( (next & 0xf8) == 0xd8 )
331 goto test_for_fp;
332 }
333 }
334
335 RE_ENTRANT_CHECK_OFF
336 }
337
338
339 void __math_abort(struct info * info, unsigned int signal)
340 {
341 RE_ENTRANT_CHECK_OFF
342 FPU_EIP = FPU_ORIG_EIP;
343 send_sig(signal,current,1);
344 RE_ENTRANT_CHECK_OFF
345 __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
346 #ifdef PARANOID
347 printk("ERROR: wm-FPU-emu math_abort failed!\n");
348 #endif PARANOID
349 }
350
351 #else
352
353 #include <linux/signal.h>
354 #include <linux/sched.h>
355
356 void math_emulate(long arg)
357 {
358 printk("math-meulation not enabled and no coprocessor found.\n");
359 printk("killing %s.\n",current->comm);
360 send_sig(SIGFPE,current,1);
361 schedule();
362 }
363
364 #endif