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 static u_char const type_table[32] = { 37 _PUSH_, _PUSH_, _PUSH_, _PUSH_, 38 _null_, _null_, _null_, _null_, 39 _REG0_, _REG0_, _REG0_, _REG0_, 40 _REG0_, _REG0_, _REG0_, _REG0_, 41 _NONE_, _null_, _NONE_, _PUSH_, 42 _NONE_, _PUSH_, _null_, _PUSH_, 43 _NONE_, _null_, _NONE_, _REG0_, 44 _NONE_, _REG0_, _NONE_, _REG0_ 45 }; 46 47 u_char const data_sizes_16[32] = { 48 4, 4, 8, 2, 0, 0, 0, 0, 49 4, 4, 8, 2, 4, 4, 8, 2, 50 14, 0, 94, 10, 2, 10, 0, 8, 51 14, 0, 94, 10, 2, 10, 2, 8 52 }; 53 54 static u_char const data_sizes_32[32] = { 55 4, 4, 8, 2, 0, 0, 0, 0, 56 4, 4, 8, 2, 4, 4, 8, 2, 57 28, 0, 108, 10, 2, 10, 0, 8, 58 28, 0, 108, 10, 2, 10, 2, 8 59 }; 60 61 int FPU_load_store(u_char type, fpu_addr_modes addr_modes, 62 void __user * data_address) 63 { 64 FPU_REG loaded_data; 65 FPU_REG *st0_ptr; 66 u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */ 67 u_char loaded_tag; 68 69 st0_ptr = NULL; /* Initialized just to stop compiler warnings. */ 70 71 if (addr_modes.default_mode & PROTECTED) { 72 if (addr_modes.default_mode == SEG32) { 73 if (access_limit < data_sizes_32[type]) 74 math_abort(FPU_info, SIGSEGV); 75 } else if (addr_modes.default_mode == PM16) { 76 if (access_limit < data_sizes_16[type]) 77 math_abort(FPU_info, SIGSEGV); 78 } 79 #ifdef PARANOID 80 else 81 EXCEPTION(EX_INTERNAL | 0x140); 82 #endif /* PARANOID */ 83 } 84 85 switch (type_table[type]) { 86 case _NONE_: 87 break; 88 case _REG0_: 89 st0_ptr = &st(0); /* Some of these instructions pop after 90 storing */ 91 st0_tag = FPU_gettag0(); 92 break; 93 case _PUSH_: 94 { 95 if (FPU_gettagi(-1) != TAG_Empty) { 96 FPU_stack_overflow(); 97 return 0; 98 } 99 top--; 100 st0_ptr = &st(0); 101 } 102 break; 103 case _null_: 104 FPU_illegal(); 105 return 0; 106 #ifdef PARANOID 107 default: 108 EXCEPTION(EX_INTERNAL | 0x141); 109 return 0; 110 #endif /* PARANOID */ 111 } 112 113 switch (type) { 114 case 000: /* fld m32real */ 115 clear_C1(); 116 loaded_tag = 117 FPU_load_single((float __user *)data_address, &loaded_data); 118 if ((loaded_tag == TAG_Special) 119 && isNaN(&loaded_data) 120 && (real_1op_NaN(&loaded_data) < 0)) { 121 top++; 122 break; 123 } 124 FPU_copy_to_reg0(&loaded_data, loaded_tag); 125 break; 126 case 001: /* fild m32int */ 127 clear_C1(); 128 loaded_tag = 129 FPU_load_int32((long __user *)data_address, &loaded_data); 130 FPU_copy_to_reg0(&loaded_data, loaded_tag); 131 break; 132 case 002: /* fld m64real */ 133 clear_C1(); 134 loaded_tag = 135 FPU_load_double((double __user *)data_address, 136 &loaded_data); 137 if ((loaded_tag == TAG_Special) 138 && isNaN(&loaded_data) 139 && (real_1op_NaN(&loaded_data) < 0)) { 140 top++; 141 break; 142 } 143 FPU_copy_to_reg0(&loaded_data, loaded_tag); 144 break; 145 case 003: /* fild m16int */ 146 clear_C1(); 147 loaded_tag = 148 FPU_load_int16((short __user *)data_address, &loaded_data); 149 FPU_copy_to_reg0(&loaded_data, loaded_tag); 150 break; 151 case 010: /* fst m32real */ 152 clear_C1(); 153 FPU_store_single(st0_ptr, st0_tag, 154 (float __user *)data_address); 155 break; 156 case 011: /* fist m32int */ 157 clear_C1(); 158 FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address); 159 break; 160 case 012: /* fst m64real */ 161 clear_C1(); 162 FPU_store_double(st0_ptr, st0_tag, 163 (double __user *)data_address); 164 break; 165 case 013: /* fist m16int */ 166 clear_C1(); 167 FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address); 168 break; 169 case 014: /* fstp m32real */ 170 clear_C1(); 171 if (FPU_store_single 172 (st0_ptr, st0_tag, (float __user *)data_address)) 173 pop_0(); /* pop only if the number was actually stored 174 (see the 80486 manual p16-28) */ 175 break; 176 case 015: /* fistp m32int */ 177 clear_C1(); 178 if (FPU_store_int32 179 (st0_ptr, st0_tag, (long __user *)data_address)) 180 pop_0(); /* pop only if the number was actually stored 181 (see the 80486 manual p16-28) */ 182 break; 183 case 016: /* fstp m64real */ 184 clear_C1(); 185 if (FPU_store_double 186 (st0_ptr, st0_tag, (double __user *)data_address)) 187 pop_0(); /* pop only if the number was actually stored 188 (see the 80486 manual p16-28) */ 189 break; 190 case 017: /* fistp m16int */ 191 clear_C1(); 192 if (FPU_store_int16 193 (st0_ptr, st0_tag, (short __user *)data_address)) 194 pop_0(); /* pop only if the number was actually stored 195 (see the 80486 manual p16-28) */ 196 break; 197 case 020: /* fldenv m14/28byte */ 198 fldenv(addr_modes, (u_char __user *) data_address); 199 /* Ensure that the values just loaded are not changed by 200 fix-up operations. */ 201 return 1; 202 case 022: /* frstor m94/108byte */ 203 frstor(addr_modes, (u_char __user *) data_address); 204 /* Ensure that the values just loaded are not changed by 205 fix-up operations. */ 206 return 1; 207 case 023: /* fbld m80dec */ 208 clear_C1(); 209 loaded_tag = FPU_load_bcd((u_char __user *) data_address); 210 FPU_settag0(loaded_tag); 211 break; 212 case 024: /* fldcw */ 213 RE_ENTRANT_CHECK_OFF; 214 FPU_access_ok(VERIFY_READ, data_address, 2); 215 FPU_get_user(control_word, 216 (unsigned short __user *)data_address); 217 RE_ENTRANT_CHECK_ON; 218 if (partial_status & ~control_word & CW_Exceptions) 219 partial_status |= (SW_Summary | SW_Backward); 220 else 221 partial_status &= ~(SW_Summary | SW_Backward); 222 #ifdef PECULIAR_486 223 control_word |= 0x40; /* An 80486 appears to always set this bit */ 224 #endif /* PECULIAR_486 */ 225 return 1; 226 case 025: /* fld m80real */ 227 clear_C1(); 228 loaded_tag = 229 FPU_load_extended((long double __user *)data_address, 0); 230 FPU_settag0(loaded_tag); 231 break; 232 case 027: /* fild m64int */ 233 clear_C1(); 234 loaded_tag = FPU_load_int64((long long __user *)data_address); 235 if (loaded_tag == TAG_Error) 236 return 0; 237 FPU_settag0(loaded_tag); 238 break; 239 case 030: /* fstenv m14/28byte */ 240 fstenv(addr_modes, (u_char __user *) data_address); 241 return 1; 242 case 032: /* fsave */ 243 fsave(addr_modes, (u_char __user *) data_address); 244 return 1; 245 case 033: /* fbstp m80dec */ 246 clear_C1(); 247 if (FPU_store_bcd 248 (st0_ptr, st0_tag, (u_char __user *) data_address)) 249 pop_0(); /* pop only if the number was actually stored 250 (see the 80486 manual p16-28) */ 251 break; 252 case 034: /* fstcw m16int */ 253 RE_ENTRANT_CHECK_OFF; 254 FPU_access_ok(VERIFY_WRITE, data_address, 2); 255 FPU_put_user(control_word, 256 (unsigned short __user *)data_address); 257 RE_ENTRANT_CHECK_ON; 258 return 1; 259 case 035: /* fstp m80real */ 260 clear_C1(); 261 if (FPU_store_extended 262 (st0_ptr, st0_tag, (long double __user *)data_address)) 263 pop_0(); /* pop only if the number was actually stored 264 (see the 80486 manual p16-28) */ 265 break; 266 case 036: /* fstsw m2byte */ 267 RE_ENTRANT_CHECK_OFF; 268 FPU_access_ok(VERIFY_WRITE, data_address, 2); 269 FPU_put_user(status_word(), 270 (unsigned short __user *)data_address); 271 RE_ENTRANT_CHECK_ON; 272 return 1; 273 case 037: /* fistp m64int */ 274 clear_C1(); 275 if (FPU_store_int64 276 (st0_ptr, st0_tag, (long long __user *)data_address)) 277 pop_0(); /* pop only if the number was actually stored 278 (see the 80486 manual p16-28) */ 279 break; 280 } 281 return 0; 282 } 283