Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / x86 / math-emu / load_store.c
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                 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 }