cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

reg_ld_str.c (32011B)


      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   billm@suburbia.net                              |
     10 |                                                                           |
     11 |                                                                           |
     12 +---------------------------------------------------------------------------*/
     13
     14/*---------------------------------------------------------------------------+
     15 | Note:                                                                     |
     16 |    The file contains code which accesses user memory.                     |
     17 |    Emulator static data may change when user memory is accessed, due to   |
     18 |    other processes using the emulator while swapping is in progress.      |
     19 +---------------------------------------------------------------------------*/
     20
     21#include "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
     39static 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
     53int 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 */
     82int 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 */
     95int 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 */
    156int 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 */
    210int 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 */
    240int 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 */
    269int 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 */
    298int 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 */
    337int 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 */
    379int 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 */
    395denormal_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 */
    564int 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 */
    753int 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 */
    803int 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 */
    849int 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 */
    895int 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 */
    970int 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
   1027u_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
   1120void 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
   1143u_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
   1199void 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/*===========================================================================*/