|
|
1.1 root 1: /*
2: * linux/kernel/math/emulate.c
3: *
1.1.1.4 root 4: * Copyright (C) 1991, 1992 Linus Torvalds
1.1 root 5: */
6:
7: /*
8: * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
9: * even for soft-float, unless you use bruce evans' patches. The patches
10: * are great, but they have to be re-applied for every version, and the
11: * library is different for soft-float and 80387. So emulation is more
12: * practical, even though it's slower.
13: *
14: * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
15: * about add/sub/mul/div. Urgel. I should find some good source, but I'll
16: * just fake up something.
17: *
18: * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
19: * test every possible combination.
20: */
21:
22: /*
23: * This file is full of ugly macros etc: one problem was that gcc simply
24: * didn't want to make the structures as they should be: it has to try to
25: * align them. Sickening code, but at least I've hidden the ugly things
26: * in this one file: the other files don't need to know about these things.
27: *
28: * The other files also don't care about ST(x) etc - they just get addresses
29: * to 80-bit temporary reals, and do with them as they please. I wanted to
30: * hide most of the 387-specific things here.
31: */
32:
33: #ifdef KERNEL_MATH_EMULATION
34:
1.1.1.4 root 35: #include <linux/signal.h>
1.1 root 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: * We don't want these inlined - it gets too messy in the machine-code.
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;
1.1.1.5 ! root 65: /* We cannot handle emulation in v86-mode */
! 66: if (EFLAGS & 0x00020000)
! 67: math_abort(info,SIGILL);
1.1 root 68: /* 0x0007 means user code space */
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: /* fnop */
82: return;
83: case 0x1d1: case 0x1d2: case 0x1d3:
84: case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
1.1.1.3 root 85: math_abort(info,SIGILL);
1.1 root 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:
1.1.1.3 root 93: math_abort(info,SIGILL);
1.1 root 94: case 0x1e4:
95: ftst(PST(0));
96: return;
97: case 0x1e5:
98: printk("fxam not implemented\n\r");
1.1.1.3 root 99: math_abort(info,SIGILL);
1.1 root 100: case 0x1e6: case 0x1e7:
1.1.1.3 root 101: math_abort(info,SIGILL);
1.1 root 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:
1.1.1.3 root 131: math_abort(info,SIGILL);
1.1.1.2 root 132: case 0x1fa:
133: fsqrt(PST(0),&tmp);
134: real_to_real(&tmp,&ST(0));
135: return;
1.1 root 136: case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
137: case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
1.1.1.2 root 138: case 0x1f8: case 0x1f9: case 0x1fb: case 0x1fd:
139: case 0x1fe: case 0x1ff:
1.1 root 140: printk("%04x fxxx not implemented\n\r",code + 0xd800);
1.1.1.3 root 141: math_abort(info,SIGILL);
1.1 root 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");
1.1.1.3 root 252: math_abort(info,SIGILL);
1.1 root 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");
1.1.1.3 root 309: math_abort(info,SIGILL);
1.1 root 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);
1.1.1.3 root 484: math_abort(info,SIGFPE);
1.1 root 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;
1.1.1.3 root 501: send_sig(signal,current,1);
1.1 root 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 /* no math emulation */
542:
1.1.1.4 root 543: #include <linux/signal.h>
1.1 root 544: #include <linux/sched.h>
545:
546: void math_emulate(long ___false)
547: {
1.1.1.3 root 548: send_sig(SIGFPE,current,1);
1.1 root 549: schedule();
550: }
551:
552: #endif /* KERNEL_MATH_EMULATION */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.