^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) }