root/arch/x86/math-emu/load_store.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. FPU_load_store

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*---------------------------------------------------------------------------+
   3  |  load_store.c                                                             |
   4  |                                                                           |
   5  | This file contains most of the code to interpret the FPU instructions     |
   6  | which load and store from user memory.                                    |
   7  |                                                                           |
   8  | Copyright (C) 1992,1993,1994,1997                                         |
   9  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  10  |                       Australia.  E-mail   billm@suburbia.net             |
  11  |                                                                           |
  12  |                                                                           |
  13  +---------------------------------------------------------------------------*/
  14 
  15 /*---------------------------------------------------------------------------+
  16  | Note:                                                                     |
  17  |    The file contains code which accesses user memory.                     |
  18  |    Emulator static data may change when user memory is accessed, due to   |
  19  |    other processes using the emulator while swapping is in progress.      |
  20  +---------------------------------------------------------------------------*/
  21 
  22 #include <linux/uaccess.h>
  23 
  24 #include "fpu_system.h"
  25 #include "exception.h"
  26 #include "fpu_emu.h"
  27 #include "status_w.h"
  28 #include "control_w.h"
  29 
  30 #define _NONE_ 0                /* st0_ptr etc not needed */
  31 #define _REG0_ 1                /* Will be storing st(0) */
  32 #define _PUSH_ 3                /* Need to check for space to push onto stack */
  33 #define _null_ 4                /* Function illegal or not implemented */
  34 
  35 #define pop_0() { FPU_settag0(TAG_Empty); top++; }
  36 
  37 /* index is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */
  38 static u_char const type_table[32] = {
  39         _PUSH_, _PUSH_, _PUSH_, _PUSH_, /* /0: d9:fld f32,  db:fild m32,  dd:fld f64,  df:fild m16 */
  40         _null_, _REG0_, _REG0_, _REG0_, /* /1: d9:undef,    db,dd,df:fisttp m32/64/16 */
  41         _REG0_, _REG0_, _REG0_, _REG0_, /* /2: d9:fst f32,  db:fist m32,  dd:fst f64,  df:fist m16 */
  42         _REG0_, _REG0_, _REG0_, _REG0_, /* /3: d9:fstp f32, db:fistp m32, dd:fstp f64, df:fistp m16 */
  43         _NONE_, _null_, _NONE_, _PUSH_,
  44         _NONE_, _PUSH_, _null_, _PUSH_,
  45         _NONE_, _null_, _NONE_, _REG0_,
  46         _NONE_, _REG0_, _NONE_, _REG0_
  47 };
  48 
  49 u_char const data_sizes_16[32] = {
  50         4, 4, 8, 2,
  51         0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */
  52         4, 4, 8, 2,
  53         4, 4, 8, 2,
  54         14, 0, 94, 10, 2, 10, 0, 8,
  55         14, 0, 94, 10, 2, 10, 2, 8
  56 };
  57 
  58 static u_char const data_sizes_32[32] = {
  59         4, 4, 8, 2,
  60         0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */
  61         4, 4, 8, 2,
  62         4, 4, 8, 2,
  63         28, 0, 108, 10, 2, 10, 0, 8,
  64         28, 0, 108, 10, 2, 10, 2, 8
  65 };
  66 
  67 int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
  68                    void __user * data_address)
  69 {
  70         FPU_REG loaded_data;
  71         FPU_REG *st0_ptr;
  72         u_char st0_tag = TAG_Empty;     /* This is just to stop a gcc warning. */
  73         u_char loaded_tag;
  74         int sv_cw;
  75 
  76         st0_ptr = NULL;         /* Initialized just to stop compiler warnings. */
  77 
  78         if (addr_modes.default_mode & PROTECTED) {
  79                 if (addr_modes.default_mode == SEG32) {
  80                         if (access_limit < data_sizes_32[type])
  81                                 math_abort(FPU_info, SIGSEGV);
  82                 } else if (addr_modes.default_mode == PM16) {
  83                         if (access_limit < data_sizes_16[type])
  84                                 math_abort(FPU_info, SIGSEGV);
  85                 }
  86 #ifdef PARANOID
  87                 else
  88                         EXCEPTION(EX_INTERNAL | 0x140);
  89 #endif /* PARANOID */
  90         }
  91 
  92         switch (type_table[type]) {
  93         case _NONE_:
  94                 break;
  95         case _REG0_:
  96                 st0_ptr = &st(0);       /* Some of these instructions pop after
  97                                            storing */
  98                 st0_tag = FPU_gettag0();
  99                 break;
 100         case _PUSH_:
 101                 {
 102                         if (FPU_gettagi(-1) != TAG_Empty) {
 103                                 FPU_stack_overflow();
 104                                 return 0;
 105                         }
 106                         top--;
 107                         st0_ptr = &st(0);
 108                 }
 109                 break;
 110         case _null_:
 111                 FPU_illegal();
 112                 return 0;
 113 #ifdef PARANOID
 114         default:
 115                 EXCEPTION(EX_INTERNAL | 0x141);
 116                 return 0;
 117 #endif /* PARANOID */
 118         }
 119 
 120         switch (type) {
 121         /* type is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */
 122         case 000:               /* fld m32real (d9 /0) */
 123                 clear_C1();
 124                 loaded_tag =
 125                     FPU_load_single((float __user *)data_address, &loaded_data);
 126                 if ((loaded_tag == TAG_Special)
 127                     && isNaN(&loaded_data)
 128                     && (real_1op_NaN(&loaded_data) < 0)) {
 129                         top++;
 130                         break;
 131                 }
 132                 FPU_copy_to_reg0(&loaded_data, loaded_tag);
 133                 break;
 134         case 001:               /* fild m32int (db /0) */
 135                 clear_C1();
 136                 loaded_tag =
 137                     FPU_load_int32((long __user *)data_address, &loaded_data);
 138                 FPU_copy_to_reg0(&loaded_data, loaded_tag);
 139                 break;
 140         case 002:               /* fld m64real (dd /0) */
 141                 clear_C1();
 142                 loaded_tag =
 143                     FPU_load_double((double __user *)data_address,
 144                                     &loaded_data);
 145                 if ((loaded_tag == TAG_Special)
 146                     && isNaN(&loaded_data)
 147                     && (real_1op_NaN(&loaded_data) < 0)) {
 148                         top++;
 149                         break;
 150                 }
 151                 FPU_copy_to_reg0(&loaded_data, loaded_tag);
 152                 break;
 153         case 003:               /* fild m16int (df /0) */
 154                 clear_C1();
 155                 loaded_tag =
 156                     FPU_load_int16((short __user *)data_address, &loaded_data);
 157                 FPU_copy_to_reg0(&loaded_data, loaded_tag);
 158                 break;
 159         /* case 004: undefined (d9 /1) */
 160         /* fisttp are enabled if CPUID(1).ECX(0) "sse3" is set */
 161         case 005:               /* fisttp m32int (db /1) */
 162                 clear_C1();
 163                 sv_cw = control_word;
 164                 control_word |= RC_CHOP;
 165                 if (FPU_store_int32
 166                     (st0_ptr, st0_tag, (long __user *)data_address))
 167                         pop_0();        /* pop only if the number was actually stored
 168                                            (see the 80486 manual p16-28) */
 169                 control_word = sv_cw;
 170                 break;
 171         case 006:               /* fisttp m64int (dd /1) */
 172                 clear_C1();
 173                 sv_cw = control_word;
 174                 control_word |= RC_CHOP;
 175                 if (FPU_store_int64
 176                     (st0_ptr, st0_tag, (long long __user *)data_address))
 177                         pop_0();        /* pop only if the number was actually stored
 178                                            (see the 80486 manual p16-28) */
 179                 control_word = sv_cw;
 180                 break;
 181         case 007:               /* fisttp m16int (df /1) */
 182                 clear_C1();
 183                 sv_cw = control_word;
 184                 control_word |= RC_CHOP;
 185                 if (FPU_store_int16
 186                     (st0_ptr, st0_tag, (short __user *)data_address))
 187                         pop_0();        /* pop only if the number was actually stored
 188                                            (see the 80486 manual p16-28) */
 189                 control_word = sv_cw;
 190                 break;
 191         case 010:               /* fst m32real */
 192                 clear_C1();
 193                 FPU_store_single(st0_ptr, st0_tag,
 194                                  (float __user *)data_address);
 195                 break;
 196         case 011:               /* fist m32int */
 197                 clear_C1();
 198                 FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
 199                 break;
 200         case 012:               /* fst m64real */
 201                 clear_C1();
 202                 FPU_store_double(st0_ptr, st0_tag,
 203                                  (double __user *)data_address);
 204                 break;
 205         case 013:               /* fist m16int */
 206                 clear_C1();
 207                 FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
 208                 break;
 209         case 014:               /* fstp m32real */
 210                 clear_C1();
 211                 if (FPU_store_single
 212                     (st0_ptr, st0_tag, (float __user *)data_address))
 213                         pop_0();        /* pop only if the number was actually stored
 214                                            (see the 80486 manual p16-28) */
 215                 break;
 216         case 015:               /* fistp m32int */
 217                 clear_C1();
 218                 if (FPU_store_int32
 219                     (st0_ptr, st0_tag, (long __user *)data_address))
 220                         pop_0();        /* pop only if the number was actually stored
 221                                            (see the 80486 manual p16-28) */
 222                 break;
 223         case 016:               /* fstp m64real */
 224                 clear_C1();
 225                 if (FPU_store_double
 226                     (st0_ptr, st0_tag, (double __user *)data_address))
 227                         pop_0();        /* pop only if the number was actually stored
 228                                            (see the 80486 manual p16-28) */
 229                 break;
 230         case 017:               /* fistp m16int */
 231                 clear_C1();
 232                 if (FPU_store_int16
 233                     (st0_ptr, st0_tag, (short __user *)data_address))
 234                         pop_0();        /* pop only if the number was actually stored
 235                                            (see the 80486 manual p16-28) */
 236                 break;
 237         case 020:               /* fldenv  m14/28byte */
 238                 fldenv(addr_modes, (u_char __user *) data_address);
 239                 /* Ensure that the values just loaded are not changed by
 240                    fix-up operations. */
 241                 return 1;
 242         case 022:               /* frstor m94/108byte */
 243                 frstor(addr_modes, (u_char __user *) data_address);
 244                 /* Ensure that the values just loaded are not changed by
 245                    fix-up operations. */
 246                 return 1;
 247         case 023:               /* fbld m80dec */
 248                 clear_C1();
 249                 loaded_tag = FPU_load_bcd((u_char __user *) data_address);
 250                 FPU_settag0(loaded_tag);
 251                 break;
 252         case 024:               /* fldcw */
 253                 RE_ENTRANT_CHECK_OFF;
 254                 FPU_access_ok(data_address, 2);
 255                 FPU_get_user(control_word,
 256                              (unsigned short __user *)data_address);
 257                 RE_ENTRANT_CHECK_ON;
 258                 if (partial_status & ~control_word & CW_Exceptions)
 259                         partial_status |= (SW_Summary | SW_Backward);
 260                 else
 261                         partial_status &= ~(SW_Summary | SW_Backward);
 262 #ifdef PECULIAR_486
 263                 control_word |= 0x40;   /* An 80486 appears to always set this bit */
 264 #endif /* PECULIAR_486 */
 265                 return 1;
 266         case 025:               /* fld m80real */
 267                 clear_C1();
 268                 loaded_tag =
 269                     FPU_load_extended((long double __user *)data_address, 0);
 270                 FPU_settag0(loaded_tag);
 271                 break;
 272         case 027:               /* fild m64int */
 273                 clear_C1();
 274                 loaded_tag = FPU_load_int64((long long __user *)data_address);
 275                 if (loaded_tag == TAG_Error)
 276                         return 0;
 277                 FPU_settag0(loaded_tag);
 278                 break;
 279         case 030:               /* fstenv  m14/28byte */
 280                 fstenv(addr_modes, (u_char __user *) data_address);
 281                 return 1;
 282         case 032:               /* fsave */
 283                 fsave(addr_modes, (u_char __user *) data_address);
 284                 return 1;
 285         case 033:               /* fbstp m80dec */
 286                 clear_C1();
 287                 if (FPU_store_bcd
 288                     (st0_ptr, st0_tag, (u_char __user *) data_address))
 289                         pop_0();        /* pop only if the number was actually stored
 290                                            (see the 80486 manual p16-28) */
 291                 break;
 292         case 034:               /* fstcw m16int */
 293                 RE_ENTRANT_CHECK_OFF;
 294                 FPU_access_ok(data_address, 2);
 295                 FPU_put_user(control_word,
 296                              (unsigned short __user *)data_address);
 297                 RE_ENTRANT_CHECK_ON;
 298                 return 1;
 299         case 035:               /* fstp m80real */
 300                 clear_C1();
 301                 if (FPU_store_extended
 302                     (st0_ptr, st0_tag, (long double __user *)data_address))
 303                         pop_0();        /* pop only if the number was actually stored
 304                                            (see the 80486 manual p16-28) */
 305                 break;
 306         case 036:               /* fstsw m2byte */
 307                 RE_ENTRANT_CHECK_OFF;
 308                 FPU_access_ok(data_address, 2);
 309                 FPU_put_user(status_word(),
 310                              (unsigned short __user *)data_address);
 311                 RE_ENTRANT_CHECK_ON;
 312                 return 1;
 313         case 037:               /* fistp m64int */
 314                 clear_C1();
 315                 if (FPU_store_int64
 316                     (st0_ptr, st0_tag, (long long __user *)data_address))
 317                         pop_0();        /* pop only if the number was actually stored
 318                                            (see the 80486 manual p16-28) */
 319                 break;
 320         }
 321         return 0;
 322 }

/* [<][>][^][v][top][bottom][index][help] */