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