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