Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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