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