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