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