Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
[deliverable/linux.git] / arch / x86 / math-emu / load_store.c
CommitLineData
1da177e4
LT
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
3d0d14f9
IM
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 */
1da177e4
LT
33
34#define pop_0() { FPU_settag0(TAG_Empty); top++; }
35
1da177e4 36static u_char const type_table[32] = {
3d0d14f9
IM
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};
1da177e4
LT
46
47u_char const data_sizes_16[32] = {
3d0d14f9
IM
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
1da177e4
LT
52};
53
54static u_char const data_sizes_32[32] = {
3d0d14f9
IM
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
1da177e4
LT
59};
60
61int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
3d0d14f9 62 void __user * data_address)
1da177e4 63{
3d0d14f9
IM
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;
1da177e4 68
3d0d14f9 69 st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
1da177e4 70
3d0d14f9
IM
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 }
1da177e4 79#ifdef PARANOID
3d0d14f9
IM
80 else
81 EXCEPTION(EX_INTERNAL | 0x140);
1da177e4 82#endif /* PARANOID */
3d0d14f9 83 }
1da177e4 84
3d0d14f9
IM
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;
1da177e4 106#ifdef PARANOID
3d0d14f9
IM
107 default:
108 EXCEPTION(EX_INTERNAL | 0x141);
109 return 0;
1da177e4 110#endif /* PARANOID */
1da177e4 111 }
3d0d14f9
IM
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);
1da177e4 222#ifdef PECULIAR_486
3d0d14f9 223 control_word |= 0x40; /* An 80486 appears to always set this bit */
1da177e4 224#endif /* PECULIAR_486 */
3d0d14f9
IM
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 }
d606f88f 281 return 0;
1da177e4 282}
This page took 0.755847 seconds and 5 git commands to generate.