Linux Audio

Check our new training course

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