0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
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
0031 #define _REG0_ 1
0032 #define _PUSH_ 3
0033 #define _null_ 4
0034
0035 #define pop_0() { FPU_settag0(TAG_Empty); top++; }
0036
0037
0038 static u_char const type_table[32] = {
0039 _PUSH_, _PUSH_, _PUSH_, _PUSH_,
0040 _null_, _REG0_, _REG0_, _REG0_,
0041 _REG0_, _REG0_, _REG0_, _REG0_,
0042 _REG0_, _REG0_, _REG0_, _REG0_,
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,
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,
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;
0073 u_char loaded_tag;
0074 int sv_cw;
0075
0076 st0_ptr = NULL;
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
0090 }
0091
0092 switch (type_table[type]) {
0093 case _NONE_:
0094 break;
0095 case _REG0_:
0096 st0_ptr = &st(0);
0097
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
0118 }
0119
0120 switch (type) {
0121
0122 case 000:
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:
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:
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:
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
0160
0161 case 005:
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();
0168
0169 control_word = sv_cw;
0170 break;
0171 case 006:
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();
0178
0179 control_word = sv_cw;
0180 break;
0181 case 007:
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();
0188
0189 control_word = sv_cw;
0190 break;
0191 case 010:
0192 clear_C1();
0193 FPU_store_single(st0_ptr, st0_tag,
0194 (float __user *)data_address);
0195 break;
0196 case 011:
0197 clear_C1();
0198 FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
0199 break;
0200 case 012:
0201 clear_C1();
0202 FPU_store_double(st0_ptr, st0_tag,
0203 (double __user *)data_address);
0204 break;
0205 case 013:
0206 clear_C1();
0207 FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
0208 break;
0209 case 014:
0210 clear_C1();
0211 if (FPU_store_single
0212 (st0_ptr, st0_tag, (float __user *)data_address))
0213 pop_0();
0214
0215 break;
0216 case 015:
0217 clear_C1();
0218 if (FPU_store_int32
0219 (st0_ptr, st0_tag, (long __user *)data_address))
0220 pop_0();
0221
0222 break;
0223 case 016:
0224 clear_C1();
0225 if (FPU_store_double
0226 (st0_ptr, st0_tag, (double __user *)data_address))
0227 pop_0();
0228
0229 break;
0230 case 017:
0231 clear_C1();
0232 if (FPU_store_int16
0233 (st0_ptr, st0_tag, (short __user *)data_address))
0234 pop_0();
0235
0236 break;
0237 case 020:
0238 fldenv(addr_modes, (u_char __user *) data_address);
0239
0240
0241 return 1;
0242 case 022:
0243 FPU_frstor(addr_modes, (u_char __user *) data_address);
0244
0245
0246 return 1;
0247 case 023:
0248 clear_C1();
0249 loaded_tag = FPU_load_bcd((u_char __user *) data_address);
0250 FPU_settag0(loaded_tag);
0251 break;
0252 case 024:
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;
0264 #endif
0265 return 1;
0266 case 025:
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:
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:
0280 fstenv(addr_modes, (u_char __user *) data_address);
0281 return 1;
0282 case 032:
0283 fsave(addr_modes, (u_char __user *) data_address);
0284 return 1;
0285 case 033:
0286 clear_C1();
0287 if (FPU_store_bcd
0288 (st0_ptr, st0_tag, (u_char __user *) data_address))
0289 pop_0();
0290
0291 break;
0292 case 034:
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:
0300 clear_C1();
0301 if (FPU_store_extended
0302 (st0_ptr, st0_tag, (long double __user *)data_address))
0303 pop_0();
0304
0305 break;
0306 case 036:
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:
0314 clear_C1();
0315 if (FPU_store_int64
0316 (st0_ptr, st0_tag, (long long __user *)data_address))
0317 pop_0();
0318
0319 break;
0320 }
0321 return 0;
0322 }