xref: /openbmc/linux/arch/x86/math-emu/fpu_entry.c (revision 6ee73861)
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 
60 static 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 
73 static 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 
101 static 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 
114 static 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
128 u_char emulating = 0;
129 #endif /* RE_ENTRANT_CHECKING */
130 
131 static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
132 			overrides * override);
133 
134 void 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. */
586 static 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 
662 void 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 
679 int 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.xstate->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 
731 int 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.xstate->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 }
768