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