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