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