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