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