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

math.c (11388B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
      4 */
      5
      6#include <linux/types.h>
      7#include <linux/sched.h>
      8
      9#include <linux/uaccess.h>
     10#include <asm/reg.h>
     11#include <asm/switch_to.h>
     12
     13#include <asm/sfp-machine.h>
     14#include <math-emu/double.h>
     15
     16#define FLOATFUNC(x)	extern int x(void *, void *, void *, void *)
     17
     18/* The instructions list which may be not implemented by a hardware FPU */
     19FLOATFUNC(fre);
     20FLOATFUNC(frsqrtes);
     21FLOATFUNC(fsqrt);
     22FLOATFUNC(fsqrts);
     23FLOATFUNC(mtfsf);
     24FLOATFUNC(mtfsfi);
     25
     26#ifdef CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED
     27#undef FLOATFUNC(x)
     28#define FLOATFUNC(x)	static inline int x(void *op1, void *op2, void *op3, \
     29						 void *op4) { }
     30#endif
     31
     32FLOATFUNC(fadd);
     33FLOATFUNC(fadds);
     34FLOATFUNC(fdiv);
     35FLOATFUNC(fdivs);
     36FLOATFUNC(fmul);
     37FLOATFUNC(fmuls);
     38FLOATFUNC(fsub);
     39FLOATFUNC(fsubs);
     40
     41FLOATFUNC(fmadd);
     42FLOATFUNC(fmadds);
     43FLOATFUNC(fmsub);
     44FLOATFUNC(fmsubs);
     45FLOATFUNC(fnmadd);
     46FLOATFUNC(fnmadds);
     47FLOATFUNC(fnmsub);
     48FLOATFUNC(fnmsubs);
     49
     50FLOATFUNC(fctiw);
     51FLOATFUNC(fctiwz);
     52FLOATFUNC(frsp);
     53
     54FLOATFUNC(fcmpo);
     55FLOATFUNC(fcmpu);
     56
     57FLOATFUNC(mcrfs);
     58FLOATFUNC(mffs);
     59FLOATFUNC(mtfsb0);
     60FLOATFUNC(mtfsb1);
     61
     62FLOATFUNC(lfd);
     63FLOATFUNC(lfs);
     64
     65FLOATFUNC(stfd);
     66FLOATFUNC(stfs);
     67FLOATFUNC(stfiwx);
     68
     69FLOATFUNC(fabs);
     70FLOATFUNC(fmr);
     71FLOATFUNC(fnabs);
     72FLOATFUNC(fneg);
     73
     74/* Optional */
     75FLOATFUNC(fres);
     76FLOATFUNC(frsqrte);
     77FLOATFUNC(fsel);
     78
     79
     80#define OP31		0x1f		/*   31 */
     81#define LFS		0x30		/*   48 */
     82#define LFSU		0x31		/*   49 */
     83#define LFD		0x32		/*   50 */
     84#define LFDU		0x33		/*   51 */
     85#define STFS		0x34		/*   52 */
     86#define STFSU		0x35		/*   53 */
     87#define STFD		0x36		/*   54 */
     88#define STFDU		0x37		/*   55 */
     89#define OP59		0x3b		/*   59 */
     90#define OP63		0x3f		/*   63 */
     91
     92/* Opcode 31: */
     93/* X-Form: */
     94#define LFSX		0x217		/*  535 */
     95#define LFSUX		0x237		/*  567 */
     96#define LFDX		0x257		/*  599 */
     97#define LFDUX		0x277		/*  631 */
     98#define STFSX		0x297		/*  663 */
     99#define STFSUX		0x2b7		/*  695 */
    100#define STFDX		0x2d7		/*  727 */
    101#define STFDUX		0x2f7		/*  759 */
    102#define STFIWX		0x3d7		/*  983 */
    103
    104/* Opcode 59: */
    105/* A-Form: */
    106#define FDIVS		0x012		/*   18 */
    107#define FSUBS		0x014		/*   20 */
    108#define FADDS		0x015		/*   21 */
    109#define FSQRTS		0x016		/*   22 */
    110#define FRES		0x018		/*   24 */
    111#define FMULS		0x019		/*   25 */
    112#define FRSQRTES	0x01a		/*   26 */
    113#define FMSUBS		0x01c		/*   28 */
    114#define FMADDS		0x01d		/*   29 */
    115#define FNMSUBS		0x01e		/*   30 */
    116#define FNMADDS		0x01f		/*   31 */
    117
    118/* Opcode 63: */
    119/* A-Form: */
    120#define FDIV		0x012		/*   18 */
    121#define FSUB		0x014		/*   20 */
    122#define FADD		0x015		/*   21 */
    123#define FSQRT		0x016		/*   22 */
    124#define FSEL		0x017		/*   23 */
    125#define FRE		0x018		/*   24 */
    126#define FMUL		0x019		/*   25 */
    127#define FRSQRTE		0x01a		/*   26 */
    128#define FMSUB		0x01c		/*   28 */
    129#define FMADD		0x01d		/*   29 */
    130#define FNMSUB		0x01e		/*   30 */
    131#define FNMADD		0x01f		/*   31 */
    132
    133/* X-Form: */
    134#define FCMPU		0x000		/*    0	*/
    135#define FRSP		0x00c		/*   12 */
    136#define FCTIW		0x00e		/*   14 */
    137#define FCTIWZ		0x00f		/*   15 */
    138#define FCMPO		0x020		/*   32 */
    139#define MTFSB1		0x026		/*   38 */
    140#define FNEG		0x028		/*   40 */
    141#define MCRFS		0x040		/*   64 */
    142#define MTFSB0		0x046		/*   70 */
    143#define FMR		0x048		/*   72 */
    144#define MTFSFI		0x086		/*  134 */
    145#define FNABS		0x088		/*  136 */
    146#define FABS		0x108		/*  264 */
    147#define MFFS		0x247		/*  583 */
    148#define MTFSF		0x2c7		/*  711 */
    149
    150
    151#define AB	2
    152#define AC	3
    153#define ABC	4
    154#define D	5
    155#define DU	6
    156#define X	7
    157#define XA	8
    158#define XB	9
    159#define XCR	11
    160#define XCRB	12
    161#define XCRI	13
    162#define XCRL	16
    163#define XE	14
    164#define XEU	15
    165#define XFLB	10
    166
    167static int
    168record_exception(struct pt_regs *regs, int eflag)
    169{
    170	u32 fpscr;
    171
    172	fpscr = __FPU_FPSCR;
    173
    174	if (eflag) {
    175		fpscr |= FPSCR_FX;
    176		if (eflag & EFLAG_OVERFLOW)
    177			fpscr |= FPSCR_OX;
    178		if (eflag & EFLAG_UNDERFLOW)
    179			fpscr |= FPSCR_UX;
    180		if (eflag & EFLAG_DIVZERO)
    181			fpscr |= FPSCR_ZX;
    182		if (eflag & EFLAG_INEXACT)
    183			fpscr |= FPSCR_XX;
    184		if (eflag & EFLAG_INVALID)
    185			fpscr |= FPSCR_VX;
    186		if (eflag & EFLAG_VXSNAN)
    187			fpscr |= FPSCR_VXSNAN;
    188		if (eflag & EFLAG_VXISI)
    189			fpscr |= FPSCR_VXISI;
    190		if (eflag & EFLAG_VXIDI)
    191			fpscr |= FPSCR_VXIDI;
    192		if (eflag & EFLAG_VXZDZ)
    193			fpscr |= FPSCR_VXZDZ;
    194		if (eflag & EFLAG_VXIMZ)
    195			fpscr |= FPSCR_VXIMZ;
    196		if (eflag & EFLAG_VXVC)
    197			fpscr |= FPSCR_VXVC;
    198		if (eflag & EFLAG_VXSOFT)
    199			fpscr |= FPSCR_VXSOFT;
    200		if (eflag & EFLAG_VXSQRT)
    201			fpscr |= FPSCR_VXSQRT;
    202		if (eflag & EFLAG_VXCVI)
    203			fpscr |= FPSCR_VXCVI;
    204	}
    205
    206//	fpscr &= ~(FPSCR_VX);
    207	if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
    208		     FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
    209		     FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
    210		fpscr |= FPSCR_VX;
    211
    212	fpscr &= ~(FPSCR_FEX);
    213	if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
    214	    ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
    215	    ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
    216	    ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
    217	    ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
    218		fpscr |= FPSCR_FEX;
    219
    220	__FPU_FPSCR = fpscr;
    221
    222	return (fpscr & FPSCR_FEX) ? 1 : 0;
    223}
    224
    225int
    226do_mathemu(struct pt_regs *regs)
    227{
    228	void *op0 = NULL, *op1 = NULL, *op2 = NULL, *op3 = NULL;
    229	unsigned long pc = regs->nip;
    230	signed short sdisp;
    231	u32 insn = 0;
    232	int idx = 0;
    233	int (*func)(void *, void *, void *, void *);
    234	int type = 0;
    235	int eflag, trap;
    236
    237	if (get_user(insn, (u32 __user *)pc))
    238		return -EFAULT;
    239
    240	switch (insn >> 26) {
    241	case LFS:	func = lfs;	type = D;	break;
    242	case LFSU:	func = lfs;	type = DU;	break;
    243	case LFD:	func = lfd;	type = D;	break;
    244	case LFDU:	func = lfd;	type = DU;	break;
    245	case STFS:	func = stfs;	type = D;	break;
    246	case STFSU:	func = stfs;	type = DU;	break;
    247	case STFD:	func = stfd;	type = D;	break;
    248	case STFDU:	func = stfd;	type = DU;	break;
    249
    250	case OP31:
    251		switch ((insn >> 1) & 0x3ff) {
    252		case LFSX:	func = lfs;	type = XE;	break;
    253		case LFSUX:	func = lfs;	type = XEU;	break;
    254		case LFDX:	func = lfd;	type = XE;	break;
    255		case LFDUX:	func = lfd;	type = XEU;	break;
    256		case STFSX:	func = stfs;	type = XE;	break;
    257		case STFSUX:	func = stfs;	type = XEU;	break;
    258		case STFDX:	func = stfd;	type = XE;	break;
    259		case STFDUX:	func = stfd;	type = XEU;	break;
    260		case STFIWX:	func = stfiwx;	type = XE;	break;
    261		default:
    262			goto illegal;
    263		}
    264		break;
    265
    266	case OP59:
    267		switch ((insn >> 1) & 0x1f) {
    268		case FDIVS:	func = fdivs;	type = AB;	break;
    269		case FSUBS:	func = fsubs;	type = AB;	break;
    270		case FADDS:	func = fadds;	type = AB;	break;
    271		case FSQRTS:	func = fsqrts;	type = XB;	break;
    272		case FRES:	func = fres;	type = XB;	break;
    273		case FMULS:	func = fmuls;	type = AC;	break;
    274		case FRSQRTES:	func = frsqrtes;type = XB;	break;
    275		case FMSUBS:	func = fmsubs;	type = ABC;	break;
    276		case FMADDS:	func = fmadds;	type = ABC;	break;
    277		case FNMSUBS:	func = fnmsubs;	type = ABC;	break;
    278		case FNMADDS:	func = fnmadds;	type = ABC;	break;
    279		default:
    280			goto illegal;
    281		}
    282		break;
    283
    284	case OP63:
    285		if (insn & 0x20) {
    286			switch ((insn >> 1) & 0x1f) {
    287			case FDIV:	func = fdiv;	type = AB;	break;
    288			case FSUB:	func = fsub;	type = AB;	break;
    289			case FADD:	func = fadd;	type = AB;	break;
    290			case FSQRT:	func = fsqrt;	type = XB;	break;
    291			case FRE:	func = fre;	type = XB;	break;
    292			case FSEL:	func = fsel;	type = ABC;	break;
    293			case FMUL:	func = fmul;	type = AC;	break;
    294			case FRSQRTE:	func = frsqrte;	type = XB;	break;
    295			case FMSUB:	func = fmsub;	type = ABC;	break;
    296			case FMADD:	func = fmadd;	type = ABC;	break;
    297			case FNMSUB:	func = fnmsub;	type = ABC;	break;
    298			case FNMADD:	func = fnmadd;	type = ABC;	break;
    299			default:
    300				goto illegal;
    301			}
    302			break;
    303		}
    304
    305		switch ((insn >> 1) & 0x3ff) {
    306		case FCMPU:	func = fcmpu;	type = XCR;	break;
    307		case FRSP:	func = frsp;	type = XB;	break;
    308		case FCTIW:	func = fctiw;	type = XB;	break;
    309		case FCTIWZ:	func = fctiwz;	type = XB;	break;
    310		case FCMPO:	func = fcmpo;	type = XCR;	break;
    311		case MTFSB1:	func = mtfsb1;	type = XCRB;	break;
    312		case FNEG:	func = fneg;	type = XB;	break;
    313		case MCRFS:	func = mcrfs;	type = XCRL;	break;
    314		case MTFSB0:	func = mtfsb0;	type = XCRB;	break;
    315		case FMR:	func = fmr;	type = XB;	break;
    316		case MTFSFI:	func = mtfsfi;	type = XCRI;	break;
    317		case FNABS:	func = fnabs;	type = XB;	break;
    318		case FABS:	func = fabs;	type = XB;	break;
    319		case MFFS:	func = mffs;	type = X;	break;
    320		case MTFSF:	func = mtfsf;	type = XFLB;	break;
    321		default:
    322			goto illegal;
    323		}
    324		break;
    325
    326	default:
    327		goto illegal;
    328	}
    329
    330	switch (type) {
    331	case AB:
    332		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    333		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
    334		op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
    335		break;
    336
    337	case AC:
    338		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    339		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
    340		op2 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
    341		break;
    342
    343	case ABC:
    344		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    345		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
    346		op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
    347		op3 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
    348		break;
    349
    350	case D:
    351		idx = (insn >> 16) & 0x1f;
    352		sdisp = (insn & 0xffff);
    353		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    354		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
    355		break;
    356
    357	case DU:
    358		idx = (insn >> 16) & 0x1f;
    359		if (!idx)
    360			goto illegal;
    361
    362		sdisp = (insn & 0xffff);
    363		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    364		op1 = (void *)(regs->gpr[idx] + sdisp);
    365		break;
    366
    367	case X:
    368		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    369		break;
    370
    371	case XA:
    372		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    373		op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
    374		break;
    375
    376	case XB:
    377		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    378		op1 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
    379		break;
    380
    381	case XE:
    382		idx = (insn >> 16) & 0x1f;
    383		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    384		op1 = (void *)((idx ? regs->gpr[idx] : 0)
    385				+ regs->gpr[(insn >> 11) & 0x1f]);
    386		break;
    387
    388	case XEU:
    389		idx = (insn >> 16) & 0x1f;
    390		if (!idx)
    391			goto illegal;
    392		op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
    393		op1 = (void *)(regs->gpr[idx]
    394				+ regs->gpr[(insn >> 11) & 0x1f]);
    395		break;
    396
    397	case XCR:
    398		op0 = (void *)&regs->ccr;
    399		op1 = (void *)((insn >> 23) & 0x7);
    400		op2 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
    401		op3 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
    402		break;
    403
    404	case XCRL:
    405		op0 = (void *)&regs->ccr;
    406		op1 = (void *)((insn >> 23) & 0x7);
    407		op2 = (void *)((insn >> 18) & 0x7);
    408		break;
    409
    410	case XCRB:
    411		op0 = (void *)((insn >> 21) & 0x1f);
    412		break;
    413
    414	case XCRI:
    415		op0 = (void *)((insn >> 23) & 0x7);
    416		op1 = (void *)((insn >> 12) & 0xf);
    417		break;
    418
    419	case XFLB:
    420		op0 = (void *)((insn >> 17) & 0xff);
    421		op1 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
    422		break;
    423
    424	default:
    425		goto illegal;
    426	}
    427
    428	/*
    429	 * If we support a HW FPU, we need to ensure the FP state
    430	 * is flushed into the thread_struct before attempting
    431	 * emulation
    432	 */
    433	flush_fp_to_thread(current);
    434
    435	eflag = func(op0, op1, op2, op3);
    436
    437	if (insn & 1) {
    438		regs->ccr &= ~(0x0f000000);
    439		regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000;
    440	}
    441
    442	trap = record_exception(regs, eflag);
    443	if (trap)
    444		return 1;
    445
    446	switch (type) {
    447	case DU:
    448	case XEU:
    449		regs->gpr[idx] = (unsigned long)op1;
    450		break;
    451
    452	default:
    453		break;
    454	}
    455
    456	regs_add_return_ip(regs, 4);
    457	return 0;
    458
    459illegal:
    460	return -ENOSYS;
    461}