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