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

fpa11_cpdt.c (8414B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    NetWinder Floating Point Emulator
      4    (c) Rebel.com, 1998-1999
      5    (c) Philip Blundell, 1998, 2001
      6
      7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
      8
      9*/
     10
     11#include "fpa11.h"
     12#include "softfloat.h"
     13#include "fpopcode.h"
     14#include "fpmodule.h"
     15#include "fpmodule.inl"
     16
     17#include <linux/uaccess.h>
     18
     19static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
     20{
     21	FPA11 *fpa11 = GET_FPA11();
     22	fpa11->fType[Fn] = typeSingle;
     23	get_user(fpa11->fpreg[Fn].fSingle, pMem);
     24}
     25
     26static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
     27{
     28	FPA11 *fpa11 = GET_FPA11();
     29	unsigned int *p;
     30	p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
     31	fpa11->fType[Fn] = typeDouble;
     32#ifdef __ARMEB__
     33	get_user(p[0], &pMem[0]);	/* sign & exponent */
     34	get_user(p[1], &pMem[1]);
     35#else
     36	get_user(p[0], &pMem[1]);
     37	get_user(p[1], &pMem[0]);	/* sign & exponent */
     38#endif
     39}
     40
     41#ifdef CONFIG_FPE_NWFPE_XP
     42static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
     43{
     44	FPA11 *fpa11 = GET_FPA11();
     45	unsigned int *p;
     46	p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
     47	fpa11->fType[Fn] = typeExtended;
     48	get_user(p[0], &pMem[0]);	/* sign & exponent */
     49#ifdef __ARMEB__
     50	get_user(p[1], &pMem[1]);	/* ms bits */
     51	get_user(p[2], &pMem[2]);	/* ls bits */
     52#else
     53	get_user(p[1], &pMem[2]);	/* ls bits */
     54	get_user(p[2], &pMem[1]);	/* ms bits */
     55#endif
     56}
     57#endif
     58
     59static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
     60{
     61	FPA11 *fpa11 = GET_FPA11();
     62	register unsigned int *p;
     63	unsigned long x;
     64
     65	p = (unsigned int *) &(fpa11->fpreg[Fn]);
     66	get_user(x, &pMem[0]);
     67	fpa11->fType[Fn] = (x >> 14) & 0x00000003;
     68
     69	switch (fpa11->fType[Fn]) {
     70	case typeSingle:
     71	case typeDouble:
     72		{
     73			get_user(p[0], &pMem[2]);	/* Single */
     74			get_user(p[1], &pMem[1]);	/* double msw */
     75			p[2] = 0;			/* empty */
     76		}
     77		break;
     78
     79#ifdef CONFIG_FPE_NWFPE_XP
     80	case typeExtended:
     81		{
     82			get_user(p[1], &pMem[2]);
     83			get_user(p[2], &pMem[1]);	/* msw */
     84			p[0] = (x & 0x80003fff);
     85		}
     86		break;
     87#endif
     88	}
     89}
     90
     91static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
     92{
     93	FPA11 *fpa11 = GET_FPA11();
     94	union {
     95		float32 f;
     96		unsigned int i[1];
     97	} val;
     98
     99	switch (fpa11->fType[Fn]) {
    100	case typeDouble:
    101		val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
    102		break;
    103
    104#ifdef CONFIG_FPE_NWFPE_XP
    105	case typeExtended:
    106		val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
    107		break;
    108#endif
    109
    110	default:
    111		val.f = fpa11->fpreg[Fn].fSingle;
    112	}
    113
    114	put_user(val.i[0], pMem);
    115}
    116
    117static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
    118{
    119	FPA11 *fpa11 = GET_FPA11();
    120	union {
    121		float64 f;
    122		unsigned int i[2];
    123	} val;
    124
    125	switch (fpa11->fType[Fn]) {
    126	case typeSingle:
    127		val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
    128		break;
    129
    130#ifdef CONFIG_FPE_NWFPE_XP
    131	case typeExtended:
    132		val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
    133		break;
    134#endif
    135
    136	default:
    137		val.f = fpa11->fpreg[Fn].fDouble;
    138	}
    139
    140#ifdef __ARMEB__
    141	put_user(val.i[0], &pMem[0]);	/* msw */
    142	put_user(val.i[1], &pMem[1]);	/* lsw */
    143#else
    144	put_user(val.i[1], &pMem[0]);	/* msw */
    145	put_user(val.i[0], &pMem[1]);	/* lsw */
    146#endif
    147}
    148
    149#ifdef CONFIG_FPE_NWFPE_XP
    150static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
    151{
    152	FPA11 *fpa11 = GET_FPA11();
    153	union {
    154		floatx80 f;
    155		unsigned int i[3];
    156	} val;
    157
    158	switch (fpa11->fType[Fn]) {
    159	case typeSingle:
    160		val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
    161		break;
    162
    163	case typeDouble:
    164		val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
    165		break;
    166
    167	default:
    168		val.f = fpa11->fpreg[Fn].fExtended;
    169	}
    170
    171	put_user(val.i[0], &pMem[0]);	/* sign & exp */
    172#ifdef __ARMEB__
    173	put_user(val.i[1], &pMem[1]);	/* msw */
    174	put_user(val.i[2], &pMem[2]);
    175#else
    176	put_user(val.i[1], &pMem[2]);
    177	put_user(val.i[2], &pMem[1]);	/* msw */
    178#endif
    179}
    180#endif
    181
    182static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
    183{
    184	FPA11 *fpa11 = GET_FPA11();
    185	register unsigned int nType, *p;
    186
    187	p = (unsigned int *) &(fpa11->fpreg[Fn]);
    188	nType = fpa11->fType[Fn];
    189
    190	switch (nType) {
    191	case typeSingle:
    192	case typeDouble:
    193		{
    194			put_user(p[0], &pMem[2]);	/* single */
    195			put_user(p[1], &pMem[1]);	/* double msw */
    196			put_user(nType << 14, &pMem[0]);
    197		}
    198		break;
    199
    200#ifdef CONFIG_FPE_NWFPE_XP
    201	case typeExtended:
    202		{
    203			put_user(p[2], &pMem[1]);	/* msw */
    204			put_user(p[1], &pMem[2]);
    205			put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
    206		}
    207		break;
    208#endif
    209	}
    210}
    211
    212unsigned int PerformLDF(const unsigned int opcode)
    213{
    214	unsigned int __user *pBase, *pAddress, *pFinal;
    215	unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
    216
    217	pBase = (unsigned int __user *) readRegister(getRn(opcode));
    218	if (REG_PC == getRn(opcode)) {
    219		pBase += 2;
    220		write_back = 0;
    221	}
    222
    223	pFinal = pBase;
    224	if (BIT_UP_SET(opcode))
    225		pFinal += getOffset(opcode);
    226	else
    227		pFinal -= getOffset(opcode);
    228
    229	if (PREINDEXED(opcode))
    230		pAddress = pFinal;
    231	else
    232		pAddress = pBase;
    233
    234	switch (opcode & MASK_TRANSFER_LENGTH) {
    235	case TRANSFER_SINGLE:
    236		loadSingle(getFd(opcode), pAddress);
    237		break;
    238	case TRANSFER_DOUBLE:
    239		loadDouble(getFd(opcode), pAddress);
    240		break;
    241#ifdef CONFIG_FPE_NWFPE_XP
    242	case TRANSFER_EXTENDED:
    243		loadExtended(getFd(opcode), pAddress);
    244		break;
    245#endif
    246	default:
    247		nRc = 0;
    248	}
    249
    250	if (write_back)
    251		writeRegister(getRn(opcode), (unsigned long) pFinal);
    252	return nRc;
    253}
    254
    255unsigned int PerformSTF(const unsigned int opcode)
    256{
    257	unsigned int __user *pBase, *pAddress, *pFinal;
    258	unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
    259	struct roundingData roundData;
    260
    261	roundData.mode = SetRoundingMode(opcode);
    262	roundData.precision = SetRoundingPrecision(opcode);
    263	roundData.exception = 0;
    264
    265	pBase = (unsigned int __user *) readRegister(getRn(opcode));
    266	if (REG_PC == getRn(opcode)) {
    267		pBase += 2;
    268		write_back = 0;
    269	}
    270
    271	pFinal = pBase;
    272	if (BIT_UP_SET(opcode))
    273		pFinal += getOffset(opcode);
    274	else
    275		pFinal -= getOffset(opcode);
    276
    277	if (PREINDEXED(opcode))
    278		pAddress = pFinal;
    279	else
    280		pAddress = pBase;
    281
    282	switch (opcode & MASK_TRANSFER_LENGTH) {
    283	case TRANSFER_SINGLE:
    284		storeSingle(&roundData, getFd(opcode), pAddress);
    285		break;
    286	case TRANSFER_DOUBLE:
    287		storeDouble(&roundData, getFd(opcode), pAddress);
    288		break;
    289#ifdef CONFIG_FPE_NWFPE_XP
    290	case TRANSFER_EXTENDED:
    291		storeExtended(getFd(opcode), pAddress);
    292		break;
    293#endif
    294	default:
    295		nRc = 0;
    296	}
    297
    298	if (roundData.exception)
    299		float_raise(roundData.exception);
    300
    301	if (write_back)
    302		writeRegister(getRn(opcode), (unsigned long) pFinal);
    303	return nRc;
    304}
    305
    306unsigned int PerformLFM(const unsigned int opcode)
    307{
    308	unsigned int __user *pBase, *pAddress, *pFinal;
    309	unsigned int i, Fd, write_back = WRITE_BACK(opcode);
    310
    311	pBase = (unsigned int __user *) readRegister(getRn(opcode));
    312	if (REG_PC == getRn(opcode)) {
    313		pBase += 2;
    314		write_back = 0;
    315	}
    316
    317	pFinal = pBase;
    318	if (BIT_UP_SET(opcode))
    319		pFinal += getOffset(opcode);
    320	else
    321		pFinal -= getOffset(opcode);
    322
    323	if (PREINDEXED(opcode))
    324		pAddress = pFinal;
    325	else
    326		pAddress = pBase;
    327
    328	Fd = getFd(opcode);
    329	for (i = getRegisterCount(opcode); i > 0; i--) {
    330		loadMultiple(Fd, pAddress);
    331		pAddress += 3;
    332		Fd++;
    333		if (Fd == 8)
    334			Fd = 0;
    335	}
    336
    337	if (write_back)
    338		writeRegister(getRn(opcode), (unsigned long) pFinal);
    339	return 1;
    340}
    341
    342unsigned int PerformSFM(const unsigned int opcode)
    343{
    344	unsigned int __user *pBase, *pAddress, *pFinal;
    345	unsigned int i, Fd, write_back = WRITE_BACK(opcode);
    346
    347	pBase = (unsigned int __user *) readRegister(getRn(opcode));
    348	if (REG_PC == getRn(opcode)) {
    349		pBase += 2;
    350		write_back = 0;
    351	}
    352
    353	pFinal = pBase;
    354	if (BIT_UP_SET(opcode))
    355		pFinal += getOffset(opcode);
    356	else
    357		pFinal -= getOffset(opcode);
    358
    359	if (PREINDEXED(opcode))
    360		pAddress = pFinal;
    361	else
    362		pAddress = pBase;
    363
    364	Fd = getFd(opcode);
    365	for (i = getRegisterCount(opcode); i > 0; i--) {
    366		storeMultiple(Fd, pAddress);
    367		pAddress += 3;
    368		Fd++;
    369		if (Fd == 8)
    370			Fd = 0;
    371	}
    372
    373	if (write_back)
    374		writeRegister(getRn(opcode), (unsigned long) pFinal);
    375	return 1;
    376}
    377
    378unsigned int EmulateCPDT(const unsigned int opcode)
    379{
    380	unsigned int nRc = 0;
    381
    382	if (LDF_OP(opcode)) {
    383		nRc = PerformLDF(opcode);
    384	} else if (LFM_OP(opcode)) {
    385		nRc = PerformLFM(opcode);
    386	} else if (STF_OP(opcode)) {
    387		nRc = PerformSTF(opcode);
    388	} else if (SFM_OP(opcode)) {
    389		nRc = PerformSFM(opcode);
    390	} else {
    391		nRc = 0;
    392	}
    393
    394	return nRc;
    395}