aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/math-emu/reg_ld_str.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/math-emu/reg_ld_str.c')
-rw-r--r--arch/x86/math-emu/reg_ld_str.c2147
1 files changed, 998 insertions, 1149 deletions
diff --git a/arch/x86/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c
index e976caef6498..799d4af5be66 100644
--- a/arch/x86/math-emu/reg_ld_str.c
+++ b/arch/x86/math-emu/reg_ld_str.c
@@ -27,1084 +27,938 @@
27#include "control_w.h" 27#include "control_w.h"
28#include "status_w.h" 28#include "status_w.h"
29 29
30 30#define DOUBLE_Emax 1023 /* largest valid exponent */
31#define DOUBLE_Emax 1023 /* largest valid exponent */
32#define DOUBLE_Ebias 1023 31#define DOUBLE_Ebias 1023
33#define DOUBLE_Emin (-1022) /* smallest valid exponent */ 32#define DOUBLE_Emin (-1022) /* smallest valid exponent */
34 33
35#define SINGLE_Emax 127 /* largest valid exponent */ 34#define SINGLE_Emax 127 /* largest valid exponent */
36#define SINGLE_Ebias 127 35#define SINGLE_Ebias 127
37#define SINGLE_Emin (-126) /* smallest valid exponent */ 36#define SINGLE_Emin (-126) /* smallest valid exponent */
38
39 37
40static u_char normalize_no_excep(FPU_REG *r, int exp, int sign) 38static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
41{ 39{
42 u_char tag; 40 u_char tag;
43 41
44 setexponent16(r, exp); 42 setexponent16(r, exp);
45 43
46 tag = FPU_normalize_nuo(r); 44 tag = FPU_normalize_nuo(r);
47 stdexp(r); 45 stdexp(r);
48 if ( sign ) 46 if (sign)
49 setnegative(r); 47 setnegative(r);
50 48
51 return tag; 49 return tag;
52} 50}
53 51
54
55int FPU_tagof(FPU_REG *ptr) 52int FPU_tagof(FPU_REG *ptr)
56{ 53{
57 int exp; 54 int exp;
58 55
59 exp = exponent16(ptr) & 0x7fff; 56 exp = exponent16(ptr) & 0x7fff;
60 if ( exp == 0 ) 57 if (exp == 0) {
61 { 58 if (!(ptr->sigh | ptr->sigl)) {
62 if ( !(ptr->sigh | ptr->sigl) ) 59 return TAG_Zero;
63 { 60 }
64 return TAG_Zero; 61 /* The number is a de-normal or pseudodenormal. */
62 return TAG_Special;
63 }
64
65 if (exp == 0x7fff) {
66 /* Is an Infinity, a NaN, or an unsupported data type. */
67 return TAG_Special;
65 } 68 }
66 /* The number is a de-normal or pseudodenormal. */
67 return TAG_Special;
68 }
69
70 if ( exp == 0x7fff )
71 {
72 /* Is an Infinity, a NaN, or an unsupported data type. */
73 return TAG_Special;
74 }
75
76 if ( !(ptr->sigh & 0x80000000) )
77 {
78 /* Unsupported data type. */
79 /* Valid numbers have the ms bit set to 1. */
80 /* Unnormal. */
81 return TAG_Special;
82 }
83
84 return TAG_Valid;
85}
86 69
70 if (!(ptr->sigh & 0x80000000)) {
71 /* Unsupported data type. */
72 /* Valid numbers have the ms bit set to 1. */
73 /* Unnormal. */
74 return TAG_Special;
75 }
76
77 return TAG_Valid;
78}
87 79
88/* Get a long double from user memory */ 80/* Get a long double from user memory */
89int FPU_load_extended(long double __user *s, int stnr) 81int FPU_load_extended(long double __user *s, int stnr)
90{ 82{
91 FPU_REG *sti_ptr = &st(stnr); 83 FPU_REG *sti_ptr = &st(stnr);
92 84
93 RE_ENTRANT_CHECK_OFF; 85 RE_ENTRANT_CHECK_OFF;
94 FPU_access_ok(VERIFY_READ, s, 10); 86 FPU_access_ok(VERIFY_READ, s, 10);
95 __copy_from_user(sti_ptr, s, 10); 87 __copy_from_user(sti_ptr, s, 10);
96 RE_ENTRANT_CHECK_ON; 88 RE_ENTRANT_CHECK_ON;
97 89
98 return FPU_tagof(sti_ptr); 90 return FPU_tagof(sti_ptr);
99} 91}
100 92
101
102/* Get a double from user memory */ 93/* Get a double from user memory */
103int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data) 94int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data)
104{ 95{
105 int exp, tag, negative; 96 int exp, tag, negative;
106 unsigned m64, l64; 97 unsigned m64, l64;
107 98
108 RE_ENTRANT_CHECK_OFF; 99 RE_ENTRANT_CHECK_OFF;
109 FPU_access_ok(VERIFY_READ, dfloat, 8); 100 FPU_access_ok(VERIFY_READ, dfloat, 8);
110 FPU_get_user(m64, 1 + (unsigned long __user *) dfloat); 101 FPU_get_user(m64, 1 + (unsigned long __user *)dfloat);
111 FPU_get_user(l64, (unsigned long __user *) dfloat); 102 FPU_get_user(l64, (unsigned long __user *)dfloat);
112 RE_ENTRANT_CHECK_ON; 103 RE_ENTRANT_CHECK_ON;
113 104
114 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive; 105 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
115 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias; 106 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
116 m64 &= 0xfffff; 107 m64 &= 0xfffff;
117 if ( exp > DOUBLE_Emax + EXTENDED_Ebias ) 108 if (exp > DOUBLE_Emax + EXTENDED_Ebias) {
118 { 109 /* Infinity or NaN */
119 /* Infinity or NaN */ 110 if ((m64 == 0) && (l64 == 0)) {
120 if ((m64 == 0) && (l64 == 0)) 111 /* +- infinity */
121 { 112 loaded_data->sigh = 0x80000000;
122 /* +- infinity */ 113 loaded_data->sigl = 0x00000000;
123 loaded_data->sigh = 0x80000000; 114 exp = EXP_Infinity + EXTENDED_Ebias;
124 loaded_data->sigl = 0x00000000; 115 tag = TAG_Special;
125 exp = EXP_Infinity + EXTENDED_Ebias; 116 } else {
126 tag = TAG_Special; 117 /* Must be a signaling or quiet NaN */
127 } 118 exp = EXP_NaN + EXTENDED_Ebias;
128 else 119 loaded_data->sigh = (m64 << 11) | 0x80000000;
129 { 120 loaded_data->sigh |= l64 >> 21;
130 /* Must be a signaling or quiet NaN */ 121 loaded_data->sigl = l64 << 11;
131 exp = EXP_NaN + EXTENDED_Ebias; 122 tag = TAG_Special; /* The calling function must look for NaNs */
132 loaded_data->sigh = (m64 << 11) | 0x80000000; 123 }
133 loaded_data->sigh |= l64 >> 21; 124 } else if (exp < DOUBLE_Emin + EXTENDED_Ebias) {
134 loaded_data->sigl = l64 << 11; 125 /* Zero or de-normal */
135 tag = TAG_Special; /* The calling function must look for NaNs */ 126 if ((m64 == 0) && (l64 == 0)) {
136 } 127 /* Zero */
137 } 128 reg_copy(&CONST_Z, loaded_data);
138 else if ( exp < DOUBLE_Emin + EXTENDED_Ebias ) 129 exp = 0;
139 { 130 tag = TAG_Zero;
140 /* Zero or de-normal */ 131 } else {
141 if ((m64 == 0) && (l64 == 0)) 132 /* De-normal */
142 { 133 loaded_data->sigh = m64 << 11;
143 /* Zero */ 134 loaded_data->sigh |= l64 >> 21;
144 reg_copy(&CONST_Z, loaded_data); 135 loaded_data->sigl = l64 << 11;
145 exp = 0; 136
146 tag = TAG_Zero; 137 return normalize_no_excep(loaded_data, DOUBLE_Emin,
147 } 138 negative)
148 else 139 | (denormal_operand() < 0 ? FPU_Exception : 0);
149 { 140 }
150 /* De-normal */ 141 } else {
151 loaded_data->sigh = m64 << 11; 142 loaded_data->sigh = (m64 << 11) | 0x80000000;
152 loaded_data->sigh |= l64 >> 21; 143 loaded_data->sigh |= l64 >> 21;
153 loaded_data->sigl = l64 << 11; 144 loaded_data->sigl = l64 << 11;
154
155 return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
156 | (denormal_operand() < 0 ? FPU_Exception : 0);
157 }
158 }
159 else
160 {
161 loaded_data->sigh = (m64 << 11) | 0x80000000;
162 loaded_data->sigh |= l64 >> 21;
163 loaded_data->sigl = l64 << 11;
164 145
165 tag = TAG_Valid; 146 tag = TAG_Valid;
166 } 147 }
167 148
168 setexponent16(loaded_data, exp | negative); 149 setexponent16(loaded_data, exp | negative);
169 150
170 return tag; 151 return tag;
171} 152}
172 153
173
174/* Get a float from user memory */ 154/* Get a float from user memory */
175int FPU_load_single(float __user *single, FPU_REG *loaded_data) 155int FPU_load_single(float __user *single, FPU_REG *loaded_data)
176{ 156{
177 unsigned m32; 157 unsigned m32;
178 int exp, tag, negative; 158 int exp, tag, negative;
179 159
180 RE_ENTRANT_CHECK_OFF; 160 RE_ENTRANT_CHECK_OFF;
181 FPU_access_ok(VERIFY_READ, single, 4); 161 FPU_access_ok(VERIFY_READ, single, 4);
182 FPU_get_user(m32, (unsigned long __user *) single); 162 FPU_get_user(m32, (unsigned long __user *)single);
183 RE_ENTRANT_CHECK_ON; 163 RE_ENTRANT_CHECK_ON;
184 164
185 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive; 165 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
186 166
187 if (!(m32 & 0x7fffffff)) 167 if (!(m32 & 0x7fffffff)) {
188 { 168 /* Zero */
189 /* Zero */ 169 reg_copy(&CONST_Z, loaded_data);
190 reg_copy(&CONST_Z, loaded_data); 170 addexponent(loaded_data, negative);
191 addexponent(loaded_data, negative); 171 return TAG_Zero;
192 return TAG_Zero;
193 }
194 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
195 m32 = (m32 & 0x7fffff) << 8;
196 if ( exp < SINGLE_Emin + EXTENDED_Ebias )
197 {
198 /* De-normals */
199 loaded_data->sigh = m32;
200 loaded_data->sigl = 0;
201
202 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
203 | (denormal_operand() < 0 ? FPU_Exception : 0);
204 }
205 else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
206 {
207 /* Infinity or NaN */
208 if ( m32 == 0 )
209 {
210 /* +- infinity */
211 loaded_data->sigh = 0x80000000;
212 loaded_data->sigl = 0x00000000;
213 exp = EXP_Infinity + EXTENDED_Ebias;
214 tag = TAG_Special;
215 } 172 }
216 else 173 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
217 { 174 m32 = (m32 & 0x7fffff) << 8;
218 /* Must be a signaling or quiet NaN */ 175 if (exp < SINGLE_Emin + EXTENDED_Ebias) {
219 exp = EXP_NaN + EXTENDED_Ebias; 176 /* De-normals */
220 loaded_data->sigh = m32 | 0x80000000; 177 loaded_data->sigh = m32;
221 loaded_data->sigl = 0; 178 loaded_data->sigl = 0;
222 tag = TAG_Special; /* The calling function must look for NaNs */ 179
180 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
181 | (denormal_operand() < 0 ? FPU_Exception : 0);
182 } else if (exp > SINGLE_Emax + EXTENDED_Ebias) {
183 /* Infinity or NaN */
184 if (m32 == 0) {
185 /* +- infinity */
186 loaded_data->sigh = 0x80000000;
187 loaded_data->sigl = 0x00000000;
188 exp = EXP_Infinity + EXTENDED_Ebias;
189 tag = TAG_Special;
190 } else {
191 /* Must be a signaling or quiet NaN */
192 exp = EXP_NaN + EXTENDED_Ebias;
193 loaded_data->sigh = m32 | 0x80000000;
194 loaded_data->sigl = 0;
195 tag = TAG_Special; /* The calling function must look for NaNs */
196 }
197 } else {
198 loaded_data->sigh = m32 | 0x80000000;
199 loaded_data->sigl = 0;
200 tag = TAG_Valid;
223 } 201 }
224 }
225 else
226 {
227 loaded_data->sigh = m32 | 0x80000000;
228 loaded_data->sigl = 0;
229 tag = TAG_Valid;
230 }
231 202
232 setexponent16(loaded_data, exp | negative); /* Set the sign. */ 203 setexponent16(loaded_data, exp | negative); /* Set the sign. */
233 204
234 return tag; 205 return tag;
235} 206}
236 207
237
238/* Get a long long from user memory */ 208/* Get a long long from user memory */
239int FPU_load_int64(long long __user *_s) 209int FPU_load_int64(long long __user *_s)
240{ 210{
241 long long s; 211 long long s;
242 int sign; 212 int sign;
243 FPU_REG *st0_ptr = &st(0); 213 FPU_REG *st0_ptr = &st(0);
244 214
245 RE_ENTRANT_CHECK_OFF; 215 RE_ENTRANT_CHECK_OFF;
246 FPU_access_ok(VERIFY_READ, _s, 8); 216 FPU_access_ok(VERIFY_READ, _s, 8);
247 if (copy_from_user(&s,_s,8)) 217 if (copy_from_user(&s, _s, 8))
248 FPU_abort; 218 FPU_abort;
249 RE_ENTRANT_CHECK_ON; 219 RE_ENTRANT_CHECK_ON;
250 220
251 if (s == 0) 221 if (s == 0) {
252 { 222 reg_copy(&CONST_Z, st0_ptr);
253 reg_copy(&CONST_Z, st0_ptr); 223 return TAG_Zero;
254 return TAG_Zero; 224 }
255 } 225
256 226 if (s > 0)
257 if (s > 0) 227 sign = SIGN_Positive;
258 sign = SIGN_Positive; 228 else {
259 else 229 s = -s;
260 { 230 sign = SIGN_Negative;
261 s = -s; 231 }
262 sign = SIGN_Negative;
263 }
264
265 significand(st0_ptr) = s;
266
267 return normalize_no_excep(st0_ptr, 63, sign);
268}
269 232
233 significand(st0_ptr) = s;
234
235 return normalize_no_excep(st0_ptr, 63, sign);
236}
270 237
271/* Get a long from user memory */ 238/* Get a long from user memory */
272int FPU_load_int32(long __user *_s, FPU_REG *loaded_data) 239int FPU_load_int32(long __user *_s, FPU_REG *loaded_data)
273{ 240{
274 long s; 241 long s;
275 int negative; 242 int negative;
276 243
277 RE_ENTRANT_CHECK_OFF; 244 RE_ENTRANT_CHECK_OFF;
278 FPU_access_ok(VERIFY_READ, _s, 4); 245 FPU_access_ok(VERIFY_READ, _s, 4);
279 FPU_get_user(s, _s); 246 FPU_get_user(s, _s);
280 RE_ENTRANT_CHECK_ON; 247 RE_ENTRANT_CHECK_ON;
281 248
282 if (s == 0) 249 if (s == 0) {
283 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; } 250 reg_copy(&CONST_Z, loaded_data);
251 return TAG_Zero;
252 }
284 253
285 if (s > 0) 254 if (s > 0)
286 negative = SIGN_Positive; 255 negative = SIGN_Positive;
287 else 256 else {
288 { 257 s = -s;
289 s = -s; 258 negative = SIGN_Negative;
290 negative = SIGN_Negative; 259 }
291 }
292 260
293 loaded_data->sigh = s; 261 loaded_data->sigh = s;
294 loaded_data->sigl = 0; 262 loaded_data->sigl = 0;
295 263
296 return normalize_no_excep(loaded_data, 31, negative); 264 return normalize_no_excep(loaded_data, 31, negative);
297} 265}
298 266
299
300/* Get a short from user memory */ 267/* Get a short from user memory */
301int FPU_load_int16(short __user *_s, FPU_REG *loaded_data) 268int FPU_load_int16(short __user *_s, FPU_REG *loaded_data)
302{ 269{
303 int s, negative; 270 int s, negative;
304 271
305 RE_ENTRANT_CHECK_OFF; 272 RE_ENTRANT_CHECK_OFF;
306 FPU_access_ok(VERIFY_READ, _s, 2); 273 FPU_access_ok(VERIFY_READ, _s, 2);
307 /* Cast as short to get the sign extended. */ 274 /* Cast as short to get the sign extended. */
308 FPU_get_user(s, _s); 275 FPU_get_user(s, _s);
309 RE_ENTRANT_CHECK_ON; 276 RE_ENTRANT_CHECK_ON;
310 277
311 if (s == 0) 278 if (s == 0) {
312 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; } 279 reg_copy(&CONST_Z, loaded_data);
280 return TAG_Zero;
281 }
313 282
314 if (s > 0) 283 if (s > 0)
315 negative = SIGN_Positive; 284 negative = SIGN_Positive;
316 else 285 else {
317 { 286 s = -s;
318 s = -s; 287 negative = SIGN_Negative;
319 negative = SIGN_Negative; 288 }
320 }
321 289
322 loaded_data->sigh = s << 16; 290 loaded_data->sigh = s << 16;
323 loaded_data->sigl = 0; 291 loaded_data->sigl = 0;
324 292
325 return normalize_no_excep(loaded_data, 15, negative); 293 return normalize_no_excep(loaded_data, 15, negative);
326} 294}
327 295
328
329/* Get a packed bcd array from user memory */ 296/* Get a packed bcd array from user memory */
330int FPU_load_bcd(u_char __user *s) 297int FPU_load_bcd(u_char __user *s)
331{ 298{
332 FPU_REG *st0_ptr = &st(0); 299 FPU_REG *st0_ptr = &st(0);
333 int pos; 300 int pos;
334 u_char bcd; 301 u_char bcd;
335 long long l=0; 302 long long l = 0;
336 int sign; 303 int sign;
337 304
338 RE_ENTRANT_CHECK_OFF; 305 RE_ENTRANT_CHECK_OFF;
339 FPU_access_ok(VERIFY_READ, s, 10); 306 FPU_access_ok(VERIFY_READ, s, 10);
340 RE_ENTRANT_CHECK_ON; 307 RE_ENTRANT_CHECK_ON;
341 for ( pos = 8; pos >= 0; pos--) 308 for (pos = 8; pos >= 0; pos--) {
342 { 309 l *= 10;
343 l *= 10; 310 RE_ENTRANT_CHECK_OFF;
344 RE_ENTRANT_CHECK_OFF; 311 FPU_get_user(bcd, s + pos);
345 FPU_get_user(bcd, s+pos); 312 RE_ENTRANT_CHECK_ON;
346 RE_ENTRANT_CHECK_ON; 313 l += bcd >> 4;
347 l += bcd >> 4; 314 l *= 10;
348 l *= 10; 315 l += bcd & 0x0f;
349 l += bcd & 0x0f; 316 }
350 } 317
351 318 RE_ENTRANT_CHECK_OFF;
352 RE_ENTRANT_CHECK_OFF; 319 FPU_get_user(sign, s + 9);
353 FPU_get_user(sign, s+9); 320 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
354 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive; 321 RE_ENTRANT_CHECK_ON;
355 RE_ENTRANT_CHECK_ON; 322
356 323 if (l == 0) {
357 if ( l == 0 ) 324 reg_copy(&CONST_Z, st0_ptr);
358 { 325 addexponent(st0_ptr, sign); /* Set the sign. */
359 reg_copy(&CONST_Z, st0_ptr); 326 return TAG_Zero;
360 addexponent(st0_ptr, sign); /* Set the sign. */ 327 } else {
361 return TAG_Zero; 328 significand(st0_ptr) = l;
362 } 329 return normalize_no_excep(st0_ptr, 63, sign);
363 else 330 }
364 {
365 significand(st0_ptr) = l;
366 return normalize_no_excep(st0_ptr, 63, sign);
367 }
368} 331}
369 332
370/*===========================================================================*/ 333/*===========================================================================*/
371 334
372/* Put a long double into user memory */ 335/* Put a long double into user memory */
373int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double __user *d) 336int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
337 long double __user * d)
374{ 338{
375 /* 339 /*
376 The only exception raised by an attempt to store to an 340 The only exception raised by an attempt to store to an
377 extended format is the Invalid Stack exception, i.e. 341 extended format is the Invalid Stack exception, i.e.
378 attempting to store from an empty register. 342 attempting to store from an empty register.
379 */ 343 */
380 344
381 if ( st0_tag != TAG_Empty ) 345 if (st0_tag != TAG_Empty) {
382 { 346 RE_ENTRANT_CHECK_OFF;
383 RE_ENTRANT_CHECK_OFF; 347 FPU_access_ok(VERIFY_WRITE, d, 10);
384 FPU_access_ok(VERIFY_WRITE, d, 10); 348
385 349 FPU_put_user(st0_ptr->sigl, (unsigned long __user *)d);
386 FPU_put_user(st0_ptr->sigl, (unsigned long __user *) d); 350 FPU_put_user(st0_ptr->sigh,
387 FPU_put_user(st0_ptr->sigh, (unsigned long __user *) ((u_char __user *)d + 4)); 351 (unsigned long __user *)((u_char __user *) d + 4));
388 FPU_put_user(exponent16(st0_ptr), (unsigned short __user *) ((u_char __user *)d + 8)); 352 FPU_put_user(exponent16(st0_ptr),
389 RE_ENTRANT_CHECK_ON; 353 (unsigned short __user *)((u_char __user *) d +
390 354 8));
391 return 1; 355 RE_ENTRANT_CHECK_ON;
392 } 356
393 357 return 1;
394 /* Empty register (stack underflow) */ 358 }
395 EXCEPTION(EX_StackUnder);
396 if ( control_word & CW_Invalid )
397 {
398 /* The masked response */
399 /* Put out the QNaN indefinite */
400 RE_ENTRANT_CHECK_OFF;
401 FPU_access_ok(VERIFY_WRITE,d,10);
402 FPU_put_user(0, (unsigned long __user *) d);
403 FPU_put_user(0xc0000000, 1 + (unsigned long __user *) d);
404 FPU_put_user(0xffff, 4 + (short __user *) d);
405 RE_ENTRANT_CHECK_ON;
406 return 1;
407 }
408 else
409 return 0;
410 359
411} 360 /* Empty register (stack underflow) */
361 EXCEPTION(EX_StackUnder);
362 if (control_word & CW_Invalid) {
363 /* The masked response */
364 /* Put out the QNaN indefinite */
365 RE_ENTRANT_CHECK_OFF;
366 FPU_access_ok(VERIFY_WRITE, d, 10);
367 FPU_put_user(0, (unsigned long __user *)d);
368 FPU_put_user(0xc0000000, 1 + (unsigned long __user *)d);
369 FPU_put_user(0xffff, 4 + (short __user *)d);
370 RE_ENTRANT_CHECK_ON;
371 return 1;
372 } else
373 return 0;
412 374
375}
413 376
414/* Put a double into user memory */ 377/* Put a double into user memory */
415int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat) 378int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
416{ 379{
417 unsigned long l[2]; 380 unsigned long l[2];
418 unsigned long increment = 0; /* avoid gcc warnings */ 381 unsigned long increment = 0; /* avoid gcc warnings */
419 int precision_loss; 382 int precision_loss;
420 int exp; 383 int exp;
421 FPU_REG tmp; 384 FPU_REG tmp;
422 385
423 if ( st0_tag == TAG_Valid ) 386 if (st0_tag == TAG_Valid) {
424 { 387 reg_copy(st0_ptr, &tmp);
425 reg_copy(st0_ptr, &tmp); 388 exp = exponent(&tmp);
426 exp = exponent(&tmp);
427 389
428 if ( exp < DOUBLE_Emin ) /* It may be a denormal */ 390 if (exp < DOUBLE_Emin) { /* It may be a denormal */
429 { 391 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
430 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
431 392
432 denormal_arg: 393 denormal_arg:
433 394
434 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) 395 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
435 {
436#ifdef PECULIAR_486 396#ifdef PECULIAR_486
437 /* Did it round to a non-denormal ? */ 397 /* Did it round to a non-denormal ? */
438 /* This behaviour might be regarded as peculiar, it appears 398 /* This behaviour might be regarded as peculiar, it appears
439 that the 80486 rounds to the dest precision, then 399 that the 80486 rounds to the dest precision, then
440 converts to decide underflow. */ 400 converts to decide underflow. */
441 if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && 401 if (!
442 (st0_ptr->sigl & 0x000007ff)) ) 402 ((tmp.sigh == 0x00100000) && (tmp.sigl == 0)
403 && (st0_ptr->sigl & 0x000007ff)))
443#endif /* PECULIAR_486 */ 404#endif /* PECULIAR_486 */
444 { 405 {
445 EXCEPTION(EX_Underflow); 406 EXCEPTION(EX_Underflow);
446 /* This is a special case: see sec 16.2.5.1 of 407 /* This is a special case: see sec 16.2.5.1 of
447 the 80486 book */ 408 the 80486 book */
448 if ( !(control_word & CW_Underflow) ) 409 if (!(control_word & CW_Underflow))
449 return 0; 410 return 0;
450 } 411 }
451 EXCEPTION(precision_loss); 412 EXCEPTION(precision_loss);
452 if ( !(control_word & CW_Precision) ) 413 if (!(control_word & CW_Precision))
453 return 0; 414 return 0;
454 }
455 l[0] = tmp.sigl;
456 l[1] = tmp.sigh;
457 }
458 else
459 {
460 if ( tmp.sigl & 0x000007ff )
461 {
462 precision_loss = 1;
463 switch (control_word & CW_RC)
464 {
465 case RC_RND:
466 /* Rounding can get a little messy.. */
467 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
468 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
469 break;
470 case RC_DOWN: /* towards -infinity */
471 increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
472 break;
473 case RC_UP: /* towards +infinity */
474 increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
475 break;
476 case RC_CHOP:
477 increment = 0;
478 break;
479 }
480
481 /* Truncate the mantissa */
482 tmp.sigl &= 0xfffff800;
483
484 if ( increment )
485 {
486 if ( tmp.sigl >= 0xfffff800 )
487 {
488 /* the sigl part overflows */
489 if ( tmp.sigh == 0xffffffff )
490 {
491 /* The sigh part overflows */
492 tmp.sigh = 0x80000000;
493 exp++;
494 if (exp >= EXP_OVER)
495 goto overflow;
496 } 415 }
497 else 416 l[0] = tmp.sigl;
498 { 417 l[1] = tmp.sigh;
499 tmp.sigh ++; 418 } else {
419 if (tmp.sigl & 0x000007ff) {
420 precision_loss = 1;
421 switch (control_word & CW_RC) {
422 case RC_RND:
423 /* Rounding can get a little messy.. */
424 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
425 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
426 break;
427 case RC_DOWN: /* towards -infinity */
428 increment =
429 signpositive(&tmp) ? 0 : tmp.
430 sigl & 0x7ff;
431 break;
432 case RC_UP: /* towards +infinity */
433 increment =
434 signpositive(&tmp) ? tmp.
435 sigl & 0x7ff : 0;
436 break;
437 case RC_CHOP:
438 increment = 0;
439 break;
440 }
441
442 /* Truncate the mantissa */
443 tmp.sigl &= 0xfffff800;
444
445 if (increment) {
446 if (tmp.sigl >= 0xfffff800) {
447 /* the sigl part overflows */
448 if (tmp.sigh == 0xffffffff) {
449 /* The sigh part overflows */
450 tmp.sigh = 0x80000000;
451 exp++;
452 if (exp >= EXP_OVER)
453 goto overflow;
454 } else {
455 tmp.sigh++;
456 }
457 tmp.sigl = 0x00000000;
458 } else {
459 /* We only need to increment sigl */
460 tmp.sigl += 0x00000800;
461 }
462 }
463 } else
464 precision_loss = 0;
465
466 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
467 l[1] = ((tmp.sigh >> 11) & 0xfffff);
468
469 if (exp > DOUBLE_Emax) {
470 overflow:
471 EXCEPTION(EX_Overflow);
472 if (!(control_word & CW_Overflow))
473 return 0;
474 set_precision_flag_up();
475 if (!(control_word & CW_Precision))
476 return 0;
477
478 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
479 /* Overflow to infinity */
480 l[0] = 0x00000000; /* Set to */
481 l[1] = 0x7ff00000; /* + INF */
482 } else {
483 if (precision_loss) {
484 if (increment)
485 set_precision_flag_up();
486 else
487 set_precision_flag_down();
488 }
489 /* Add the exponent */
490 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
500 } 491 }
501 tmp.sigl = 0x00000000;
502 }
503 else
504 {
505 /* We only need to increment sigl */
506 tmp.sigl += 0x00000800;
507 }
508 }
509 }
510 else
511 precision_loss = 0;
512
513 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
514 l[1] = ((tmp.sigh >> 11) & 0xfffff);
515
516 if ( exp > DOUBLE_Emax )
517 {
518 overflow:
519 EXCEPTION(EX_Overflow);
520 if ( !(control_word & CW_Overflow) )
521 return 0;
522 set_precision_flag_up();
523 if ( !(control_word & CW_Precision) )
524 return 0;
525
526 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
527 /* Overflow to infinity */
528 l[0] = 0x00000000; /* Set to */
529 l[1] = 0x7ff00000; /* + INF */
530 }
531 else
532 {
533 if ( precision_loss )
534 {
535 if ( increment )
536 set_precision_flag_up();
537 else
538 set_precision_flag_down();
539 } 492 }
540 /* Add the exponent */ 493 } else if (st0_tag == TAG_Zero) {
541 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); 494 /* Number is zero */
542 } 495 l[0] = 0;
543 } 496 l[1] = 0;
544 } 497 } else if (st0_tag == TAG_Special) {
545 else if (st0_tag == TAG_Zero) 498 st0_tag = FPU_Special(st0_ptr);
546 { 499 if (st0_tag == TW_Denormal) {
547 /* Number is zero */ 500 /* A denormal will always underflow. */
548 l[0] = 0;
549 l[1] = 0;
550 }
551 else if ( st0_tag == TAG_Special )
552 {
553 st0_tag = FPU_Special(st0_ptr);
554 if ( st0_tag == TW_Denormal )
555 {
556 /* A denormal will always underflow. */
557#ifndef PECULIAR_486 501#ifndef PECULIAR_486
558 /* An 80486 is supposed to be able to generate 502 /* An 80486 is supposed to be able to generate
559 a denormal exception here, but... */ 503 a denormal exception here, but... */
560 /* Underflow has priority. */ 504 /* Underflow has priority. */
561 if ( control_word & CW_Underflow ) 505 if (control_word & CW_Underflow)
562 denormal_operand(); 506 denormal_operand();
563#endif /* PECULIAR_486 */ 507#endif /* PECULIAR_486 */
564 reg_copy(st0_ptr, &tmp); 508 reg_copy(st0_ptr, &tmp);
565 goto denormal_arg; 509 goto denormal_arg;
566 } 510 } else if (st0_tag == TW_Infinity) {
567 else if (st0_tag == TW_Infinity) 511 l[0] = 0;
568 { 512 l[1] = 0x7ff00000;
569 l[0] = 0; 513 } else if (st0_tag == TW_NaN) {
570 l[1] = 0x7ff00000; 514 /* Is it really a NaN ? */
571 } 515 if ((exponent(st0_ptr) == EXP_OVER)
572 else if (st0_tag == TW_NaN) 516 && (st0_ptr->sigh & 0x80000000)) {
573 { 517 /* See if we can get a valid NaN from the FPU_REG */
574 /* Is it really a NaN ? */ 518 l[0] =
575 if ( (exponent(st0_ptr) == EXP_OVER) 519 (st0_ptr->sigl >> 11) | (st0_ptr->
576 && (st0_ptr->sigh & 0x80000000) ) 520 sigh << 21);
577 { 521 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
578 /* See if we can get a valid NaN from the FPU_REG */ 522 if (!(st0_ptr->sigh & 0x40000000)) {
579 l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21); 523 /* It is a signalling NaN */
580 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); 524 EXCEPTION(EX_Invalid);
581 if ( !(st0_ptr->sigh & 0x40000000) ) 525 if (!(control_word & CW_Invalid))
582 { 526 return 0;
583 /* It is a signalling NaN */ 527 l[1] |= (0x40000000 >> 11);
584 EXCEPTION(EX_Invalid); 528 }
585 if ( !(control_word & CW_Invalid) ) 529 l[1] |= 0x7ff00000;
586 return 0; 530 } else {
587 l[1] |= (0x40000000 >> 11); 531 /* It is an unsupported data type */
532 EXCEPTION(EX_Invalid);
533 if (!(control_word & CW_Invalid))
534 return 0;
535 l[0] = 0;
536 l[1] = 0xfff80000;
537 }
588 } 538 }
589 l[1] |= 0x7ff00000; 539 } else if (st0_tag == TAG_Empty) {
590 } 540 /* Empty register (stack underflow) */
591 else 541 EXCEPTION(EX_StackUnder);
592 { 542 if (control_word & CW_Invalid) {
593 /* It is an unsupported data type */ 543 /* The masked response */
594 EXCEPTION(EX_Invalid); 544 /* Put out the QNaN indefinite */
595 if ( !(control_word & CW_Invalid) ) 545 RE_ENTRANT_CHECK_OFF;
596 return 0; 546 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
597 l[0] = 0; 547 FPU_put_user(0, (unsigned long __user *)dfloat);
598 l[1] = 0xfff80000; 548 FPU_put_user(0xfff80000,
599 } 549 1 + (unsigned long __user *)dfloat);
550 RE_ENTRANT_CHECK_ON;
551 return 1;
552 } else
553 return 0;
600 } 554 }
601 } 555 if (getsign(st0_ptr))
602 else if ( st0_tag == TAG_Empty ) 556 l[1] |= 0x80000000;
603 {
604 /* Empty register (stack underflow) */
605 EXCEPTION(EX_StackUnder);
606 if ( control_word & CW_Invalid )
607 {
608 /* The masked response */
609 /* Put out the QNaN indefinite */
610 RE_ENTRANT_CHECK_OFF;
611 FPU_access_ok(VERIFY_WRITE,dfloat,8);
612 FPU_put_user(0, (unsigned long __user *) dfloat);
613 FPU_put_user(0xfff80000, 1 + (unsigned long __user *) dfloat);
614 RE_ENTRANT_CHECK_ON;
615 return 1;
616 }
617 else
618 return 0;
619 }
620 if ( getsign(st0_ptr) )
621 l[1] |= 0x80000000;
622
623 RE_ENTRANT_CHECK_OFF;
624 FPU_access_ok(VERIFY_WRITE,dfloat,8);
625 FPU_put_user(l[0], (unsigned long __user *)dfloat);
626 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
627 RE_ENTRANT_CHECK_ON;
628
629 return 1;
630}
631 557
558 RE_ENTRANT_CHECK_OFF;
559 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
560 FPU_put_user(l[0], (unsigned long __user *)dfloat);
561 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
562 RE_ENTRANT_CHECK_ON;
563
564 return 1;
565}
632 566
633/* Put a float into user memory */ 567/* Put a float into user memory */
634int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single) 568int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
635{ 569{
636 long templ = 0; 570 long templ = 0;
637 unsigned long increment = 0; /* avoid gcc warnings */ 571 unsigned long increment = 0; /* avoid gcc warnings */
638 int precision_loss; 572 int precision_loss;
639 int exp; 573 int exp;
640 FPU_REG tmp; 574 FPU_REG tmp;
641 575
642 if ( st0_tag == TAG_Valid ) 576 if (st0_tag == TAG_Valid) {
643 {
644 577
645 reg_copy(st0_ptr, &tmp); 578 reg_copy(st0_ptr, &tmp);
646 exp = exponent(&tmp); 579 exp = exponent(&tmp);
647 580
648 if ( exp < SINGLE_Emin ) 581 if (exp < SINGLE_Emin) {
649 { 582 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
650 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
651 583
652 denormal_arg: 584 denormal_arg:
653 585
654 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) 586 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
655 {
656#ifdef PECULIAR_486 587#ifdef PECULIAR_486
657 /* Did it round to a non-denormal ? */ 588 /* Did it round to a non-denormal ? */
658 /* This behaviour might be regarded as peculiar, it appears 589 /* This behaviour might be regarded as peculiar, it appears
659 that the 80486 rounds to the dest precision, then 590 that the 80486 rounds to the dest precision, then
660 converts to decide underflow. */ 591 converts to decide underflow. */
661 if ( !((tmp.sigl == 0x00800000) && 592 if (!((tmp.sigl == 0x00800000) &&
662 ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) ) 593 ((st0_ptr->sigh & 0x000000ff)
594 || st0_ptr->sigl)))
663#endif /* PECULIAR_486 */ 595#endif /* PECULIAR_486 */
664 { 596 {
665 EXCEPTION(EX_Underflow); 597 EXCEPTION(EX_Underflow);
666 /* This is a special case: see sec 16.2.5.1 of 598 /* This is a special case: see sec 16.2.5.1 of
667 the 80486 book */ 599 the 80486 book */
668 if ( !(control_word & CW_Underflow) ) 600 if (!(control_word & CW_Underflow))
669 return 0; 601 return 0;
670 } 602 }
671 EXCEPTION(precision_loss); 603 EXCEPTION(precision_loss);
672 if ( !(control_word & CW_Precision) ) 604 if (!(control_word & CW_Precision))
673 return 0; 605 return 0;
674 } 606 }
675 templ = tmp.sigl; 607 templ = tmp.sigl;
676 } 608 } else {
677 else 609 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
678 { 610 unsigned long sigh = tmp.sigh;
679 if ( tmp.sigl | (tmp.sigh & 0x000000ff) ) 611 unsigned long sigl = tmp.sigl;
680 { 612
681 unsigned long sigh = tmp.sigh; 613 precision_loss = 1;
682 unsigned long sigl = tmp.sigl; 614 switch (control_word & CW_RC) {
683 615 case RC_RND:
684 precision_loss = 1; 616 increment = ((sigh & 0xff) > 0x80) /* more than half */
685 switch (control_word & CW_RC) 617 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
686 { 618 ||((sigh & 0x180) == 0x180); /* round to even */
687 case RC_RND: 619 break;
688 increment = ((sigh & 0xff) > 0x80) /* more than half */ 620 case RC_DOWN: /* towards -infinity */
689 || (((sigh & 0xff) == 0x80) && sigl) /* more than half */ 621 increment = signpositive(&tmp)
690 || ((sigh & 0x180) == 0x180); /* round to even */ 622 ? 0 : (sigl | (sigh & 0xff));
691 break; 623 break;
692 case RC_DOWN: /* towards -infinity */ 624 case RC_UP: /* towards +infinity */
693 increment = signpositive(&tmp) 625 increment = signpositive(&tmp)
694 ? 0 : (sigl | (sigh & 0xff)); 626 ? (sigl | (sigh & 0xff)) : 0;
695 break; 627 break;
696 case RC_UP: /* towards +infinity */ 628 case RC_CHOP:
697 increment = signpositive(&tmp) 629 increment = 0;
698 ? (sigl | (sigh & 0xff)) : 0; 630 break;
699 break; 631 }
700 case RC_CHOP: 632
701 increment = 0; 633 /* Truncate part of the mantissa */
702 break; 634 tmp.sigl = 0;
703 } 635
704 636 if (increment) {
705 /* Truncate part of the mantissa */ 637 if (sigh >= 0xffffff00) {
706 tmp.sigl = 0; 638 /* The sigh part overflows */
707 639 tmp.sigh = 0x80000000;
708 if (increment) 640 exp++;
709 { 641 if (exp >= EXP_OVER)
710 if ( sigh >= 0xffffff00 ) 642 goto overflow;
711 { 643 } else {
712 /* The sigh part overflows */ 644 tmp.sigh &= 0xffffff00;
713 tmp.sigh = 0x80000000; 645 tmp.sigh += 0x100;
714 exp++; 646 }
715 if ( exp >= EXP_OVER ) 647 } else {
716 goto overflow; 648 tmp.sigh &= 0xffffff00; /* Finish the truncation */
717 } 649 }
718 else 650 } else
719 { 651 precision_loss = 0;
720 tmp.sigh &= 0xffffff00; 652
721 tmp.sigh += 0x100; 653 templ = (tmp.sigh >> 8) & 0x007fffff;
722 } 654
723 } 655 if (exp > SINGLE_Emax) {
724 else 656 overflow:
725 { 657 EXCEPTION(EX_Overflow);
726 tmp.sigh &= 0xffffff00; /* Finish the truncation */ 658 if (!(control_word & CW_Overflow))
727 } 659 return 0;
728 } 660 set_precision_flag_up();
729 else 661 if (!(control_word & CW_Precision))
730 precision_loss = 0; 662 return 0;
731 663
732 templ = (tmp.sigh >> 8) & 0x007fffff; 664 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
733 665 /* Masked response is overflow to infinity. */
734 if ( exp > SINGLE_Emax ) 666 templ = 0x7f800000;
735 { 667 } else {
736 overflow: 668 if (precision_loss) {
737 EXCEPTION(EX_Overflow); 669 if (increment)
738 if ( !(control_word & CW_Overflow) ) 670 set_precision_flag_up();
739 return 0; 671 else
740 set_precision_flag_up(); 672 set_precision_flag_down();
741 if ( !(control_word & CW_Precision) ) 673 }
742 return 0; 674 /* Add the exponent */
743 675 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
744 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */ 676 }
745 /* Masked response is overflow to infinity. */
746 templ = 0x7f800000;
747 }
748 else
749 {
750 if ( precision_loss )
751 {
752 if ( increment )
753 set_precision_flag_up();
754 else
755 set_precision_flag_down();
756 } 677 }
757 /* Add the exponent */ 678 } else if (st0_tag == TAG_Zero) {
758 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; 679 templ = 0;
759 } 680 } else if (st0_tag == TAG_Special) {
760 } 681 st0_tag = FPU_Special(st0_ptr);
761 } 682 if (st0_tag == TW_Denormal) {
762 else if (st0_tag == TAG_Zero) 683 reg_copy(st0_ptr, &tmp);
763 { 684
764 templ = 0; 685 /* A denormal will always underflow. */
765 }
766 else if ( st0_tag == TAG_Special )
767 {
768 st0_tag = FPU_Special(st0_ptr);
769 if (st0_tag == TW_Denormal)
770 {
771 reg_copy(st0_ptr, &tmp);
772
773 /* A denormal will always underflow. */
774#ifndef PECULIAR_486 686#ifndef PECULIAR_486
775 /* An 80486 is supposed to be able to generate 687 /* An 80486 is supposed to be able to generate
776 a denormal exception here, but... */ 688 a denormal exception here, but... */
777 /* Underflow has priority. */ 689 /* Underflow has priority. */
778 if ( control_word & CW_Underflow ) 690 if (control_word & CW_Underflow)
779 denormal_operand(); 691 denormal_operand();
780#endif /* PECULIAR_486 */ 692#endif /* PECULIAR_486 */
781 goto denormal_arg; 693 goto denormal_arg;
782 } 694 } else if (st0_tag == TW_Infinity) {
783 else if (st0_tag == TW_Infinity) 695 templ = 0x7f800000;
784 { 696 } else if (st0_tag == TW_NaN) {
785 templ = 0x7f800000; 697 /* Is it really a NaN ? */
786 } 698 if ((exponent(st0_ptr) == EXP_OVER)
787 else if (st0_tag == TW_NaN) 699 && (st0_ptr->sigh & 0x80000000)) {
788 { 700 /* See if we can get a valid NaN from the FPU_REG */
789 /* Is it really a NaN ? */ 701 templ = st0_ptr->sigh >> 8;
790 if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) ) 702 if (!(st0_ptr->sigh & 0x40000000)) {
791 { 703 /* It is a signalling NaN */
792 /* See if we can get a valid NaN from the FPU_REG */ 704 EXCEPTION(EX_Invalid);
793 templ = st0_ptr->sigh >> 8; 705 if (!(control_word & CW_Invalid))
794 if ( !(st0_ptr->sigh & 0x40000000) ) 706 return 0;
795 { 707 templ |= (0x40000000 >> 8);
796 /* It is a signalling NaN */ 708 }
797 EXCEPTION(EX_Invalid); 709 templ |= 0x7f800000;
798 if ( !(control_word & CW_Invalid) ) 710 } else {
799 return 0; 711 /* It is an unsupported data type */
800 templ |= (0x40000000 >> 8); 712 EXCEPTION(EX_Invalid);
713 if (!(control_word & CW_Invalid))
714 return 0;
715 templ = 0xffc00000;
716 }
801 } 717 }
802 templ |= 0x7f800000;
803 }
804 else
805 {
806 /* It is an unsupported data type */
807 EXCEPTION(EX_Invalid);
808 if ( !(control_word & CW_Invalid) )
809 return 0;
810 templ = 0xffc00000;
811 }
812 }
813#ifdef PARANOID 718#ifdef PARANOID
814 else 719 else {
815 { 720 EXCEPTION(EX_INTERNAL | 0x164);
816 EXCEPTION(EX_INTERNAL|0x164); 721 return 0;
817 return 0; 722 }
818 }
819#endif 723#endif
820 } 724 } else if (st0_tag == TAG_Empty) {
821 else if ( st0_tag == TAG_Empty ) 725 /* Empty register (stack underflow) */
822 { 726 EXCEPTION(EX_StackUnder);
823 /* Empty register (stack underflow) */ 727 if (control_word & EX_Invalid) {
824 EXCEPTION(EX_StackUnder); 728 /* The masked response */
825 if ( control_word & EX_Invalid ) 729 /* Put out the QNaN indefinite */
826 { 730 RE_ENTRANT_CHECK_OFF;
827 /* The masked response */ 731 FPU_access_ok(VERIFY_WRITE, single, 4);
828 /* Put out the QNaN indefinite */ 732 FPU_put_user(0xffc00000,
829 RE_ENTRANT_CHECK_OFF; 733 (unsigned long __user *)single);
830 FPU_access_ok(VERIFY_WRITE,single,4); 734 RE_ENTRANT_CHECK_ON;
831 FPU_put_user(0xffc00000, (unsigned long __user *) single); 735 return 1;
832 RE_ENTRANT_CHECK_ON; 736 } else
833 return 1; 737 return 0;
834 } 738 }
835 else
836 return 0;
837 }
838#ifdef PARANOID 739#ifdef PARANOID
839 else 740 else {
840 { 741 EXCEPTION(EX_INTERNAL | 0x163);
841 EXCEPTION(EX_INTERNAL|0x163); 742 return 0;
842 return 0; 743 }
843 }
844#endif 744#endif
845 if ( getsign(st0_ptr) ) 745 if (getsign(st0_ptr))
846 templ |= 0x80000000; 746 templ |= 0x80000000;
847 747
848 RE_ENTRANT_CHECK_OFF; 748 RE_ENTRANT_CHECK_OFF;
849 FPU_access_ok(VERIFY_WRITE,single,4); 749 FPU_access_ok(VERIFY_WRITE, single, 4);
850 FPU_put_user(templ,(unsigned long __user *) single); 750 FPU_put_user(templ, (unsigned long __user *)single);
851 RE_ENTRANT_CHECK_ON; 751 RE_ENTRANT_CHECK_ON;
852 752
853 return 1; 753 return 1;
854} 754}
855 755
856
857/* Put a long long into user memory */ 756/* Put a long long into user memory */
858int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d) 757int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d)
859{ 758{
860 FPU_REG t; 759 FPU_REG t;
861 long long tll; 760 long long tll;
862 int precision_loss; 761 int precision_loss;
863 762
864 if ( st0_tag == TAG_Empty ) 763 if (st0_tag == TAG_Empty) {
865 { 764 /* Empty register (stack underflow) */
866 /* Empty register (stack underflow) */ 765 EXCEPTION(EX_StackUnder);
867 EXCEPTION(EX_StackUnder); 766 goto invalid_operand;
868 goto invalid_operand; 767 } else if (st0_tag == TAG_Special) {
869 } 768 st0_tag = FPU_Special(st0_ptr);
870 else if ( st0_tag == TAG_Special ) 769 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
871 { 770 EXCEPTION(EX_Invalid);
872 st0_tag = FPU_Special(st0_ptr); 771 goto invalid_operand;
873 if ( (st0_tag == TW_Infinity) || 772 }
874 (st0_tag == TW_NaN) )
875 {
876 EXCEPTION(EX_Invalid);
877 goto invalid_operand;
878 } 773 }
879 } 774
880 775 reg_copy(st0_ptr, &t);
881 reg_copy(st0_ptr, &t); 776 precision_loss = FPU_round_to_int(&t, st0_tag);
882 precision_loss = FPU_round_to_int(&t, st0_tag); 777 ((long *)&tll)[0] = t.sigl;
883 ((long *)&tll)[0] = t.sigl; 778 ((long *)&tll)[1] = t.sigh;
884 ((long *)&tll)[1] = t.sigh; 779 if ((precision_loss == 1) ||
885 if ( (precision_loss == 1) || 780 ((t.sigh & 0x80000000) &&
886 ((t.sigh & 0x80000000) && 781 !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t)))) {
887 !((t.sigh == 0x80000000) && (t.sigl == 0) && 782 EXCEPTION(EX_Invalid);
888 signnegative(&t))) ) 783 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
889 { 784 invalid_operand:
890 EXCEPTION(EX_Invalid); 785 if (control_word & EX_Invalid) {
891 /* This is a special case: see sec 16.2.5.1 of the 80486 book */ 786 /* Produce something like QNaN "indefinite" */
892 invalid_operand: 787 tll = 0x8000000000000000LL;
893 if ( control_word & EX_Invalid ) 788 } else
894 { 789 return 0;
895 /* Produce something like QNaN "indefinite" */ 790 } else {
896 tll = 0x8000000000000000LL; 791 if (precision_loss)
792 set_precision_flag(precision_loss);
793 if (signnegative(&t))
794 tll = -tll;
897 } 795 }
898 else
899 return 0;
900 }
901 else
902 {
903 if ( precision_loss )
904 set_precision_flag(precision_loss);
905 if ( signnegative(&t) )
906 tll = - tll;
907 }
908
909 RE_ENTRANT_CHECK_OFF;
910 FPU_access_ok(VERIFY_WRITE,d,8);
911 if (copy_to_user(d, &tll, 8))
912 FPU_abort;
913 RE_ENTRANT_CHECK_ON;
914
915 return 1;
916}
917 796
797 RE_ENTRANT_CHECK_OFF;
798 FPU_access_ok(VERIFY_WRITE, d, 8);
799 if (copy_to_user(d, &tll, 8))
800 FPU_abort;
801 RE_ENTRANT_CHECK_ON;
802
803 return 1;
804}
918 805
919/* Put a long into user memory */ 806/* Put a long into user memory */
920int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d) 807int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
921{ 808{
922 FPU_REG t; 809 FPU_REG t;
923 int precision_loss; 810 int precision_loss;
924 811
925 if ( st0_tag == TAG_Empty ) 812 if (st0_tag == TAG_Empty) {
926 { 813 /* Empty register (stack underflow) */
927 /* Empty register (stack underflow) */ 814 EXCEPTION(EX_StackUnder);
928 EXCEPTION(EX_StackUnder); 815 goto invalid_operand;
929 goto invalid_operand; 816 } else if (st0_tag == TAG_Special) {
930 } 817 st0_tag = FPU_Special(st0_ptr);
931 else if ( st0_tag == TAG_Special ) 818 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
932 { 819 EXCEPTION(EX_Invalid);
933 st0_tag = FPU_Special(st0_ptr); 820 goto invalid_operand;
934 if ( (st0_tag == TW_Infinity) || 821 }
935 (st0_tag == TW_NaN) )
936 {
937 EXCEPTION(EX_Invalid);
938 goto invalid_operand;
939 } 822 }
940 } 823
941 824 reg_copy(st0_ptr, &t);
942 reg_copy(st0_ptr, &t); 825 precision_loss = FPU_round_to_int(&t, st0_tag);
943 precision_loss = FPU_round_to_int(&t, st0_tag); 826 if (t.sigh ||
944 if (t.sigh || 827 ((t.sigl & 0x80000000) &&
945 ((t.sigl & 0x80000000) && 828 !((t.sigl == 0x80000000) && signnegative(&t)))) {
946 !((t.sigl == 0x80000000) && signnegative(&t))) ) 829 EXCEPTION(EX_Invalid);
947 { 830 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
948 EXCEPTION(EX_Invalid); 831 invalid_operand:
949 /* This is a special case: see sec 16.2.5.1 of the 80486 book */ 832 if (control_word & EX_Invalid) {
950 invalid_operand: 833 /* Produce something like QNaN "indefinite" */
951 if ( control_word & EX_Invalid ) 834 t.sigl = 0x80000000;
952 { 835 } else
953 /* Produce something like QNaN "indefinite" */ 836 return 0;
954 t.sigl = 0x80000000; 837 } else {
838 if (precision_loss)
839 set_precision_flag(precision_loss);
840 if (signnegative(&t))
841 t.sigl = -(long)t.sigl;
955 } 842 }
956 else
957 return 0;
958 }
959 else
960 {
961 if ( precision_loss )
962 set_precision_flag(precision_loss);
963 if ( signnegative(&t) )
964 t.sigl = -(long)t.sigl;
965 }
966
967 RE_ENTRANT_CHECK_OFF;
968 FPU_access_ok(VERIFY_WRITE,d,4);
969 FPU_put_user(t.sigl, (unsigned long __user *) d);
970 RE_ENTRANT_CHECK_ON;
971
972 return 1;
973}
974 843
844 RE_ENTRANT_CHECK_OFF;
845 FPU_access_ok(VERIFY_WRITE, d, 4);
846 FPU_put_user(t.sigl, (unsigned long __user *)d);
847 RE_ENTRANT_CHECK_ON;
848
849 return 1;
850}
975 851
976/* Put a short into user memory */ 852/* Put a short into user memory */
977int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d) 853int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
978{ 854{
979 FPU_REG t; 855 FPU_REG t;
980 int precision_loss; 856 int precision_loss;
981 857
982 if ( st0_tag == TAG_Empty ) 858 if (st0_tag == TAG_Empty) {
983 { 859 /* Empty register (stack underflow) */
984 /* Empty register (stack underflow) */ 860 EXCEPTION(EX_StackUnder);
985 EXCEPTION(EX_StackUnder); 861 goto invalid_operand;
986 goto invalid_operand; 862 } else if (st0_tag == TAG_Special) {
987 } 863 st0_tag = FPU_Special(st0_ptr);
988 else if ( st0_tag == TAG_Special ) 864 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
989 { 865 EXCEPTION(EX_Invalid);
990 st0_tag = FPU_Special(st0_ptr); 866 goto invalid_operand;
991 if ( (st0_tag == TW_Infinity) || 867 }
992 (st0_tag == TW_NaN) )
993 {
994 EXCEPTION(EX_Invalid);
995 goto invalid_operand;
996 } 868 }
997 } 869
998 870 reg_copy(st0_ptr, &t);
999 reg_copy(st0_ptr, &t); 871 precision_loss = FPU_round_to_int(&t, st0_tag);
1000 precision_loss = FPU_round_to_int(&t, st0_tag); 872 if (t.sigh ||
1001 if (t.sigh || 873 ((t.sigl & 0xffff8000) &&
1002 ((t.sigl & 0xffff8000) && 874 !((t.sigl == 0x8000) && signnegative(&t)))) {
1003 !((t.sigl == 0x8000) && signnegative(&t))) ) 875 EXCEPTION(EX_Invalid);
1004 { 876 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1005 EXCEPTION(EX_Invalid); 877 invalid_operand:
1006 /* This is a special case: see sec 16.2.5.1 of the 80486 book */ 878 if (control_word & EX_Invalid) {
1007 invalid_operand: 879 /* Produce something like QNaN "indefinite" */
1008 if ( control_word & EX_Invalid ) 880 t.sigl = 0x8000;
1009 { 881 } else
1010 /* Produce something like QNaN "indefinite" */ 882 return 0;
1011 t.sigl = 0x8000; 883 } else {
884 if (precision_loss)
885 set_precision_flag(precision_loss);
886 if (signnegative(&t))
887 t.sigl = -t.sigl;
1012 } 888 }
1013 else
1014 return 0;
1015 }
1016 else
1017 {
1018 if ( precision_loss )
1019 set_precision_flag(precision_loss);
1020 if ( signnegative(&t) )
1021 t.sigl = -t.sigl;
1022 }
1023
1024 RE_ENTRANT_CHECK_OFF;
1025 FPU_access_ok(VERIFY_WRITE,d,2);
1026 FPU_put_user((short)t.sigl, d);
1027 RE_ENTRANT_CHECK_ON;
1028
1029 return 1;
1030}
1031 889
890 RE_ENTRANT_CHECK_OFF;
891 FPU_access_ok(VERIFY_WRITE, d, 2);
892 FPU_put_user((short)t.sigl, d);
893 RE_ENTRANT_CHECK_ON;
894
895 return 1;
896}
1032 897
1033/* Put a packed bcd array into user memory */ 898/* Put a packed bcd array into user memory */
1034int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d) 899int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
1035{ 900{
1036 FPU_REG t; 901 FPU_REG t;
1037 unsigned long long ll; 902 unsigned long long ll;
1038 u_char b; 903 u_char b;
1039 int i, precision_loss; 904 int i, precision_loss;
1040 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0; 905 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
1041 906
1042 if ( st0_tag == TAG_Empty ) 907 if (st0_tag == TAG_Empty) {
1043 { 908 /* Empty register (stack underflow) */
1044 /* Empty register (stack underflow) */ 909 EXCEPTION(EX_StackUnder);
1045 EXCEPTION(EX_StackUnder); 910 goto invalid_operand;
1046 goto invalid_operand; 911 } else if (st0_tag == TAG_Special) {
1047 } 912 st0_tag = FPU_Special(st0_ptr);
1048 else if ( st0_tag == TAG_Special ) 913 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
1049 { 914 EXCEPTION(EX_Invalid);
1050 st0_tag = FPU_Special(st0_ptr); 915 goto invalid_operand;
1051 if ( (st0_tag == TW_Infinity) || 916 }
1052 (st0_tag == TW_NaN) ) 917 }
1053 { 918
1054 EXCEPTION(EX_Invalid); 919 reg_copy(st0_ptr, &t);
1055 goto invalid_operand; 920 precision_loss = FPU_round_to_int(&t, st0_tag);
921 ll = significand(&t);
922
923 /* Check for overflow, by comparing with 999999999999999999 decimal. */
924 if ((t.sigh > 0x0de0b6b3) ||
925 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
926 EXCEPTION(EX_Invalid);
927 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
928 invalid_operand:
929 if (control_word & CW_Invalid) {
930 /* Produce the QNaN "indefinite" */
931 RE_ENTRANT_CHECK_OFF;
932 FPU_access_ok(VERIFY_WRITE, d, 10);
933 for (i = 0; i < 7; i++)
934 FPU_put_user(0, d + i); /* These bytes "undefined" */
935 FPU_put_user(0xc0, d + 7); /* This byte "undefined" */
936 FPU_put_user(0xff, d + 8);
937 FPU_put_user(0xff, d + 9);
938 RE_ENTRANT_CHECK_ON;
939 return 1;
940 } else
941 return 0;
942 } else if (precision_loss) {
943 /* Precision loss doesn't stop the data transfer */
944 set_precision_flag(precision_loss);
1056 } 945 }
1057 } 946
1058 947 RE_ENTRANT_CHECK_OFF;
1059 reg_copy(st0_ptr, &t); 948 FPU_access_ok(VERIFY_WRITE, d, 10);
1060 precision_loss = FPU_round_to_int(&t, st0_tag); 949 RE_ENTRANT_CHECK_ON;
1061 ll = significand(&t); 950 for (i = 0; i < 9; i++) {
1062 951 b = FPU_div_small(&ll, 10);
1063 /* Check for overflow, by comparing with 999999999999999999 decimal. */ 952 b |= (FPU_div_small(&ll, 10)) << 4;
1064 if ( (t.sigh > 0x0de0b6b3) || 953 RE_ENTRANT_CHECK_OFF;
1065 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) ) 954 FPU_put_user(b, d + i);
1066 { 955 RE_ENTRANT_CHECK_ON;
1067 EXCEPTION(EX_Invalid);
1068 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1069 invalid_operand:
1070 if ( control_word & CW_Invalid )
1071 {
1072 /* Produce the QNaN "indefinite" */
1073 RE_ENTRANT_CHECK_OFF;
1074 FPU_access_ok(VERIFY_WRITE,d,10);
1075 for ( i = 0; i < 7; i++)
1076 FPU_put_user(0, d+i); /* These bytes "undefined" */
1077 FPU_put_user(0xc0, d+7); /* This byte "undefined" */
1078 FPU_put_user(0xff, d+8);
1079 FPU_put_user(0xff, d+9);
1080 RE_ENTRANT_CHECK_ON;
1081 return 1;
1082 } 956 }
1083 else 957 RE_ENTRANT_CHECK_OFF;
1084 return 0; 958 FPU_put_user(sign, d + 9);
1085 } 959 RE_ENTRANT_CHECK_ON;
1086 else if ( precision_loss ) 960
1087 { 961 return 1;
1088 /* Precision loss doesn't stop the data transfer */
1089 set_precision_flag(precision_loss);
1090 }
1091
1092 RE_ENTRANT_CHECK_OFF;
1093 FPU_access_ok(VERIFY_WRITE,d,10);
1094 RE_ENTRANT_CHECK_ON;
1095 for ( i = 0; i < 9; i++)
1096 {
1097 b = FPU_div_small(&ll, 10);
1098 b |= (FPU_div_small(&ll, 10)) << 4;
1099 RE_ENTRANT_CHECK_OFF;
1100 FPU_put_user(b, d+i);
1101 RE_ENTRANT_CHECK_ON;
1102 }
1103 RE_ENTRANT_CHECK_OFF;
1104 FPU_put_user(sign, d+9);
1105 RE_ENTRANT_CHECK_ON;
1106
1107 return 1;
1108} 962}
1109 963
1110/*===========================================================================*/ 964/*===========================================================================*/
@@ -1119,59 +973,56 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
1119 largest possible value */ 973 largest possible value */
1120int FPU_round_to_int(FPU_REG *r, u_char tag) 974int FPU_round_to_int(FPU_REG *r, u_char tag)
1121{ 975{
1122 u_char very_big; 976 u_char very_big;
1123 unsigned eax; 977 unsigned eax;
1124 978
1125 if (tag == TAG_Zero) 979 if (tag == TAG_Zero) {
1126 { 980 /* Make sure that zero is returned */
1127 /* Make sure that zero is returned */ 981 significand(r) = 0;
1128 significand(r) = 0; 982 return 0; /* o.k. */
1129 return 0; /* o.k. */ 983 }
1130 } 984
1131 985 if (exponent(r) > 63) {
1132 if (exponent(r) > 63) 986 r->sigl = r->sigh = ~0; /* The largest representable number */
1133 { 987 return 1; /* overflow */
1134 r->sigl = r->sigh = ~0; /* The largest representable number */ 988 }
1135 return 1; /* overflow */ 989
1136 } 990 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
1137 991 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1138 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
1139 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1140#define half_or_more (eax & 0x80000000) 992#define half_or_more (eax & 0x80000000)
1141#define frac_part (eax) 993#define frac_part (eax)
1142#define more_than_half ((eax & 0x80000001) == 0x80000001) 994#define more_than_half ((eax & 0x80000001) == 0x80000001)
1143 switch (control_word & CW_RC) 995 switch (control_word & CW_RC) {
1144 { 996 case RC_RND:
1145 case RC_RND: 997 if (more_than_half /* nearest */
1146 if ( more_than_half /* nearest */ 998 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
1147 || (half_or_more && (r->sigl & 1)) ) /* odd -> even */ 999 if (very_big)
1148 { 1000 return 1; /* overflow */
1149 if ( very_big ) return 1; /* overflow */ 1001 significand(r)++;
1150 significand(r) ++; 1002 return PRECISION_LOST_UP;
1151 return PRECISION_LOST_UP; 1003 }
1152 } 1004 break;
1153 break; 1005 case RC_DOWN:
1154 case RC_DOWN: 1006 if (frac_part && getsign(r)) {
1155 if (frac_part && getsign(r)) 1007 if (very_big)
1156 { 1008 return 1; /* overflow */
1157 if ( very_big ) return 1; /* overflow */ 1009 significand(r)++;
1158 significand(r) ++; 1010 return PRECISION_LOST_UP;
1159 return PRECISION_LOST_UP; 1011 }
1160 } 1012 break;
1161 break; 1013 case RC_UP:
1162 case RC_UP: 1014 if (frac_part && !getsign(r)) {
1163 if (frac_part && !getsign(r)) 1015 if (very_big)
1164 { 1016 return 1; /* overflow */
1165 if ( very_big ) return 1; /* overflow */ 1017 significand(r)++;
1166 significand(r) ++; 1018 return PRECISION_LOST_UP;
1167 return PRECISION_LOST_UP; 1019 }
1020 break;
1021 case RC_CHOP:
1022 break;
1168 } 1023 }
1169 break;
1170 case RC_CHOP:
1171 break;
1172 }
1173 1024
1174 return eax ? PRECISION_LOST_DOWN : 0; 1025 return eax ? PRECISION_LOST_DOWN : 0;
1175 1026
1176} 1027}
1177 1028
@@ -1179,197 +1030,195 @@ int FPU_round_to_int(FPU_REG *r, u_char tag)
1179 1030
1180u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s) 1031u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
1181{ 1032{
1182 unsigned short tag_word = 0; 1033 unsigned short tag_word = 0;
1183 u_char tag; 1034 u_char tag;
1184 int i; 1035 int i;
1185 1036
1186 if ( (addr_modes.default_mode == VM86) || 1037 if ((addr_modes.default_mode == VM86) ||
1187 ((addr_modes.default_mode == PM16) 1038 ((addr_modes.default_mode == PM16)
1188 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) ) 1039 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1189 { 1040 RE_ENTRANT_CHECK_OFF;
1190 RE_ENTRANT_CHECK_OFF; 1041 FPU_access_ok(VERIFY_READ, s, 0x0e);
1191 FPU_access_ok(VERIFY_READ, s, 0x0e); 1042 FPU_get_user(control_word, (unsigned short __user *)s);
1192 FPU_get_user(control_word, (unsigned short __user *) s); 1043 FPU_get_user(partial_status, (unsigned short __user *)(s + 2));
1193 FPU_get_user(partial_status, (unsigned short __user *) (s+2)); 1044 FPU_get_user(tag_word, (unsigned short __user *)(s + 4));
1194 FPU_get_user(tag_word, (unsigned short __user *) (s+4)); 1045 FPU_get_user(instruction_address.offset,
1195 FPU_get_user(instruction_address.offset, (unsigned short __user *) (s+6)); 1046 (unsigned short __user *)(s + 6));
1196 FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+8)); 1047 FPU_get_user(instruction_address.selector,
1197 FPU_get_user(operand_address.offset, (unsigned short __user *) (s+0x0a)); 1048 (unsigned short __user *)(s + 8));
1198 FPU_get_user(operand_address.selector, (unsigned short __user *) (s+0x0c)); 1049 FPU_get_user(operand_address.offset,
1199 RE_ENTRANT_CHECK_ON; 1050 (unsigned short __user *)(s + 0x0a));
1200 s += 0x0e; 1051 FPU_get_user(operand_address.selector,
1201 if ( addr_modes.default_mode == VM86 ) 1052 (unsigned short __user *)(s + 0x0c));
1202 { 1053 RE_ENTRANT_CHECK_ON;
1203 instruction_address.offset 1054 s += 0x0e;
1204 += (instruction_address.selector & 0xf000) << 4; 1055 if (addr_modes.default_mode == VM86) {
1205 operand_address.offset += (operand_address.selector & 0xf000) << 4; 1056 instruction_address.offset
1057 += (instruction_address.selector & 0xf000) << 4;
1058 operand_address.offset +=
1059 (operand_address.selector & 0xf000) << 4;
1060 }
1061 } else {
1062 RE_ENTRANT_CHECK_OFF;
1063 FPU_access_ok(VERIFY_READ, s, 0x1c);
1064 FPU_get_user(control_word, (unsigned short __user *)s);
1065 FPU_get_user(partial_status, (unsigned short __user *)(s + 4));
1066 FPU_get_user(tag_word, (unsigned short __user *)(s + 8));
1067 FPU_get_user(instruction_address.offset,
1068 (unsigned long __user *)(s + 0x0c));
1069 FPU_get_user(instruction_address.selector,
1070 (unsigned short __user *)(s + 0x10));
1071 FPU_get_user(instruction_address.opcode,
1072 (unsigned short __user *)(s + 0x12));
1073 FPU_get_user(operand_address.offset,
1074 (unsigned long __user *)(s + 0x14));
1075 FPU_get_user(operand_address.selector,
1076 (unsigned long __user *)(s + 0x18));
1077 RE_ENTRANT_CHECK_ON;
1078 s += 0x1c;
1206 } 1079 }
1207 }
1208 else
1209 {
1210 RE_ENTRANT_CHECK_OFF;
1211 FPU_access_ok(VERIFY_READ, s, 0x1c);
1212 FPU_get_user(control_word, (unsigned short __user *) s);
1213 FPU_get_user(partial_status, (unsigned short __user *) (s+4));
1214 FPU_get_user(tag_word, (unsigned short __user *) (s+8));
1215 FPU_get_user(instruction_address.offset, (unsigned long __user *) (s+0x0c));
1216 FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+0x10));
1217 FPU_get_user(instruction_address.opcode, (unsigned short __user *) (s+0x12));
1218 FPU_get_user(operand_address.offset, (unsigned long __user *) (s+0x14));
1219 FPU_get_user(operand_address.selector, (unsigned long __user *) (s+0x18));
1220 RE_ENTRANT_CHECK_ON;
1221 s += 0x1c;
1222 }
1223 1080
1224#ifdef PECULIAR_486 1081#ifdef PECULIAR_486
1225 control_word &= ~0xe080; 1082 control_word &= ~0xe080;
1226#endif /* PECULIAR_486 */ 1083#endif /* PECULIAR_486 */
1227 1084
1228 top = (partial_status >> SW_Top_Shift) & 7; 1085 top = (partial_status >> SW_Top_Shift) & 7;
1229 1086
1230 if ( partial_status & ~control_word & CW_Exceptions ) 1087 if (partial_status & ~control_word & CW_Exceptions)
1231 partial_status |= (SW_Summary | SW_Backward); 1088 partial_status |= (SW_Summary | SW_Backward);
1232 else 1089 else
1233 partial_status &= ~(SW_Summary | SW_Backward); 1090 partial_status &= ~(SW_Summary | SW_Backward);
1234 1091
1235 for ( i = 0; i < 8; i++ ) 1092 for (i = 0; i < 8; i++) {
1236 { 1093 tag = tag_word & 3;
1237 tag = tag_word & 3; 1094 tag_word >>= 2;
1238 tag_word >>= 2; 1095
1239 1096 if (tag == TAG_Empty)
1240 if ( tag == TAG_Empty ) 1097 /* New tag is empty. Accept it */
1241 /* New tag is empty. Accept it */ 1098 FPU_settag(i, TAG_Empty);
1242 FPU_settag(i, TAG_Empty); 1099 else if (FPU_gettag(i) == TAG_Empty) {
1243 else if ( FPU_gettag(i) == TAG_Empty ) 1100 /* Old tag is empty and new tag is not empty. New tag is determined
1244 { 1101 by old reg contents */
1245 /* Old tag is empty and new tag is not empty. New tag is determined 1102 if (exponent(&fpu_register(i)) == -EXTENDED_Ebias) {
1246 by old reg contents */ 1103 if (!
1247 if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias ) 1104 (fpu_register(i).sigl | fpu_register(i).
1248 { 1105 sigh))
1249 if ( !(fpu_register(i).sigl | fpu_register(i).sigh) ) 1106 FPU_settag(i, TAG_Zero);
1250 FPU_settag(i, TAG_Zero); 1107 else
1251 else 1108 FPU_settag(i, TAG_Special);
1252 FPU_settag(i, TAG_Special); 1109 } else if (exponent(&fpu_register(i)) ==
1253 } 1110 0x7fff - EXTENDED_Ebias) {
1254 else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias ) 1111 FPU_settag(i, TAG_Special);
1255 { 1112 } else if (fpu_register(i).sigh & 0x80000000)
1256 FPU_settag(i, TAG_Special); 1113 FPU_settag(i, TAG_Valid);
1257 } 1114 else
1258 else if ( fpu_register(i).sigh & 0x80000000 ) 1115 FPU_settag(i, TAG_Special); /* An Un-normal */
1259 FPU_settag(i, TAG_Valid); 1116 }
1260 else 1117 /* Else old tag is not empty and new tag is not empty. Old tag
1261 FPU_settag(i, TAG_Special); /* An Un-normal */ 1118 remains correct */
1262 } 1119 }
1263 /* Else old tag is not empty and new tag is not empty. Old tag
1264 remains correct */
1265 }
1266
1267 return s;
1268}
1269 1120
1121 return s;
1122}
1270 1123
1271void frstor(fpu_addr_modes addr_modes, u_char __user *data_address) 1124void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
1272{ 1125{
1273 int i, regnr; 1126 int i, regnr;
1274 u_char __user *s = fldenv(addr_modes, data_address); 1127 u_char __user *s = fldenv(addr_modes, data_address);
1275 int offset = (top & 7) * 10, other = 80 - offset; 1128 int offset = (top & 7) * 10, other = 80 - offset;
1276 1129
1277 /* Copy all registers in stack order. */ 1130 /* Copy all registers in stack order. */
1278 RE_ENTRANT_CHECK_OFF; 1131 RE_ENTRANT_CHECK_OFF;
1279 FPU_access_ok(VERIFY_READ,s,80); 1132 FPU_access_ok(VERIFY_READ, s, 80);
1280 __copy_from_user(register_base+offset, s, other); 1133 __copy_from_user(register_base + offset, s, other);
1281 if ( offset ) 1134 if (offset)
1282 __copy_from_user(register_base, s+other, offset); 1135 __copy_from_user(register_base, s + other, offset);
1283 RE_ENTRANT_CHECK_ON; 1136 RE_ENTRANT_CHECK_ON;
1284 1137
1285 for ( i = 0; i < 8; i++ ) 1138 for (i = 0; i < 8; i++) {
1286 { 1139 regnr = (i + top) & 7;
1287 regnr = (i+top) & 7; 1140 if (FPU_gettag(regnr) != TAG_Empty)
1288 if ( FPU_gettag(regnr) != TAG_Empty ) 1141 /* The loaded data over-rides all other cases. */
1289 /* The loaded data over-rides all other cases. */ 1142 FPU_settag(regnr, FPU_tagof(&st(i)));
1290 FPU_settag(regnr, FPU_tagof(&st(i))); 1143 }
1291 }
1292 1144
1293} 1145}
1294 1146
1295
1296u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d) 1147u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
1297{ 1148{
1298 if ( (addr_modes.default_mode == VM86) || 1149 if ((addr_modes.default_mode == VM86) ||
1299 ((addr_modes.default_mode == PM16) 1150 ((addr_modes.default_mode == PM16)
1300 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) ) 1151 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1301 { 1152 RE_ENTRANT_CHECK_OFF;
1302 RE_ENTRANT_CHECK_OFF; 1153 FPU_access_ok(VERIFY_WRITE, d, 14);
1303 FPU_access_ok(VERIFY_WRITE,d,14);
1304#ifdef PECULIAR_486 1154#ifdef PECULIAR_486
1305 FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d); 1155 FPU_put_user(control_word & ~0xe080, (unsigned long __user *)d);
1306#else 1156#else
1307 FPU_put_user(control_word, (unsigned short __user *) d); 1157 FPU_put_user(control_word, (unsigned short __user *)d);
1308#endif /* PECULIAR_486 */ 1158#endif /* PECULIAR_486 */
1309 FPU_put_user(status_word(), (unsigned short __user *) (d+2)); 1159 FPU_put_user(status_word(), (unsigned short __user *)(d + 2));
1310 FPU_put_user(fpu_tag_word, (unsigned short __user *) (d+4)); 1160 FPU_put_user(fpu_tag_word, (unsigned short __user *)(d + 4));
1311 FPU_put_user(instruction_address.offset, (unsigned short __user *) (d+6)); 1161 FPU_put_user(instruction_address.offset,
1312 FPU_put_user(operand_address.offset, (unsigned short __user *) (d+0x0a)); 1162 (unsigned short __user *)(d + 6));
1313 if ( addr_modes.default_mode == VM86 ) 1163 FPU_put_user(operand_address.offset,
1314 { 1164 (unsigned short __user *)(d + 0x0a));
1315 FPU_put_user((instruction_address.offset & 0xf0000) >> 4, 1165 if (addr_modes.default_mode == VM86) {
1316 (unsigned short __user *) (d+8)); 1166 FPU_put_user((instruction_address.
1317 FPU_put_user((operand_address.offset & 0xf0000) >> 4, 1167 offset & 0xf0000) >> 4,
1318 (unsigned short __user *) (d+0x0c)); 1168 (unsigned short __user *)(d + 8));
1319 } 1169 FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1320 else 1170 (unsigned short __user *)(d + 0x0c));
1321 { 1171 } else {
1322 FPU_put_user(instruction_address.selector, (unsigned short __user *) (d+8)); 1172 FPU_put_user(instruction_address.selector,
1323 FPU_put_user(operand_address.selector, (unsigned short __user *) (d+0x0c)); 1173 (unsigned short __user *)(d + 8));
1324 } 1174 FPU_put_user(operand_address.selector,
1325 RE_ENTRANT_CHECK_ON; 1175 (unsigned short __user *)(d + 0x0c));
1326 d += 0x0e; 1176 }
1327 } 1177 RE_ENTRANT_CHECK_ON;
1328 else 1178 d += 0x0e;
1329 { 1179 } else {
1330 RE_ENTRANT_CHECK_OFF; 1180 RE_ENTRANT_CHECK_OFF;
1331 FPU_access_ok(VERIFY_WRITE, d, 7*4); 1181 FPU_access_ok(VERIFY_WRITE, d, 7 * 4);
1332#ifdef PECULIAR_486 1182#ifdef PECULIAR_486
1333 control_word &= ~0xe080; 1183 control_word &= ~0xe080;
1334 /* An 80486 sets nearly all of the reserved bits to 1. */ 1184 /* An 80486 sets nearly all of the reserved bits to 1. */
1335 control_word |= 0xffff0040; 1185 control_word |= 0xffff0040;
1336 partial_status = status_word() | 0xffff0000; 1186 partial_status = status_word() | 0xffff0000;
1337 fpu_tag_word |= 0xffff0000; 1187 fpu_tag_word |= 0xffff0000;
1338 I387.soft.fcs &= ~0xf8000000; 1188 I387.soft.fcs &= ~0xf8000000;
1339 I387.soft.fos |= 0xffff0000; 1189 I387.soft.fos |= 0xffff0000;
1340#endif /* PECULIAR_486 */ 1190#endif /* PECULIAR_486 */
1341 if (__copy_to_user(d, &control_word, 7*4)) 1191 if (__copy_to_user(d, &control_word, 7 * 4))
1342 FPU_abort; 1192 FPU_abort;
1343 RE_ENTRANT_CHECK_ON; 1193 RE_ENTRANT_CHECK_ON;
1344 d += 0x1c; 1194 d += 0x1c;
1345 } 1195 }
1346
1347 control_word |= CW_Exceptions;
1348 partial_status &= ~(SW_Summary | SW_Backward);
1349
1350 return d;
1351}
1352 1196
1197 control_word |= CW_Exceptions;
1198 partial_status &= ~(SW_Summary | SW_Backward);
1199
1200 return d;
1201}
1353 1202
1354void fsave(fpu_addr_modes addr_modes, u_char __user *data_address) 1203void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
1355{ 1204{
1356 u_char __user *d; 1205 u_char __user *d;
1357 int offset = (top & 7) * 10, other = 80 - offset; 1206 int offset = (top & 7) * 10, other = 80 - offset;
1358 1207
1359 d = fstenv(addr_modes, data_address); 1208 d = fstenv(addr_modes, data_address);
1360 1209
1361 RE_ENTRANT_CHECK_OFF; 1210 RE_ENTRANT_CHECK_OFF;
1362 FPU_access_ok(VERIFY_WRITE,d,80); 1211 FPU_access_ok(VERIFY_WRITE, d, 80);
1363 1212
1364 /* Copy all registers in stack order. */ 1213 /* Copy all registers in stack order. */
1365 if (__copy_to_user(d, register_base+offset, other)) 1214 if (__copy_to_user(d, register_base + offset, other))
1366 FPU_abort; 1215 FPU_abort;
1367 if ( offset ) 1216 if (offset)
1368 if (__copy_to_user(d+other, register_base, offset)) 1217 if (__copy_to_user(d + other, register_base, offset))
1369 FPU_abort; 1218 FPU_abort;
1370 RE_ENTRANT_CHECK_ON; 1219 RE_ENTRANT_CHECK_ON;
1371 1220
1372 finit(); 1221 finit();
1373} 1222}
1374 1223
1375/*===========================================================================*/ 1224/*===========================================================================*/