PageRenderTime 39ms CodeModel.GetById 15ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/x86/math-emu/fpu_entry.c

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