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