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