~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/load_store.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php