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