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
51static 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
83static 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
96u_char emulating = 0;
97#endif /* RE_ENTRANT_CHECKING */
98
99static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
100			overrides * override);
101
102void 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. */
546static 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
622void 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
639int 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
691int 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