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

fpu.c (5431B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
      3
      4#include <linux/ptrace.h>
      5#include <linux/uaccess.h>
      6#include <abi/reg_ops.h>
      7
      8#define MTCR_MASK	0xFC00FFE0
      9#define MFCR_MASK	0xFC00FFE0
     10#define MTCR_DIST	0xC0006420
     11#define MFCR_DIST	0xC0006020
     12
     13/*
     14 * fpu_libc_helper() is to help libc to excute:
     15 *  - mfcr %a, cr<1, 2>
     16 *  - mfcr %a, cr<2, 2>
     17 *  - mtcr %a, cr<1, 2>
     18 *  - mtcr %a, cr<2, 2>
     19 */
     20int fpu_libc_helper(struct pt_regs *regs)
     21{
     22	int fault;
     23	unsigned long instrptr, regx = 0;
     24	unsigned long index = 0, tmp = 0;
     25	unsigned long tinstr = 0;
     26	u16 instr_hi, instr_low;
     27
     28	instrptr = instruction_pointer(regs);
     29	if (instrptr & 1)
     30		return 0;
     31
     32	fault = __get_user(instr_low, (u16 *)instrptr);
     33	if (fault)
     34		return 0;
     35
     36	fault = __get_user(instr_hi, (u16 *)(instrptr + 2));
     37	if (fault)
     38		return 0;
     39
     40	tinstr = instr_hi | ((unsigned long)instr_low << 16);
     41
     42	if (((tinstr >> 21) & 0x1F) != 2)
     43		return 0;
     44
     45	if ((tinstr & MTCR_MASK) == MTCR_DIST) {
     46		index = (tinstr >> 16) & 0x1F;
     47		if (index > 13)
     48			return 0;
     49
     50		tmp = tinstr & 0x1F;
     51		if (tmp > 2)
     52			return 0;
     53
     54		regx =  *(&regs->a0 + index);
     55
     56		if (tmp == 1)
     57			mtcr("cr<1, 2>", regx);
     58		else if (tmp == 2)
     59			mtcr("cr<2, 2>", regx);
     60		else
     61			return 0;
     62
     63		regs->pc += 4;
     64		return 1;
     65	}
     66
     67	if ((tinstr & MFCR_MASK) == MFCR_DIST) {
     68		index = tinstr & 0x1F;
     69		if (index > 13)
     70			return 0;
     71
     72		tmp = ((tinstr >> 16) & 0x1F);
     73		if (tmp > 2)
     74			return 0;
     75
     76		if (tmp == 1)
     77			regx = mfcr("cr<1, 2>");
     78		else if (tmp == 2)
     79			regx = mfcr("cr<2, 2>");
     80		else
     81			return 0;
     82
     83		*(&regs->a0 + index) = regx;
     84
     85		regs->pc += 4;
     86		return 1;
     87	}
     88
     89	return 0;
     90}
     91
     92void fpu_fpe(struct pt_regs *regs)
     93{
     94	int sig, code;
     95	unsigned int fesr;
     96
     97	fesr = mfcr("cr<2, 2>");
     98
     99	sig = SIGFPE;
    100	code = FPE_FLTUNK;
    101
    102	if (fesr & FPE_ILLE) {
    103		sig = SIGILL;
    104		code = ILL_ILLOPC;
    105	} else if (fesr & FPE_IDC) {
    106		sig = SIGILL;
    107		code = ILL_ILLOPN;
    108	} else if (fesr & FPE_FEC) {
    109		sig = SIGFPE;
    110		if (fesr & FPE_IOC)
    111			code = FPE_FLTINV;
    112		else if (fesr & FPE_DZC)
    113			code = FPE_FLTDIV;
    114		else if (fesr & FPE_UFC)
    115			code = FPE_FLTUND;
    116		else if (fesr & FPE_OFC)
    117			code = FPE_FLTOVF;
    118		else if (fesr & FPE_IXC)
    119			code = FPE_FLTRES;
    120	}
    121
    122	force_sig_fault(sig, code, (void __user *)regs->pc);
    123}
    124
    125#define FMFVR_FPU_REGS(vrx, vry)	\
    126	"fmfvrl %0, "#vrx"\n"		\
    127	"fmfvrh %1, "#vrx"\n"		\
    128	"fmfvrl %2, "#vry"\n"		\
    129	"fmfvrh %3, "#vry"\n"
    130
    131#define FMTVR_FPU_REGS(vrx, vry)	\
    132	"fmtvrl "#vrx", %0\n"		\
    133	"fmtvrh "#vrx", %1\n"		\
    134	"fmtvrl "#vry", %2\n"		\
    135	"fmtvrh "#vry", %3\n"
    136
    137#define STW_FPU_REGS(a, b, c, d)	\
    138	"stw    %0, (%4, "#a")\n"	\
    139	"stw    %1, (%4, "#b")\n"	\
    140	"stw    %2, (%4, "#c")\n"	\
    141	"stw    %3, (%4, "#d")\n"
    142
    143#define LDW_FPU_REGS(a, b, c, d)	\
    144	"ldw    %0, (%4, "#a")\n"	\
    145	"ldw    %1, (%4, "#b")\n"	\
    146	"ldw    %2, (%4, "#c")\n"	\
    147	"ldw    %3, (%4, "#d")\n"
    148
    149void save_to_user_fp(struct user_fp *user_fp)
    150{
    151	unsigned long flg;
    152	unsigned long tmp1, tmp2;
    153	unsigned long *fpregs;
    154
    155	local_irq_save(flg);
    156
    157	tmp1 = mfcr("cr<1, 2>");
    158	tmp2 = mfcr("cr<2, 2>");
    159
    160	user_fp->fcr = tmp1;
    161	user_fp->fesr = tmp2;
    162
    163	fpregs = &user_fp->vr[0];
    164#ifdef CONFIG_CPU_HAS_FPUV2
    165#ifdef CONFIG_CPU_HAS_VDSP
    166	asm volatile(
    167		"vstmu.32    vr0-vr3,   (%0)\n"
    168		"vstmu.32    vr4-vr7,   (%0)\n"
    169		"vstmu.32    vr8-vr11,  (%0)\n"
    170		"vstmu.32    vr12-vr15, (%0)\n"
    171		"fstmu.64    vr16-vr31, (%0)\n"
    172		: "+a"(fpregs)
    173		::"memory");
    174#else
    175	asm volatile(
    176		"fstmu.64    vr0-vr31,  (%0)\n"
    177		: "+a"(fpregs)
    178		::"memory");
    179#endif
    180#else
    181	{
    182	unsigned long tmp3, tmp4;
    183
    184	asm volatile(
    185		FMFVR_FPU_REGS(vr0, vr1)
    186		STW_FPU_REGS(0, 4, 16, 20)
    187		FMFVR_FPU_REGS(vr2, vr3)
    188		STW_FPU_REGS(32, 36, 48, 52)
    189		FMFVR_FPU_REGS(vr4, vr5)
    190		STW_FPU_REGS(64, 68, 80, 84)
    191		FMFVR_FPU_REGS(vr6, vr7)
    192		STW_FPU_REGS(96, 100, 112, 116)
    193		"addi	%4, 128\n"
    194		FMFVR_FPU_REGS(vr8, vr9)
    195		STW_FPU_REGS(0, 4, 16, 20)
    196		FMFVR_FPU_REGS(vr10, vr11)
    197		STW_FPU_REGS(32, 36, 48, 52)
    198		FMFVR_FPU_REGS(vr12, vr13)
    199		STW_FPU_REGS(64, 68, 80, 84)
    200		FMFVR_FPU_REGS(vr14, vr15)
    201		STW_FPU_REGS(96, 100, 112, 116)
    202		: "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
    203		  "=a"(tmp4), "+a"(fpregs)
    204		::"memory");
    205	}
    206#endif
    207
    208	local_irq_restore(flg);
    209}
    210
    211void restore_from_user_fp(struct user_fp *user_fp)
    212{
    213	unsigned long flg;
    214	unsigned long tmp1, tmp2;
    215	unsigned long *fpregs;
    216
    217	local_irq_save(flg);
    218
    219	tmp1 = user_fp->fcr;
    220	tmp2 = user_fp->fesr;
    221
    222	mtcr("cr<1, 2>", tmp1);
    223	mtcr("cr<2, 2>", tmp2);
    224
    225	fpregs = &user_fp->vr[0];
    226#ifdef CONFIG_CPU_HAS_FPUV2
    227#ifdef CONFIG_CPU_HAS_VDSP
    228	asm volatile(
    229		"vldmu.32    vr0-vr3,   (%0)\n"
    230		"vldmu.32    vr4-vr7,   (%0)\n"
    231		"vldmu.32    vr8-vr11,  (%0)\n"
    232		"vldmu.32    vr12-vr15, (%0)\n"
    233		"fldmu.64    vr16-vr31, (%0)\n"
    234		: "+a"(fpregs)
    235		::"memory");
    236#else
    237	asm volatile(
    238		"fldmu.64    vr0-vr31,  (%0)\n"
    239		: "+a"(fpregs)
    240		::"memory");
    241#endif
    242#else
    243	{
    244	unsigned long tmp3, tmp4;
    245
    246	asm volatile(
    247		LDW_FPU_REGS(0, 4, 16, 20)
    248		FMTVR_FPU_REGS(vr0, vr1)
    249		LDW_FPU_REGS(32, 36, 48, 52)
    250		FMTVR_FPU_REGS(vr2, vr3)
    251		LDW_FPU_REGS(64, 68, 80, 84)
    252		FMTVR_FPU_REGS(vr4, vr5)
    253		LDW_FPU_REGS(96, 100, 112, 116)
    254		FMTVR_FPU_REGS(vr6, vr7)
    255		"addi	%4, 128\n"
    256		LDW_FPU_REGS(0, 4, 16, 20)
    257		FMTVR_FPU_REGS(vr8, vr9)
    258		LDW_FPU_REGS(32, 36, 48, 52)
    259		FMTVR_FPU_REGS(vr10, vr11)
    260		LDW_FPU_REGS(64, 68, 80, 84)
    261		FMTVR_FPU_REGS(vr12, vr13)
    262		LDW_FPU_REGS(96, 100, 112, 116)
    263		FMTVR_FPU_REGS(vr14, vr15)
    264		: "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
    265		  "=a"(tmp4), "+a"(fpregs)
    266		::"memory");
    267	}
    268#endif
    269	local_irq_restore(flg);
    270}