aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/math-emu/fpu_entry.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/math-emu/fpu_entry.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/i386/math-emu/fpu_entry.c')
-rw-r--r--arch/i386/math-emu/fpu_entry.c760
1 files changed, 760 insertions, 0 deletions
diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c
new file mode 100644
index 000000000000..d93f16ef828f
--- /dev/null
+++ b/arch/i386/math-emu/fpu_entry.c
@@ -0,0 +1,760 @@
1/*---------------------------------------------------------------------------+
2 | fpu_entry.c |
3 | |
4 | The entry functions for wm-FPU-emu |
5 | |
6 | Copyright (C) 1992,1993,1994,1996,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
9 | |
10 | See the files "README" and "COPYING" for further copyright and warranty |
11 | information. |
12 | |
13 +---------------------------------------------------------------------------*/
14
15/*---------------------------------------------------------------------------+
16 | Note: |
17 | The file contains code which accesses user memory. |
18 | Emulator static data may change when user memory is accessed, due to |
19 | other processes using the emulator while swapping is in progress. |
20 +---------------------------------------------------------------------------*/
21
22/*---------------------------------------------------------------------------+
23 | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
24 | entry points for wm-FPU-emu. |
25 +---------------------------------------------------------------------------*/
26
27#include <linux/signal.h>
28#include <linux/ptrace.h>
29
30#include <asm/uaccess.h>
31#include <asm/desc.h>
32
33#include "fpu_system.h"
34#include "fpu_emu.h"
35#include "exception.h"
36#include "control_w.h"
37#include "status_w.h"
38
39#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
40
41#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
42
43/* WARNING: These codes are not documented by Intel in their 80486 manual
44 and may not work on FPU clones or later Intel FPUs. */
45
46/* Changes to support the un-doc codes provided by Linus Torvalds. */
47
48#define _d9_d8_ fstp_i /* unofficial code (19) */
49#define _dc_d0_ fcom_st /* unofficial code (14) */
50#define _dc_d8_ fcompst /* unofficial code (1c) */
51#define _dd_c8_ fxch_i /* unofficial code (0d) */
52#define _de_d0_ fcompst /* unofficial code (16) */
53#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
54#define _df_c8_ fxch_i /* unofficial code (0f) */
55#define _df_d0_ fstp_i /* unofficial code (17) */
56#define _df_d8_ fstp_i /* unofficial code (1f) */
57
58static FUNC const st_instr_table[64] = {
59 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
60 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
61 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
62 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
63 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
64 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
65 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
66 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
67};
68
69#else /* Support only documented FPU op-codes */
70
71static FUNC const st_instr_table[64] = {
72 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
73 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
74 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
75 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
76 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
77 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
78 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
79 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
80};
81
82#endif /* NO_UNDOC_CODE */
83
84
85#define _NONE_ 0 /* Take no special action */
86#define _REG0_ 1 /* Need to check for not empty st(0) */
87#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
88#define _REGi_ 0 /* Uses st(rm) */
89#define _PUSH_ 3 /* Need to check for space to push onto stack */
90#define _null_ 4 /* Function illegal or not implemented */
91#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
92#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
93#define _REGIc 0 /* Compare st(0) and st(rm) */
94#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
95
96#ifndef NO_UNDOC_CODE
97
98/* Un-documented FPU op-codes supported by default. (see above) */
99
100static u_char const type_table[64] = {
101 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
102 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
103 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
104 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
105 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
106 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
107 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
108 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
109};
110
111#else /* Support only documented FPU op-codes */
112
113static u_char const type_table[64] = {
114 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
115 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
116 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
117 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
118 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
119 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
120 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
121 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
122};
123
124#endif /* NO_UNDOC_CODE */
125
126
127#ifdef RE_ENTRANT_CHECKING
128u_char emulating=0;
129#endif /* RE_ENTRANT_CHECKING */
130
131static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
132 overrides *override);
133
134asmlinkage void math_emulate(long arg)
135{
136 u_char FPU_modrm, byte1;
137 unsigned short code;
138 fpu_addr_modes addr_modes;
139 int unmasked;
140 FPU_REG loaded_data;
141 FPU_REG *st0_ptr;
142 u_char loaded_tag, st0_tag;
143 void __user *data_address;
144 struct address data_sel_off;
145 struct address entry_sel_off;
146 unsigned long code_base = 0;
147 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
148 struct desc_struct code_descriptor;
149
150#ifdef RE_ENTRANT_CHECKING
151 if ( emulating )
152 {
153 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
154 }
155 RE_ENTRANT_CHECK_ON;
156#endif /* RE_ENTRANT_CHECKING */
157
158 if (!used_math())
159 {
160 finit();
161 set_used_math();
162 }
163
164 SETUP_DATA_AREA(arg);
165
166 FPU_ORIG_EIP = FPU_EIP;
167
168 if ( (FPU_EFLAGS & 0x00020000) != 0 )
169 {
170 /* Virtual 8086 mode */
171 addr_modes.default_mode = VM86;
172 FPU_EIP += code_base = FPU_CS << 4;
173 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
174 }
175 else if ( FPU_CS == __USER_CS && FPU_DS == __USER_DS )
176 {
177 addr_modes.default_mode = 0;
178 }
179 else if ( FPU_CS == __KERNEL_CS )
180 {
181 printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
182 panic("Math emulation needed in kernel");
183 }
184 else
185 {
186
187 if ( (FPU_CS & 4) != 4 ) /* Must be in the LDT */
188 {
189 /* Can only handle segmented addressing via the LDT
190 for now, and it must be 16 bit */
191 printk("FPU emulator: Unsupported addressing mode\n");
192 math_abort(FPU_info, SIGILL);
193 }
194
195 code_descriptor = LDT_DESCRIPTOR(FPU_CS);
196 if ( SEG_D_SIZE(code_descriptor) )
197 {
198 /* The above test may be wrong, the book is not clear */
199 /* Segmented 32 bit protected mode */
200 addr_modes.default_mode = SEG32;
201 }
202 else
203 {
204 /* 16 bit protected mode */
205 addr_modes.default_mode = PM16;
206 }
207 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
208 code_limit = code_base
209 + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor)
210 - 1;
211 if ( code_limit < code_base ) code_limit = 0xffffffff;
212 }
213
214 FPU_lookahead = 1;
215 if (current->ptrace & PT_PTRACED)
216 FPU_lookahead = 0;
217
218 if ( !valid_prefix(&byte1, (u_char __user **)&FPU_EIP,
219 &addr_modes.override) )
220 {
221 RE_ENTRANT_CHECK_OFF;
222 printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
223 "FPU emulator: self-modifying code! (emulation impossible)\n",
224 byte1);
225 RE_ENTRANT_CHECK_ON;
226 EXCEPTION(EX_INTERNAL|0x126);
227 math_abort(FPU_info,SIGILL);
228 }
229
230do_another_FPU_instruction:
231
232 no_ip_update = 0;
233
234 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
235
236 if ( addr_modes.default_mode )
237 {
238 /* This checks for the minimum instruction bytes.
239 We also need to check any extra (address mode) code access. */
240 if ( FPU_EIP > code_limit )
241 math_abort(FPU_info,SIGSEGV);
242 }
243
244 if ( (byte1 & 0xf8) != 0xd8 )
245 {
246 if ( byte1 == FWAIT_OPCODE )
247 {
248 if (partial_status & SW_Summary)
249 goto do_the_FPU_interrupt;
250 else
251 goto FPU_fwait_done;
252 }
253#ifdef PARANOID
254 EXCEPTION(EX_INTERNAL|0x128);
255 math_abort(FPU_info,SIGILL);
256#endif /* PARANOID */
257 }
258
259 RE_ENTRANT_CHECK_OFF;
260 FPU_code_access_ok(1);
261 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
262 RE_ENTRANT_CHECK_ON;
263 FPU_EIP++;
264
265 if (partial_status & SW_Summary)
266 {
267 /* Ignore the error for now if the current instruction is a no-wait
268 control instruction */
269 /* The 80486 manual contradicts itself on this topic,
270 but a real 80486 uses the following instructions:
271 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
272 */
273 code = (FPU_modrm << 8) | byte1;
274 if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
275 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
276 fnstsw */
277 ((code & 0xc000) != 0xc000))) ) )
278 {
279 /*
280 * We need to simulate the action of the kernel to FPU
281 * interrupts here.
282 */
283 do_the_FPU_interrupt:
284
285 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
286
287 RE_ENTRANT_CHECK_OFF;
288 current->thread.trap_no = 16;
289 current->thread.error_code = 0;
290 send_sig(SIGFPE, current, 1);
291 return;
292 }
293 }
294
295 entry_sel_off.offset = FPU_ORIG_EIP;
296 entry_sel_off.selector = FPU_CS;
297 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
298
299 FPU_rm = FPU_modrm & 7;
300
301 if ( FPU_modrm < 0300 )
302 {
303 /* All of these instructions use the mod/rm byte to get a data address */
304
305 if ( (addr_modes.default_mode & SIXTEEN)
306 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
307 data_address = FPU_get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
308 addr_modes);
309 else
310 data_address = FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
311 addr_modes);
312
313 if ( addr_modes.default_mode )
314 {
315 if ( FPU_EIP-1 > code_limit )
316 math_abort(FPU_info,SIGSEGV);
317 }
318
319 if ( !(byte1 & 1) )
320 {
321 unsigned short status1 = partial_status;
322
323 st0_ptr = &st(0);
324 st0_tag = FPU_gettag0();
325
326 /* Stack underflow has priority */
327 if ( NOT_EMPTY_ST0 )
328 {
329 if ( addr_modes.default_mode & PROTECTED )
330 {
331 /* This table works for 16 and 32 bit protected mode */
332 if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] )
333 math_abort(FPU_info,SIGSEGV);
334 }
335
336 unmasked = 0; /* Do this here to stop compiler warnings. */
337 switch ( (byte1 >> 1) & 3 )
338 {
339 case 0:
340 unmasked = FPU_load_single((float __user *)data_address,
341 &loaded_data);
342 loaded_tag = unmasked & 0xff;
343 unmasked &= ~0xff;
344 break;
345 case 1:
346 loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
347 break;
348 case 2:
349 unmasked = FPU_load_double((double __user *)data_address,
350 &loaded_data);
351 loaded_tag = unmasked & 0xff;
352 unmasked &= ~0xff;
353 break;
354 case 3:
355 default: /* Used here to suppress gcc warnings. */
356 loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data);
357 break;
358 }
359
360 /* No more access to user memory, it is safe
361 to use static data now */
362
363 /* NaN operands have the next priority. */
364 /* We have to delay looking at st(0) until after
365 loading the data, because that data might contain an SNaN */
366 if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
367 ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
368 {
369 /* Restore the status word; we might have loaded a
370 denormal. */
371 partial_status = status1;
372 if ( (FPU_modrm & 0x30) == 0x10 )
373 {
374 /* fcom or fcomp */
375 EXCEPTION(EX_Invalid);
376 setcc(SW_C3 | SW_C2 | SW_C0);
377 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
378 FPU_pop(); /* fcomp, masked, so we pop. */
379 }
380 else
381 {
382 if ( loaded_tag == TAG_Special )
383 loaded_tag = FPU_Special(&loaded_data);
384#ifdef PECULIAR_486
385 /* This is not really needed, but gives behaviour
386 identical to an 80486 */
387 if ( (FPU_modrm & 0x28) == 0x20 )
388 /* fdiv or fsub */
389 real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
390 else
391#endif /* PECULIAR_486 */
392 /* fadd, fdivr, fmul, or fsubr */
393 real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
394 }
395 goto reg_mem_instr_done;
396 }
397
398 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )
399 {
400 /* Is not a comparison instruction. */
401 if ( (FPU_modrm & 0x38) == 0x38 )
402 {
403 /* fdivr */
404 if ( (st0_tag == TAG_Zero) &&
405 ((loaded_tag == TAG_Valid)
406 || (loaded_tag == TAG_Special
407 && isdenormal(&loaded_data))) )
408 {
409 if ( FPU_divide_by_zero(0, getsign(&loaded_data))
410 < 0 )
411 {
412 /* We use the fact here that the unmasked
413 exception in the loaded data was for a
414 denormal operand */
415 /* Restore the state of the denormal op bit */
416 partial_status &= ~SW_Denorm_Op;
417 partial_status |= status1 & SW_Denorm_Op;
418 }
419 else
420 setsign(st0_ptr, getsign(&loaded_data));
421 }
422 }
423 goto reg_mem_instr_done;
424 }
425
426 switch ( (FPU_modrm >> 3) & 7 )
427 {
428 case 0: /* fadd */
429 clear_C1();
430 FPU_add(&loaded_data, loaded_tag, 0, control_word);
431 break;
432 case 1: /* fmul */
433 clear_C1();
434 FPU_mul(&loaded_data, loaded_tag, 0, control_word);
435 break;
436 case 2: /* fcom */
437 FPU_compare_st_data(&loaded_data, loaded_tag);
438 break;
439 case 3: /* fcomp */
440 if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
441 && !unmasked )
442 FPU_pop();
443 break;
444 case 4: /* fsub */
445 clear_C1();
446 FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word);
447 break;
448 case 5: /* fsubr */
449 clear_C1();
450 FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
451 break;
452 case 6: /* fdiv */
453 clear_C1();
454 FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word);
455 break;
456 case 7: /* fdivr */
457 clear_C1();
458 if ( st0_tag == TAG_Zero )
459 partial_status = status1; /* Undo any denorm tag,
460 zero-divide has priority. */
461 FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
462 break;
463 }
464 }
465 else
466 {
467 if ( (FPU_modrm & 0x30) == 0x10 )
468 {
469 /* The instruction is fcom or fcomp */
470 EXCEPTION(EX_StackUnder);
471 setcc(SW_C3 | SW_C2 | SW_C0);
472 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
473 FPU_pop(); /* fcomp */
474 }
475 else
476 FPU_stack_underflow();
477 }
478 reg_mem_instr_done:
479 operand_address = data_sel_off;
480 }
481 else
482 {
483 if ( !(no_ip_update =
484 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
485 addr_modes, data_address)) )
486 {
487 operand_address = data_sel_off;
488 }
489 }
490
491 }
492 else
493 {
494 /* None of these instructions access user memory */
495 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
496
497#ifdef PECULIAR_486
498 /* This is supposed to be undefined, but a real 80486 seems
499 to do this: */
500 operand_address.offset = 0;
501 operand_address.selector = FPU_DS;
502#endif /* PECULIAR_486 */
503
504 st0_ptr = &st(0);
505 st0_tag = FPU_gettag0();
506 switch ( type_table[(int) instr_index] )
507 {
508 case _NONE_: /* also _REGIc: _REGIn */
509 break;
510 case _REG0_:
511 if ( !NOT_EMPTY_ST0 )
512 {
513 FPU_stack_underflow();
514 goto FPU_instruction_done;
515 }
516 break;
517 case _REGIi:
518 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
519 {
520 FPU_stack_underflow_i(FPU_rm);
521 goto FPU_instruction_done;
522 }
523 break;
524 case _REGIp:
525 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
526 {
527 FPU_stack_underflow_pop(FPU_rm);
528 goto FPU_instruction_done;
529 }
530 break;
531 case _REGI_:
532 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )
533 {
534 FPU_stack_underflow();
535 goto FPU_instruction_done;
536 }
537 break;
538 case _PUSH_: /* Only used by the fld st(i) instruction */
539 break;
540 case _null_:
541 FPU_illegal();
542 goto FPU_instruction_done;
543 default:
544 EXCEPTION(EX_INTERNAL|0x111);
545 goto FPU_instruction_done;
546 }
547 (*st_instr_table[(int) instr_index])();
548
549FPU_instruction_done:
550 ;
551 }
552
553 if ( ! no_ip_update )
554 instruction_address = entry_sel_off;
555
556FPU_fwait_done:
557
558#ifdef DEBUG
559 RE_ENTRANT_CHECK_OFF;
560 FPU_printall();
561 RE_ENTRANT_CHECK_ON;
562#endif /* DEBUG */
563
564 if (FPU_lookahead && !need_resched())
565 {
566 FPU_ORIG_EIP = FPU_EIP - code_base;
567 if ( valid_prefix(&byte1, (u_char __user **)&FPU_EIP,
568 &addr_modes.override) )
569 goto do_another_FPU_instruction;
570 }
571
572 if ( addr_modes.default_mode )
573 FPU_EIP -= code_base;
574
575 RE_ENTRANT_CHECK_OFF;
576}
577
578
579/* Support for prefix bytes is not yet complete. To properly handle
580 all prefix bytes, further changes are needed in the emulator code
581 which accesses user address space. Access to separate segments is
582 important for msdos emulation. */
583static int valid_prefix(u_char *Byte, u_char __user **fpu_eip,
584 overrides *override)
585{
586 u_char byte;
587 u_char __user *ip = *fpu_eip;
588
589 *override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */
590
591 RE_ENTRANT_CHECK_OFF;
592 FPU_code_access_ok(1);
593 FPU_get_user(byte, ip);
594 RE_ENTRANT_CHECK_ON;
595
596 while ( 1 )
597 {
598 switch ( byte )
599 {
600 case ADDR_SIZE_PREFIX:
601 override->address_size = ADDR_SIZE_PREFIX;
602 goto do_next_byte;
603
604 case OP_SIZE_PREFIX:
605 override->operand_size = OP_SIZE_PREFIX;
606 goto do_next_byte;
607
608 case PREFIX_CS:
609 override->segment = PREFIX_CS_;
610 goto do_next_byte;
611 case PREFIX_ES:
612 override->segment = PREFIX_ES_;
613 goto do_next_byte;
614 case PREFIX_SS:
615 override->segment = PREFIX_SS_;
616 goto do_next_byte;
617 case PREFIX_FS:
618 override->segment = PREFIX_FS_;
619 goto do_next_byte;
620 case PREFIX_GS:
621 override->segment = PREFIX_GS_;
622 goto do_next_byte;
623 case PREFIX_DS:
624 override->segment = PREFIX_DS_;
625 goto do_next_byte;
626
627/* lock is not a valid prefix for FPU instructions,
628 let the cpu handle it to generate a SIGILL. */
629/* case PREFIX_LOCK: */
630
631 /* rep.. prefixes have no meaning for FPU instructions */
632 case PREFIX_REPE:
633 case PREFIX_REPNE:
634
635 do_next_byte:
636 ip++;
637 RE_ENTRANT_CHECK_OFF;
638 FPU_code_access_ok(1);
639 FPU_get_user(byte, ip);
640 RE_ENTRANT_CHECK_ON;
641 break;
642 case FWAIT_OPCODE:
643 *Byte = byte;
644 return 1;
645 default:
646 if ( (byte & 0xf8) == 0xd8 )
647 {
648 *Byte = byte;
649 *fpu_eip = ip;
650 return 1;
651 }
652 else
653 {
654 /* Not a valid sequence of prefix bytes followed by
655 an FPU instruction. */
656 *Byte = byte; /* Needed for error message. */
657 return 0;
658 }
659 }
660 }
661}
662
663
664void math_abort(struct info * info, unsigned int signal)
665{
666 FPU_EIP = FPU_ORIG_EIP;
667 current->thread.trap_no = 16;
668 current->thread.error_code = 0;
669 send_sig(signal,current,1);
670 RE_ENTRANT_CHECK_OFF;
671 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
672#ifdef PARANOID
673 printk("ERROR: wm-FPU-emu math_abort failed!\n");
674#endif /* PARANOID */
675}
676
677
678
679#define S387 ((struct i387_soft_struct *)s387)
680#define sstatus_word() \
681 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
682
683int restore_i387_soft(void *s387, struct _fpstate __user *buf)
684{
685 u_char __user *d = (u_char __user *)buf;
686 int offset, other, i, tags, regnr, tag, newtop;
687
688 RE_ENTRANT_CHECK_OFF;
689 FPU_access_ok(VERIFY_READ, d, 7*4 + 8*10);
690 if (__copy_from_user(&S387->cwd, d, 7*4))
691 return -1;
692 RE_ENTRANT_CHECK_ON;
693
694 d += 7*4;
695
696 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
697 offset = (S387->ftop & 7) * 10;
698 other = 80 - offset;
699
700 RE_ENTRANT_CHECK_OFF;
701 /* Copy all registers in stack order. */
702 if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other))
703 return -1;
704 if ( offset )
705 if (__copy_from_user((u_char *)&S387->st_space, d+other, offset))
706 return -1;
707 RE_ENTRANT_CHECK_ON;
708
709 /* The tags may need to be corrected now. */
710 tags = S387->twd;
711 newtop = S387->ftop;
712 for ( i = 0; i < 8; i++ )
713 {
714 regnr = (i+newtop) & 7;
715 if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty )
716 {
717 /* The loaded data over-rides all other cases. */
718 tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr));
719 tags &= ~(3 << (regnr*2));
720 tags |= (tag & 3) << (regnr*2);
721 }
722 }
723 S387->twd = tags;
724
725 return 0;
726}
727
728
729int save_i387_soft(void *s387, struct _fpstate __user * buf)
730{
731 u_char __user *d = (u_char __user *)buf;
732 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
733
734 RE_ENTRANT_CHECK_OFF;
735 FPU_access_ok(VERIFY_WRITE, d, 7*4 + 8*10);
736#ifdef PECULIAR_486
737 S387->cwd &= ~0xe080;
738 /* An 80486 sets nearly all of the reserved bits to 1. */
739 S387->cwd |= 0xffff0040;
740 S387->swd = sstatus_word() | 0xffff0000;
741 S387->twd |= 0xffff0000;
742 S387->fcs &= ~0xf8000000;
743 S387->fos |= 0xffff0000;
744#endif /* PECULIAR_486 */
745 __copy_to_user(d, &S387->cwd, 7*4);
746 RE_ENTRANT_CHECK_ON;
747
748 d += 7*4;
749
750 RE_ENTRANT_CHECK_OFF;
751 /* Copy all registers in stack order. */
752 if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other))
753 return -1;
754 if ( offset )
755 if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset))
756 return -1
757 RE_ENTRANT_CHECK_ON;
758
759 return 1;
760}