|
|
1.1 root 1: /*---------------------------------------------------------------------------+
2: | fpu_entry.c |
3: | |
4: | The entry function for wm-FPU-emu |
5: | |
6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
7: | Australia. E-mail [email protected] |
8: | |
9: | See the files "README" and "COPYING" for further copyright and warranty |
10: | information. |
11: | |
12: +---------------------------------------------------------------------------*/
13:
14: /*---------------------------------------------------------------------------+
15: | Note: |
16: | The file contains code which accesses user memory. |
17: | Emulator static data may change when user memory is accessed, due to |
18: | other processes using the emulator while swapping is in progress. |
19: +---------------------------------------------------------------------------*/
20:
21: /*---------------------------------------------------------------------------+
22: | math_emulate() is the sole entry point for wm-FPU-emu |
23: +---------------------------------------------------------------------------*/
24:
25: #ifdef KERNEL_MATH_EMULATION
26:
27: #include <linux/signal.h>
28:
29: #include "fpu_system.h"
30: #include "fpu_emu.h"
31: #include "exception.h"
32:
33: #include <asm/segment.h>
34:
35: #ifdef COHERENT
36: struct _fpstackframe *emCurrent;
37: struct _fpemstate *FPU_info;
38: #endif
39:
40: #define __BAD__ Un_impl /* Not implemented */
41:
42: static FUNC st_instr_table[64] = {
43: fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
44: fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
45: fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
46: fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
47: fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
48: fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
49: fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
50: fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
51: };
52:
53: #define _NONE_ 0 /* Take no special action */
54: #define _REG0_ 1 /* Need to check for not empty st(0) */
55: #define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
56: #define _REGi_ 0 /* Uses st(rm) */
57: #define _PUSH_ 3 /* Need to check for space to push onto stack */
58: #define _null_ 4 /* Function illegal or not implemented */
59:
60: static unsigned char type_table[64] = {
61: _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _null_,
62: _REGI_, _REGI_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
63: _REGI_, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
64: _REGI_, _null_, _null_, _null_, _null_, _REG0_, _REGI_, _null_,
65: _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
66: _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
67: _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
68: _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
69: };
70:
71:
72: /* Be careful when using any of these global variables...
73: they might change if swapping is triggered */
74: unsigned char FPU_rm;
75: char FPU_st0_tag;
76: FPU_REG *FPU_st0_ptr;
77:
78: #ifdef PARANOID
79: char emulating=0;
80: #endif PARANOID
81:
82: #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
83:
84: #if COHERENT
85: /* Special kernel routines to pack and unpack emulator to normal */
86: void kfsave(struct _fpemstate *fpem, struct _fpstate *fp)
87: {
88: FPU_info = fpem;
89: FPU_data_address = (void *)fp;
90: fsave();
91: }
92:
93: void kfrstor(struct _fpstate *fp, struct _fpemstate *fpem)
94: {
95: FPU_info = fpem;
96: FPU_data_address = (void *)fp;
97: frstor();
98: }
99:
100: void math_emulate(long *saveRegs, struct _fpemstate *fpem, int looker)
101: {
102: unsigned char FPU_modrm;
103: unsigned short code;
104:
105: emCurrent = (struct _fpstackframe *)(saveRegs - 1);
106: FPU_info = fpem;
107:
108: FPU_lookahead = looker;
109: #else
110: void math_emulate(long arg)
111: {
112: unsigned char FPU_modrm;
113: unsigned short code;
114:
115: #ifdef PARANOID
116: if ( emulating )
117: {
118: printf("ERROR: wm-FPU-emu is not RE-ENTRANT!\r\n");
119: }
120: RE_ENTRANT_CHECK_ON
121: #endif PARANOID
122:
123: if (!emCurrent->used_math)
124: {
125: finit();
126: emCurrent->used_math = 1;
127: control_word = 0x037f;
128: status_word = 0x0000;
129: }
130:
131: FPU_info = (struct info *) &arg;
132:
133: /* We cannot handle emulation in v86-mode */
134: if (FPU_EFLAGS & 0x00020000)
135: math_abort(FPU_info,SIGILL);
136:
137: /* 0x000f means user code space */
138: if (FPU_CS != 0x000f)
139: {
140: printf("math_emulate: %04x:%08x\n\r",FPU_CS,FPU_EIP);
141: emPanic("Math emulation needed in kernel");
142: }
143:
144: FPU_lookahead = 1;
145: if (emCurrent->flags & PF_PTRACED)
146: FPU_lookahead = 0;
147: #endif
148: do_another:
149:
150: FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
151:
152: RE_ENTRANT_CHECK_OFF
153: code = get_fs_word((unsigned short *) FPU_EIP);
154: RE_ENTRANT_CHECK_ON
155:
156: if ( (code & 0xff) == 0x66 )
157: {
158: FPU_EIP++;
159: RE_ENTRANT_CHECK_OFF
160: code = get_fs_word((unsigned short *) FPU_EIP);
161: RE_ENTRANT_CHECK_ON
162: }
163: FPU_EIP += 2;
164:
165: FPU_modrm = code >> 8;
166: FPU_rm = FPU_modrm & 7;
167:
168: if ( FPU_modrm < 0300 )
169: {
170: /* All of these instructions use the mod/rm byte to get a data address */
171: get_address(FPU_modrm);
172:
173: if ( !(code & 1) )
174: {
175: switch ( (code >> 1) & 3 )
176: {
177: case 0:
178: reg_load_single();
179: break;
180: case 1:
181: reg_load_int32();
182: break;
183: case 2:
184: reg_load_double();
185: break;
186: case 3:
187: reg_load_int16();
188: break;
189: }
190:
191: /* No more access to user memory, it is safe
192: to use static data now */
193: FPU_st0_ptr = &st(0);
194: FPU_st0_tag = FPU_st0_ptr->tag;
195: if ( NOT_EMPTY_0 )
196: {
197: switch ( (FPU_modrm >> 3) & 7 )
198: {
199: case 0: /* fadd */
200: reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
201: break;
202: case 1: /* fmul */
203: reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
204: break;
205: case 2: /* fcom */
206: compare_st_data();
207: break;
208: case 3: /* fcomp */
209: compare_st_data();
210: pop();
211: break;
212: case 4: /* fsub */
213: reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
214: break;
215: case 5: /* fsubr */
216: reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
217: break;
218: case 6: /* fdiv */
219: reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
220: break;
221: case 7: /* fdivr */
222: reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
223: break;
224: }
225: }
226: else
227: stack_underflow();
228: }
229: else
230: {
231: load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
232: }
233:
234: #ifdef COHERENT
235: if (data_operand_offset != (unsigned long)FPU_data_address) {
236: data_operand_offset = (unsigned long)FPU_data_address;
237: operand_selector = FPU_DS;
238: }
239: #else
240: data_operand_offset = (unsigned long)FPU_data_address;
241: #endif
242: }
243: else
244: {
245: /* None of these instructions access user memory */
246: unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
247: FPU_st0_ptr = &st(0);
248: FPU_st0_tag = FPU_st0_ptr->tag;
249: switch ( type_table[(int) instr_index] )
250: {
251: case _NONE_:
252: break;
253: case _REG0_:
254: if ( !NOT_EMPTY_0 )
255: {
256: stack_underflow();
257: goto instruction_done;
258: }
259: break;
260: case _REGI_:
261: if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) )
262: {
263: stack_underflow();
264: goto instruction_done;
265: }
266: break;
267: case _PUSH_: /* Only used by the fld st(i) instruction */
268: break;
269: case _null_:
270: Un_impl();
271: goto instruction_done;
272: default:
273: EXCEPTION(EX_INTERNAL|0x111);
274: goto instruction_done;
275: }
276: (*st_instr_table[(int) instr_index])();
277: }
278:
279: instruction_done:
280:
281: #ifdef COHERENT
282: if (ip_offset != FPU_entry_eip) {
283: ip_offset = FPU_entry_eip;
284: bswapw(code);
285: cs_selector = ((code & 0x7ff) << 16) | FPU_CS;
286: }
287: #else
288: ip_offset = FPU_entry_eip;
289: bswapw(code);
290: *(1 + (unsigned short *)&cs_selector) = code & 0x7ff;
291: #endif
292:
293: #ifdef COHERENT
294: if (FPU_lookahead)
295: #else
296: if (FPU_lookahead && !need_resched)
297: #endif
298: {
299: unsigned char next;
300: skip_fwait:
301: RE_ENTRANT_CHECK_OFF
302: next = get_fs_byte((unsigned char *) FPU_EIP);
303: RE_ENTRANT_CHECK_ON
304: test_for_fp:
305: if ( (next & 0xf8) == 0xd8 )
306: {
307: goto do_another;
308: }
309: if ( next == 0x9b ) /* fwait */
310: { FPU_EIP++; goto skip_fwait; }
311: if ( next == 0x66 ) /* size prefix */
312: {
313: RE_ENTRANT_CHECK_OFF
314: next = get_fs_byte((unsigned char *) (FPU_EIP+1));
315: RE_ENTRANT_CHECK_ON
316: if ( (next & 0xf8) == 0xd8 )
317: goto test_for_fp;
318: }
319: }
320:
321: RE_ENTRANT_CHECK_OFF
322: }
323:
324: #ifndef COHERENT
325: void __math_abort(struct info * info, unsigned int signal)
326: {
327: FPU_EIP = FPU_ORIG_EIP;
328: emSendsig(signal,emCurrent,1);
329: __asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
330: }
331: #endif
332: #else /* no math emulation */
333:
334: #include <linux/signal.h>
335: #include <linux/sched.h>
336:
337: void math_emulate(long arg)
338: {
339: emSendsig(SIGFPE,emCurrent,1);
340: schedule();
341: }
342:
343: #endif /* KERNEL_MATH_EMULATION */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.