This source file includes following definitions.
- do_emu
- math_emulate
- __math_abort
- fpop
- fpush
- fxchg
- __st
- 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
27
28
29
30
31
32
33 #ifdef KERNEL_MATH_EMULATION
34
35 #include <signal.h>
36
37 #define __ALIGNED_TEMP_REAL 1
38 #include <linux/math_emu.h>
39 #include <linux/kernel.h>
40 #include <asm/segment.h>
41
42 #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
43 #define ST(x) (*__st((x)))
44 #define PST(x) ((const temp_real *) __st((x)))
45
46
47
48
49 static void fpop(void);
50 static void fpush(void);
51 static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
52 static temp_real_unaligned * __st(int i);
53
54 static void do_emu(struct info * info)
55 {
56 unsigned short code;
57 temp_real tmp;
58 char * address;
59
60 if (I387.cwd & I387.swd & 0x3f)
61 I387.swd |= 0x8000;
62 else
63 I387.swd &= 0x7fff;
64 ORIG_EIP = EIP;
65
66 if (CS != 0x000F) {
67 printk("math_emulate: %04x:%08x\n\r",CS,EIP);
68 panic("Math emulation needed in kernel");
69 }
70 code = get_fs_word((unsigned short *) EIP);
71 bswapw(code);
72 code &= 0x7ff;
73 I387.fip = EIP;
74 *(unsigned short *) &I387.fcs = CS;
75 *(1+(unsigned short *) &I387.fcs) = code;
76 EIP += 2;
77 switch (code) {
78 case 0x1d0:
79 return;
80 case 0x1d1: case 0x1d2: case 0x1d3:
81 case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
82 math_abort(info,1<<(SIGILL-1));
83 case 0x1e0:
84 ST(0).exponent ^= 0x8000;
85 return;
86 case 0x1e1:
87 ST(0).exponent &= 0x7fff;
88 return;
89 case 0x1e2: case 0x1e3:
90 math_abort(info,1<<(SIGILL-1));
91 case 0x1e4:
92 ftst(PST(0));
93 return;
94 case 0x1e5:
95 printk("fxam not implemented\n\r");
96 math_abort(info,1<<(SIGILL-1));
97 case 0x1e6: case 0x1e7:
98 math_abort(info,1<<(SIGILL-1));
99 case 0x1e8:
100 fpush();
101 ST(0) = CONST1;
102 return;
103 case 0x1e9:
104 fpush();
105 ST(0) = CONSTL2T;
106 return;
107 case 0x1ea:
108 fpush();
109 ST(0) = CONSTL2E;
110 return;
111 case 0x1eb:
112 fpush();
113 ST(0) = CONSTPI;
114 return;
115 case 0x1ec:
116 fpush();
117 ST(0) = CONSTLG2;
118 return;
119 case 0x1ed:
120 fpush();
121 ST(0) = CONSTLN2;
122 return;
123 case 0x1ee:
124 fpush();
125 ST(0) = CONSTZ;
126 return;
127 case 0x1ef:
128 math_abort(info,1<<(SIGILL-1));
129 case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
130 case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
131 case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
132 case 0x1fd: case 0x1fe: case 0x1ff:
133 printk("%04x fxxx not implemented\n\r",code + 0xd800);
134 math_abort(info,1<<(SIGILL-1));
135 case 0x1fc:
136 frndint(PST(0),&tmp);
137 real_to_real(&tmp,&ST(0));
138 return;
139 case 0x2e9:
140 fucom(PST(1),PST(0));
141 fpop(); fpop();
142 return;
143 case 0x3d0: case 0x3d1:
144 return;
145 case 0x3e2:
146 I387.swd &= 0x7f00;
147 return;
148 case 0x3e3:
149 I387.cwd = 0x037f;
150 I387.swd = 0x0000;
151 I387.twd = 0x0000;
152 return;
153 case 0x3e4:
154 return;
155 case 0x6d9:
156 fcom(PST(1),PST(0));
157 fpop(); fpop();
158 return;
159 case 0x7e0:
160 *(short *) &EAX = I387.swd;
161 return;
162 }
163 switch (code >> 3) {
164 case 0x18:
165 fadd(PST(0),PST(code & 7),&tmp);
166 real_to_real(&tmp,&ST(0));
167 return;
168 case 0x19:
169 fmul(PST(0),PST(code & 7),&tmp);
170 real_to_real(&tmp,&ST(0));
171 return;
172 case 0x1a:
173 fcom(PST(code & 7),PST(0));
174 return;
175 case 0x1b:
176 fcom(PST(code & 7),PST(0));
177 fpop();
178 return;
179 case 0x1c:
180 real_to_real(&ST(code & 7),&tmp);
181 tmp.exponent ^= 0x8000;
182 fadd(PST(0),&tmp,&tmp);
183 real_to_real(&tmp,&ST(0));
184 return;
185 case 0x1d:
186 ST(0).exponent ^= 0x8000;
187 fadd(PST(0),PST(code & 7),&tmp);
188 real_to_real(&tmp,&ST(0));
189 return;
190 case 0x1e:
191 fdiv(PST(0),PST(code & 7),&tmp);
192 real_to_real(&tmp,&ST(0));
193 return;
194 case 0x1f:
195 fdiv(PST(code & 7),PST(0),&tmp);
196 real_to_real(&tmp,&ST(0));
197 return;
198 case 0x38:
199 fpush();
200 ST(0) = ST((code+1) & 7);
201 return;
202 case 0x39:
203 fxchg(&ST(0),&ST(code & 7));
204 return;
205 case 0x3b:
206 ST(code & 7) = ST(0);
207 fpop();
208 return;
209 case 0x98:
210 fadd(PST(0),PST(code & 7),&tmp);
211 real_to_real(&tmp,&ST(code & 7));
212 return;
213 case 0x99:
214 fmul(PST(0),PST(code & 7),&tmp);
215 real_to_real(&tmp,&ST(code & 7));
216 return;
217 case 0x9a:
218 fcom(PST(code & 7),PST(0));
219 return;
220 case 0x9b:
221 fcom(PST(code & 7),PST(0));
222 fpop();
223 return;
224 case 0x9c:
225 ST(code & 7).exponent ^= 0x8000;
226 fadd(PST(0),PST(code & 7),&tmp);
227 real_to_real(&tmp,&ST(code & 7));
228 return;
229 case 0x9d:
230 real_to_real(&ST(0),&tmp);
231 tmp.exponent ^= 0x8000;
232 fadd(PST(code & 7),&tmp,&tmp);
233 real_to_real(&tmp,&ST(code & 7));
234 return;
235 case 0x9e:
236 fdiv(PST(0),PST(code & 7),&tmp);
237 real_to_real(&tmp,&ST(code & 7));
238 return;
239 case 0x9f:
240 fdiv(PST(code & 7),PST(0),&tmp);
241 real_to_real(&tmp,&ST(code & 7));
242 return;
243 case 0xb8:
244 printk("ffree not implemented\n\r");
245 math_abort(info,1<<(SIGILL-1));
246 case 0xb9:
247 fxchg(&ST(0),&ST(code & 7));
248 return;
249 case 0xba:
250 ST(code & 7) = ST(0);
251 return;
252 case 0xbb:
253 ST(code & 7) = ST(0);
254 fpop();
255 return;
256 case 0xbc:
257 fucom(PST(code & 7),PST(0));
258 return;
259 case 0xbd:
260 fucom(PST(code & 7),PST(0));
261 fpop();
262 return;
263 case 0xd8:
264 fadd(PST(code & 7),PST(0),&tmp);
265 real_to_real(&tmp,&ST(code & 7));
266 fpop();
267 return;
268 case 0xd9:
269 fmul(PST(code & 7),PST(0),&tmp);
270 real_to_real(&tmp,&ST(code & 7));
271 fpop();
272 return;
273 case 0xda:
274 fcom(PST(code & 7),PST(0));
275 fpop();
276 return;
277 case 0xdc:
278 ST(code & 7).exponent ^= 0x8000;
279 fadd(PST(0),PST(code & 7),&tmp);
280 real_to_real(&tmp,&ST(code & 7));
281 fpop();
282 return;
283 case 0xdd:
284 real_to_real(&ST(0),&tmp);
285 tmp.exponent ^= 0x8000;
286 fadd(PST(code & 7),&tmp,&tmp);
287 real_to_real(&tmp,&ST(code & 7));
288 fpop();
289 return;
290 case 0xde:
291 fdiv(PST(0),PST(code & 7),&tmp);
292 real_to_real(&tmp,&ST(code & 7));
293 fpop();
294 return;
295 case 0xdf:
296 fdiv(PST(code & 7),PST(0),&tmp);
297 real_to_real(&tmp,&ST(code & 7));
298 fpop();
299 return;
300 case 0xf8:
301 printk("ffree not implemented\n\r");
302 math_abort(info,1<<(SIGILL-1));
303 fpop();
304 return;
305 case 0xf9:
306 fxchg(&ST(0),&ST(code & 7));
307 return;
308 case 0xfa:
309 case 0xfb:
310 ST(code & 7) = ST(0);
311 fpop();
312 return;
313 }
314 switch ((code>>3) & 0xe7) {
315 case 0x22:
316 put_short_real(PST(0),info,code);
317 return;
318 case 0x23:
319 put_short_real(PST(0),info,code);
320 fpop();
321 return;
322 case 0x24:
323 address = ea(info,code);
324 for (code = 0 ; code < 7 ; code++) {
325 ((long *) & I387)[code] =
326 get_fs_long((unsigned long *) address);
327 address += 4;
328 }
329 return;
330 case 0x25:
331 address = ea(info,code);
332 *(unsigned short *) &I387.cwd =
333 get_fs_word((unsigned short *) address);
334 return;
335 case 0x26:
336 address = ea(info,code);
337 verify_area(address,28);
338 for (code = 0 ; code < 7 ; code++) {
339 put_fs_long( ((long *) & I387)[code],
340 (unsigned long *) address);
341 address += 4;
342 }
343 return;
344 case 0x27:
345 address = ea(info,code);
346 verify_area(address,2);
347 put_fs_word(I387.cwd,(short *) address);
348 return;
349 case 0x62:
350 put_long_int(PST(0),info,code);
351 return;
352 case 0x63:
353 put_long_int(PST(0),info,code);
354 fpop();
355 return;
356 case 0x65:
357 fpush();
358 get_temp_real(&tmp,info,code);
359 real_to_real(&tmp,&ST(0));
360 return;
361 case 0x67:
362 put_temp_real(PST(0),info,code);
363 fpop();
364 return;
365 case 0xa2:
366 put_long_real(PST(0),info,code);
367 return;
368 case 0xa3:
369 put_long_real(PST(0),info,code);
370 fpop();
371 return;
372 case 0xa4:
373 address = ea(info,code);
374 for (code = 0 ; code < 27 ; code++) {
375 ((long *) & I387)[code] =
376 get_fs_long((unsigned long *) address);
377 address += 4;
378 }
379 return;
380 case 0xa6:
381 address = ea(info,code);
382 verify_area(address,108);
383 for (code = 0 ; code < 27 ; code++) {
384 put_fs_long( ((long *) & I387)[code],
385 (unsigned long *) address);
386 address += 4;
387 }
388 I387.cwd = 0x037f;
389 I387.swd = 0x0000;
390 I387.twd = 0x0000;
391 return;
392 case 0xa7:
393 address = ea(info,code);
394 verify_area(address,2);
395 put_fs_word(I387.swd,(short *) address);
396 return;
397 case 0xe2:
398 put_short_int(PST(0),info,code);
399 return;
400 case 0xe3:
401 put_short_int(PST(0),info,code);
402 fpop();
403 return;
404 case 0xe4:
405 fpush();
406 get_BCD(&tmp,info,code);
407 real_to_real(&tmp,&ST(0));
408 return;
409 case 0xe5:
410 fpush();
411 get_longlong_int(&tmp,info,code);
412 real_to_real(&tmp,&ST(0));
413 return;
414 case 0xe6:
415 put_BCD(PST(0),info,code);
416 fpop();
417 return;
418 case 0xe7:
419 put_longlong_int(PST(0),info,code);
420 fpop();
421 return;
422 }
423 switch (code >> 9) {
424 case 0:
425 get_short_real(&tmp,info,code);
426 break;
427 case 1:
428 get_long_int(&tmp,info,code);
429 break;
430 case 2:
431 get_long_real(&tmp,info,code);
432 break;
433 case 4:
434 get_short_int(&tmp,info,code);
435 }
436 switch ((code>>3) & 0x27) {
437 case 0:
438 fadd(&tmp,PST(0),&tmp);
439 real_to_real(&tmp,&ST(0));
440 return;
441 case 1:
442 fmul(&tmp,PST(0),&tmp);
443 real_to_real(&tmp,&ST(0));
444 return;
445 case 2:
446 fcom(&tmp,PST(0));
447 return;
448 case 3:
449 fcom(&tmp,PST(0));
450 fpop();
451 return;
452 case 4:
453 tmp.exponent ^= 0x8000;
454 fadd(&tmp,PST(0),&tmp);
455 real_to_real(&tmp,&ST(0));
456 return;
457 case 5:
458 ST(0).exponent ^= 0x8000;
459 fadd(&tmp,PST(0),&tmp);
460 real_to_real(&tmp,&ST(0));
461 return;
462 case 6:
463 fdiv(PST(0),&tmp,&tmp);
464 real_to_real(&tmp,&ST(0));
465 return;
466 case 7:
467 fdiv(&tmp,PST(0),&tmp);
468 real_to_real(&tmp,&ST(0));
469 return;
470 }
471 if ((code & 0x138) == 0x100) {
472 fpush();
473 real_to_real(&tmp,&ST(0));
474 return;
475 }
476 printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code);
477 math_abort(info,1<<(SIGFPE-1));
478 }
479
480 void math_emulate(long ___false)
481 {
482 if (!current->used_math) {
483 current->used_math = 1;
484 I387.cwd = 0x037f;
485 I387.swd = 0x0000;
486 I387.twd = 0x0000;
487 }
488 do_emu((struct info *) &___false);
489 }
490
491 void __math_abort(struct info * info, unsigned int signal)
492 {
493 EIP = ORIG_EIP;
494 current->signal |= signal;
495 __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
496 }
497
498 static void fpop(void)
499 {
500 unsigned long tmp;
501
502 tmp = I387.swd & 0xffffc7ff;
503 I387.swd += 0x00000800;
504 I387.swd &= 0x00003800;
505 I387.swd |= tmp;
506 }
507
508 static void fpush(void)
509 {
510 unsigned long tmp;
511
512 tmp = I387.swd & 0xffffc7ff;
513 I387.swd += 0x00003800;
514 I387.swd &= 0x00003800;
515 I387.swd |= tmp;
516 }
517
518 static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
519 {
520 temp_real_unaligned c;
521
522 c = *a;
523 *a = *b;
524 *b = c;
525 }
526
527 static temp_real_unaligned * __st(int i)
528 {
529 i += I387.swd >> 11;
530 i &= 7;
531 return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
532 }
533
534 #else
535
536 #include <signal.h>
537 #include <linux/sched.h>
538
539 void math_emulate(long ___false)
540 {
541 current->signal |= 1<<(SIGFPE-1);
542 schedule();
543 }
544
545 #endif