Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*---------------------------------------------------------------------------+
0003  |  load_store.c                                                             |
0004  |                                                                           |
0005  | This file contains most of the code to interpret the FPU instructions     |
0006  | which load and store from user memory.                                    |
0007  |                                                                           |
0008  | Copyright (C) 1992,1993,1994,1997                                         |
0009  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
0010  |                       Australia.  E-mail   billm@suburbia.net             |
0011  |                                                                           |
0012  |                                                                           |
0013  +---------------------------------------------------------------------------*/
0014 
0015 /*---------------------------------------------------------------------------+
0016  | Note:                                                                     |
0017  |    The file contains code which accesses user memory.                     |
0018  |    Emulator static data may change when user memory is accessed, due to   |
0019  |    other processes using the emulator while swapping is in progress.      |
0020  +---------------------------------------------------------------------------*/
0021 
0022 #include <linux/uaccess.h>
0023 
0024 #include "fpu_system.h"
0025 #include "exception.h"
0026 #include "fpu_emu.h"
0027 #include "status_w.h"
0028 #include "control_w.h"
0029 
0030 #define _NONE_ 0        /* st0_ptr etc not needed */
0031 #define _REG0_ 1        /* Will be storing st(0) */
0032 #define _PUSH_ 3        /* Need to check for space to push onto stack */
0033 #define _null_ 4        /* Function illegal or not implemented */
0034 
0035 #define pop_0() { FPU_settag0(TAG_Empty); top++; }
0036 
0037 /* index is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */
0038 static u_char const type_table[32] = {
0039     _PUSH_, _PUSH_, _PUSH_, _PUSH_, /* /0: d9:fld f32,  db:fild m32,  dd:fld f64,  df:fild m16 */
0040     _null_, _REG0_, _REG0_, _REG0_, /* /1: d9:undef,    db,dd,df:fisttp m32/64/16 */
0041     _REG0_, _REG0_, _REG0_, _REG0_, /* /2: d9:fst f32,  db:fist m32,  dd:fst f64,  df:fist m16 */
0042     _REG0_, _REG0_, _REG0_, _REG0_, /* /3: d9:fstp f32, db:fistp m32, dd:fstp f64, df:fistp m16 */
0043     _NONE_, _null_, _NONE_, _PUSH_,
0044     _NONE_, _PUSH_, _null_, _PUSH_,
0045     _NONE_, _null_, _NONE_, _REG0_,
0046     _NONE_, _REG0_, _NONE_, _REG0_
0047 };
0048 
0049 u_char const data_sizes_16[32] = {
0050     4, 4, 8, 2,
0051     0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */
0052     4, 4, 8, 2,
0053     4, 4, 8, 2,
0054     14, 0, 94, 10, 2, 10, 0, 8,
0055     14, 0, 94, 10, 2, 10, 2, 8
0056 };
0057 
0058 static u_char const data_sizes_32[32] = {
0059     4, 4, 8, 2,
0060     0, 4, 8, 2, /* /1: d9:undef, db,dd,df:fisttp */
0061     4, 4, 8, 2,
0062     4, 4, 8, 2,
0063     28, 0, 108, 10, 2, 10, 0, 8,
0064     28, 0, 108, 10, 2, 10, 2, 8
0065 };
0066 
0067 int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
0068            void __user * data_address)
0069 {
0070     FPU_REG loaded_data;
0071     FPU_REG *st0_ptr;
0072     u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
0073     u_char loaded_tag;
0074     int sv_cw;
0075 
0076     st0_ptr = NULL;     /* Initialized just to stop compiler warnings. */
0077 
0078     if (addr_modes.default_mode & PROTECTED) {
0079         if (addr_modes.default_mode == SEG32) {
0080             if (access_limit < data_sizes_32[type])
0081                 math_abort(FPU_info, SIGSEGV);
0082         } else if (addr_modes.default_mode == PM16) {
0083             if (access_limit < data_sizes_16[type])
0084                 math_abort(FPU_info, SIGSEGV);
0085         }
0086 #ifdef PARANOID
0087         else
0088             EXCEPTION(EX_INTERNAL | 0x140);
0089 #endif /* PARANOID */
0090     }
0091 
0092     switch (type_table[type]) {
0093     case _NONE_:
0094         break;
0095     case _REG0_:
0096         st0_ptr = &st(0);   /* Some of these instructions pop after
0097                        storing */
0098         st0_tag = FPU_gettag0();
0099         break;
0100     case _PUSH_:
0101         {
0102             if (FPU_gettagi(-1) != TAG_Empty) {
0103                 FPU_stack_overflow();
0104                 return 0;
0105             }
0106             top--;
0107             st0_ptr = &st(0);
0108         }
0109         break;
0110     case _null_:
0111         FPU_illegal();
0112         return 0;
0113 #ifdef PARANOID
0114     default:
0115         EXCEPTION(EX_INTERNAL | 0x141);
0116         return 0;
0117 #endif /* PARANOID */
0118     }
0119 
0120     switch (type) {
0121     /* type is a 5-bit value: (3-bit FPU_modrm.reg field | opcode[2,1]) */
0122     case 000:       /* fld m32real (d9 /0) */
0123         clear_C1();
0124         loaded_tag =
0125             FPU_load_single((float __user *)data_address, &loaded_data);
0126         if ((loaded_tag == TAG_Special)
0127             && isNaN(&loaded_data)
0128             && (real_1op_NaN(&loaded_data) < 0)) {
0129             top++;
0130             break;
0131         }
0132         FPU_copy_to_reg0(&loaded_data, loaded_tag);
0133         break;
0134     case 001:       /* fild m32int (db /0) */
0135         clear_C1();
0136         loaded_tag =
0137             FPU_load_int32((long __user *)data_address, &loaded_data);
0138         FPU_copy_to_reg0(&loaded_data, loaded_tag);
0139         break;
0140     case 002:       /* fld m64real (dd /0) */
0141         clear_C1();
0142         loaded_tag =
0143             FPU_load_double((double __user *)data_address,
0144                     &loaded_data);
0145         if ((loaded_tag == TAG_Special)
0146             && isNaN(&loaded_data)
0147             && (real_1op_NaN(&loaded_data) < 0)) {
0148             top++;
0149             break;
0150         }
0151         FPU_copy_to_reg0(&loaded_data, loaded_tag);
0152         break;
0153     case 003:       /* fild m16int (df /0) */
0154         clear_C1();
0155         loaded_tag =
0156             FPU_load_int16((short __user *)data_address, &loaded_data);
0157         FPU_copy_to_reg0(&loaded_data, loaded_tag);
0158         break;
0159     /* case 004: undefined (d9 /1) */
0160     /* fisttp are enabled if CPUID(1).ECX(0) "sse3" is set */
0161     case 005:       /* fisttp m32int (db /1) */
0162         clear_C1();
0163         sv_cw = control_word;
0164         control_word |= RC_CHOP;
0165         if (FPU_store_int32
0166             (st0_ptr, st0_tag, (long __user *)data_address))
0167             pop_0();    /* pop only if the number was actually stored
0168                        (see the 80486 manual p16-28) */
0169         control_word = sv_cw;
0170         break;
0171     case 006:       /* fisttp m64int (dd /1) */
0172         clear_C1();
0173         sv_cw = control_word;
0174         control_word |= RC_CHOP;
0175         if (FPU_store_int64
0176             (st0_ptr, st0_tag, (long long __user *)data_address))
0177             pop_0();    /* pop only if the number was actually stored
0178                        (see the 80486 manual p16-28) */
0179         control_word = sv_cw;
0180         break;
0181     case 007:       /* fisttp m16int (df /1) */
0182         clear_C1();
0183         sv_cw = control_word;
0184         control_word |= RC_CHOP;
0185         if (FPU_store_int16
0186             (st0_ptr, st0_tag, (short __user *)data_address))
0187             pop_0();    /* pop only if the number was actually stored
0188                        (see the 80486 manual p16-28) */
0189         control_word = sv_cw;
0190         break;
0191     case 010:       /* fst m32real */
0192         clear_C1();
0193         FPU_store_single(st0_ptr, st0_tag,
0194                  (float __user *)data_address);
0195         break;
0196     case 011:       /* fist m32int */
0197         clear_C1();
0198         FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
0199         break;
0200     case 012:       /* fst m64real */
0201         clear_C1();
0202         FPU_store_double(st0_ptr, st0_tag,
0203                  (double __user *)data_address);
0204         break;
0205     case 013:       /* fist m16int */
0206         clear_C1();
0207         FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
0208         break;
0209     case 014:       /* fstp m32real */
0210         clear_C1();
0211         if (FPU_store_single
0212             (st0_ptr, st0_tag, (float __user *)data_address))
0213             pop_0();    /* pop only if the number was actually stored
0214                        (see the 80486 manual p16-28) */
0215         break;
0216     case 015:       /* fistp m32int */
0217         clear_C1();
0218         if (FPU_store_int32
0219             (st0_ptr, st0_tag, (long __user *)data_address))
0220             pop_0();    /* pop only if the number was actually stored
0221                        (see the 80486 manual p16-28) */
0222         break;
0223     case 016:       /* fstp m64real */
0224         clear_C1();
0225         if (FPU_store_double
0226             (st0_ptr, st0_tag, (double __user *)data_address))
0227             pop_0();    /* pop only if the number was actually stored
0228                        (see the 80486 manual p16-28) */
0229         break;
0230     case 017:       /* fistp m16int */
0231         clear_C1();
0232         if (FPU_store_int16
0233             (st0_ptr, st0_tag, (short __user *)data_address))
0234             pop_0();    /* pop only if the number was actually stored
0235                        (see the 80486 manual p16-28) */
0236         break;
0237     case 020:       /* fldenv  m14/28byte */
0238         fldenv(addr_modes, (u_char __user *) data_address);
0239         /* Ensure that the values just loaded are not changed by
0240            fix-up operations. */
0241         return 1;
0242     case 022:       /* frstor m94/108byte */
0243         FPU_frstor(addr_modes, (u_char __user *) data_address);
0244         /* Ensure that the values just loaded are not changed by
0245            fix-up operations. */
0246         return 1;
0247     case 023:       /* fbld m80dec */
0248         clear_C1();
0249         loaded_tag = FPU_load_bcd((u_char __user *) data_address);
0250         FPU_settag0(loaded_tag);
0251         break;
0252     case 024:       /* fldcw */
0253         RE_ENTRANT_CHECK_OFF;
0254         FPU_access_ok(data_address, 2);
0255         FPU_get_user(control_word,
0256                  (unsigned short __user *)data_address);
0257         RE_ENTRANT_CHECK_ON;
0258         if (partial_status & ~control_word & CW_Exceptions)
0259             partial_status |= (SW_Summary | SW_Backward);
0260         else
0261             partial_status &= ~(SW_Summary | SW_Backward);
0262 #ifdef PECULIAR_486
0263         control_word |= 0x40;   /* An 80486 appears to always set this bit */
0264 #endif /* PECULIAR_486 */
0265         return 1;
0266     case 025:       /* fld m80real */
0267         clear_C1();
0268         loaded_tag =
0269             FPU_load_extended((long double __user *)data_address, 0);
0270         FPU_settag0(loaded_tag);
0271         break;
0272     case 027:       /* fild m64int */
0273         clear_C1();
0274         loaded_tag = FPU_load_int64((long long __user *)data_address);
0275         if (loaded_tag == TAG_Error)
0276             return 0;
0277         FPU_settag0(loaded_tag);
0278         break;
0279     case 030:       /* fstenv  m14/28byte */
0280         fstenv(addr_modes, (u_char __user *) data_address);
0281         return 1;
0282     case 032:       /* fsave */
0283         fsave(addr_modes, (u_char __user *) data_address);
0284         return 1;
0285     case 033:       /* fbstp m80dec */
0286         clear_C1();
0287         if (FPU_store_bcd
0288             (st0_ptr, st0_tag, (u_char __user *) data_address))
0289             pop_0();    /* pop only if the number was actually stored
0290                        (see the 80486 manual p16-28) */
0291         break;
0292     case 034:       /* fstcw m16int */
0293         RE_ENTRANT_CHECK_OFF;
0294         FPU_access_ok(data_address, 2);
0295         FPU_put_user(control_word,
0296                  (unsigned short __user *)data_address);
0297         RE_ENTRANT_CHECK_ON;
0298         return 1;
0299     case 035:       /* fstp m80real */
0300         clear_C1();
0301         if (FPU_store_extended
0302             (st0_ptr, st0_tag, (long double __user *)data_address))
0303             pop_0();    /* pop only if the number was actually stored
0304                        (see the 80486 manual p16-28) */
0305         break;
0306     case 036:       /* fstsw m2byte */
0307         RE_ENTRANT_CHECK_OFF;
0308         FPU_access_ok(data_address, 2);
0309         FPU_put_user(status_word(),
0310                  (unsigned short __user *)data_address);
0311         RE_ENTRANT_CHECK_ON;
0312         return 1;
0313     case 037:       /* fistp m64int */
0314         clear_C1();
0315         if (FPU_store_int64
0316             (st0_ptr, st0_tag, (long long __user *)data_address))
0317             pop_0();    /* pop only if the number was actually stored
0318                        (see the 80486 manual p16-28) */
0319         break;
0320     }
0321     return 0;
0322 }