1b0a668fbSLeonid Yegoshin /*
2b0a668fbSLeonid Yegoshin  * This file is subject to the terms and conditions of the GNU General Public
3b0a668fbSLeonid Yegoshin  * License.  See the file "COPYING" in the main directory of this archive
4b0a668fbSLeonid Yegoshin  * for more details.
5b0a668fbSLeonid Yegoshin  *
6b0a668fbSLeonid Yegoshin  * Copyright (c) 2014 Imagination Technologies Ltd.
7b0a668fbSLeonid Yegoshin  * Author: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
8b0a668fbSLeonid Yegoshin  * Author: Markos Chandras <markos.chandras@imgtec.com>
9b0a668fbSLeonid Yegoshin  *
10b0a668fbSLeonid Yegoshin  *      MIPS R2 user space instruction emulator for MIPS R6
11b0a668fbSLeonid Yegoshin  *
12b0a668fbSLeonid Yegoshin  */
13b0a668fbSLeonid Yegoshin #include <linux/bug.h>
14b0a668fbSLeonid Yegoshin #include <linux/compiler.h>
15b0a668fbSLeonid Yegoshin #include <linux/debugfs.h>
16b0a668fbSLeonid Yegoshin #include <linux/init.h>
17b0a668fbSLeonid Yegoshin #include <linux/kernel.h>
18b0a668fbSLeonid Yegoshin #include <linux/ptrace.h>
19b0a668fbSLeonid Yegoshin #include <linux/seq_file.h>
20b0a668fbSLeonid Yegoshin 
21b0a668fbSLeonid Yegoshin #include <asm/asm.h>
22b0a668fbSLeonid Yegoshin #include <asm/branch.h>
23b0a668fbSLeonid Yegoshin #include <asm/break.h>
2475dcfc1dSPaul Burton #include <asm/debug.h>
25b0a668fbSLeonid Yegoshin #include <asm/fpu.h>
26b0a668fbSLeonid Yegoshin #include <asm/fpu_emulator.h>
27b0a668fbSLeonid Yegoshin #include <asm/inst.h>
28b0a668fbSLeonid Yegoshin #include <asm/mips-r2-to-r6-emul.h>
29b0a668fbSLeonid Yegoshin #include <asm/local.h>
3041fa29e4SLeonid Yegoshin #include <asm/mipsregs.h>
31b0a668fbSLeonid Yegoshin #include <asm/ptrace.h>
327c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
33b0a668fbSLeonid Yegoshin 
34b0a668fbSLeonid Yegoshin #ifdef CONFIG_64BIT
35b0a668fbSLeonid Yegoshin #define ADDIU	"daddiu "
36b0a668fbSLeonid Yegoshin #define INS	"dins "
37b0a668fbSLeonid Yegoshin #define EXT	"dext "
38b0a668fbSLeonid Yegoshin #else
39b0a668fbSLeonid Yegoshin #define ADDIU	"addiu "
40b0a668fbSLeonid Yegoshin #define INS	"ins "
41b0a668fbSLeonid Yegoshin #define EXT	"ext "
42b0a668fbSLeonid Yegoshin #endif /* CONFIG_64BIT */
43b0a668fbSLeonid Yegoshin 
44b0a668fbSLeonid Yegoshin #define SB	"sb "
45b0a668fbSLeonid Yegoshin #define LB	"lb "
46b0a668fbSLeonid Yegoshin #define LL	"ll "
47b0a668fbSLeonid Yegoshin #define SC	"sc "
48b0a668fbSLeonid Yegoshin 
49b7fc2cc5SPaul Burton #ifdef CONFIG_DEBUG_FS
50b7fc2cc5SPaul Burton static DEFINE_PER_CPU(struct mips_r2_emulator_stats, mipsr2emustats);
51b7fc2cc5SPaul Burton static DEFINE_PER_CPU(struct mips_r2_emulator_stats, mipsr2bdemustats);
52b7fc2cc5SPaul Burton static DEFINE_PER_CPU(struct mips_r2br_emulator_stats, mipsr2bremustats);
53b7fc2cc5SPaul Burton #endif
54b0a668fbSLeonid Yegoshin 
55b0a668fbSLeonid Yegoshin extern const unsigned int fpucondbit[8];
56b0a668fbSLeonid Yegoshin 
57b0a668fbSLeonid Yegoshin #define MIPS_R2_EMUL_TOTAL_PASS	10
58b0a668fbSLeonid Yegoshin 
59b0a668fbSLeonid Yegoshin int mipsr2_emulation = 0;
60b0a668fbSLeonid Yegoshin 
mipsr2emu_enable(char * s)61b0a668fbSLeonid Yegoshin static int __init mipsr2emu_enable(char *s)
62b0a668fbSLeonid Yegoshin {
63b0a668fbSLeonid Yegoshin 	mipsr2_emulation = 1;
64b0a668fbSLeonid Yegoshin 
65b0a668fbSLeonid Yegoshin 	pr_info("MIPS R2-to-R6 Emulator Enabled!");
66b0a668fbSLeonid Yegoshin 
67b0a668fbSLeonid Yegoshin 	return 1;
68b0a668fbSLeonid Yegoshin }
69b0a668fbSLeonid Yegoshin __setup("mipsr2emu", mipsr2emu_enable);
70b0a668fbSLeonid Yegoshin 
71b0a668fbSLeonid Yegoshin /**
72b0a668fbSLeonid Yegoshin  * mipsr6_emul - Emulate some frequent R2/R5/R6 instructions in delay slot
73b0a668fbSLeonid Yegoshin  * for performance instead of the traditional way of using a stack trampoline
74b0a668fbSLeonid Yegoshin  * which is rather slow.
75b0a668fbSLeonid Yegoshin  * @regs: Process register set
76b0a668fbSLeonid Yegoshin  * @ir: Instruction
77b0a668fbSLeonid Yegoshin  */
mipsr6_emul(struct pt_regs * regs,u32 ir)78b0a668fbSLeonid Yegoshin static inline int mipsr6_emul(struct pt_regs *regs, u32 ir)
79b0a668fbSLeonid Yegoshin {
80b0a668fbSLeonid Yegoshin 	switch (MIPSInst_OPCODE(ir)) {
81b0a668fbSLeonid Yegoshin 	case addiu_op:
82b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(ir))
83b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(ir)] =
84b0a668fbSLeonid Yegoshin 				(s32)regs->regs[MIPSInst_RS(ir)] +
85b0a668fbSLeonid Yegoshin 				(s32)MIPSInst_SIMM(ir);
86b0a668fbSLeonid Yegoshin 		return 0;
87b0a668fbSLeonid Yegoshin 	case daddiu_op:
8897f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT))
89b0a668fbSLeonid Yegoshin 			break;
90b0a668fbSLeonid Yegoshin 
91b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(ir))
92b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(ir)] =
93b0a668fbSLeonid Yegoshin 				(s64)regs->regs[MIPSInst_RS(ir)] +
94b0a668fbSLeonid Yegoshin 				(s64)MIPSInst_SIMM(ir);
95b0a668fbSLeonid Yegoshin 		return 0;
96b0a668fbSLeonid Yegoshin 	case lwc1_op:
97b0a668fbSLeonid Yegoshin 	case swc1_op:
98b0a668fbSLeonid Yegoshin 	case cop1_op:
99b0a668fbSLeonid Yegoshin 	case cop1x_op:
100b0a668fbSLeonid Yegoshin 		/* FPU instructions in delay slot */
101b0a668fbSLeonid Yegoshin 		return -SIGFPE;
102b0a668fbSLeonid Yegoshin 	case spec_op:
103b0a668fbSLeonid Yegoshin 		switch (MIPSInst_FUNC(ir)) {
104b0a668fbSLeonid Yegoshin 		case or_op:
105b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
106b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
107b0a668fbSLeonid Yegoshin 					regs->regs[MIPSInst_RS(ir)] |
108b0a668fbSLeonid Yegoshin 					regs->regs[MIPSInst_RT(ir)];
109b0a668fbSLeonid Yegoshin 			return 0;
110b0a668fbSLeonid Yegoshin 		case sll_op:
111b0a668fbSLeonid Yegoshin 			if (MIPSInst_RS(ir))
112b0a668fbSLeonid Yegoshin 				break;
113b0a668fbSLeonid Yegoshin 
114b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
115b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
116b0a668fbSLeonid Yegoshin 					(s32)(((u32)regs->regs[MIPSInst_RT(ir)]) <<
117b0a668fbSLeonid Yegoshin 						MIPSInst_FD(ir));
118b0a668fbSLeonid Yegoshin 			return 0;
119b0a668fbSLeonid Yegoshin 		case srl_op:
120b0a668fbSLeonid Yegoshin 			if (MIPSInst_RS(ir))
121b0a668fbSLeonid Yegoshin 				break;
122b0a668fbSLeonid Yegoshin 
123b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
124b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
125b0a668fbSLeonid Yegoshin 					(s32)(((u32)regs->regs[MIPSInst_RT(ir)]) >>
126b0a668fbSLeonid Yegoshin 						MIPSInst_FD(ir));
127b0a668fbSLeonid Yegoshin 			return 0;
128b0a668fbSLeonid Yegoshin 		case addu_op:
129b0a668fbSLeonid Yegoshin 			if (MIPSInst_FD(ir))
130b0a668fbSLeonid Yegoshin 				break;
131b0a668fbSLeonid Yegoshin 
132b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
133b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
134b0a668fbSLeonid Yegoshin 					(s32)((u32)regs->regs[MIPSInst_RS(ir)] +
135b0a668fbSLeonid Yegoshin 					      (u32)regs->regs[MIPSInst_RT(ir)]);
136b0a668fbSLeonid Yegoshin 			return 0;
137b0a668fbSLeonid Yegoshin 		case subu_op:
138b0a668fbSLeonid Yegoshin 			if (MIPSInst_FD(ir))
139b0a668fbSLeonid Yegoshin 				break;
140b0a668fbSLeonid Yegoshin 
141b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
142b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
143b0a668fbSLeonid Yegoshin 					(s32)((u32)regs->regs[MIPSInst_RS(ir)] -
144b0a668fbSLeonid Yegoshin 					      (u32)regs->regs[MIPSInst_RT(ir)]);
145b0a668fbSLeonid Yegoshin 			return 0;
146b0a668fbSLeonid Yegoshin 		case dsll_op:
14797f2645fSMasahiro Yamada 			if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_RS(ir))
148b0a668fbSLeonid Yegoshin 				break;
149b0a668fbSLeonid Yegoshin 
150b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
151b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
152b0a668fbSLeonid Yegoshin 					(s64)(((u64)regs->regs[MIPSInst_RT(ir)]) <<
153b0a668fbSLeonid Yegoshin 						MIPSInst_FD(ir));
154b0a668fbSLeonid Yegoshin 			return 0;
155b0a668fbSLeonid Yegoshin 		case dsrl_op:
15697f2645fSMasahiro Yamada 			if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_RS(ir))
157b0a668fbSLeonid Yegoshin 				break;
158b0a668fbSLeonid Yegoshin 
159b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
160b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
161b0a668fbSLeonid Yegoshin 					(s64)(((u64)regs->regs[MIPSInst_RT(ir)]) >>
162b0a668fbSLeonid Yegoshin 						MIPSInst_FD(ir));
163b0a668fbSLeonid Yegoshin 			return 0;
164b0a668fbSLeonid Yegoshin 		case daddu_op:
16597f2645fSMasahiro Yamada 			if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_FD(ir))
166b0a668fbSLeonid Yegoshin 				break;
167b0a668fbSLeonid Yegoshin 
168b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
169b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
170b0a668fbSLeonid Yegoshin 					(u64)regs->regs[MIPSInst_RS(ir)] +
171b0a668fbSLeonid Yegoshin 					(u64)regs->regs[MIPSInst_RT(ir)];
172b0a668fbSLeonid Yegoshin 			return 0;
173b0a668fbSLeonid Yegoshin 		case dsubu_op:
17497f2645fSMasahiro Yamada 			if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_FD(ir))
175b0a668fbSLeonid Yegoshin 				break;
176b0a668fbSLeonid Yegoshin 
177b0a668fbSLeonid Yegoshin 			if (MIPSInst_RD(ir))
178b0a668fbSLeonid Yegoshin 				regs->regs[MIPSInst_RD(ir)] =
179b0a668fbSLeonid Yegoshin 					(s64)((u64)regs->regs[MIPSInst_RS(ir)] -
180b0a668fbSLeonid Yegoshin 					      (u64)regs->regs[MIPSInst_RT(ir)]);
181b0a668fbSLeonid Yegoshin 			return 0;
182b0a668fbSLeonid Yegoshin 		}
183b0a668fbSLeonid Yegoshin 		break;
184b0a668fbSLeonid Yegoshin 	default:
185b0a668fbSLeonid Yegoshin 		pr_debug("No fastpath BD emulation for instruction 0x%08x (op: %02x)\n",
186b0a668fbSLeonid Yegoshin 			 ir, MIPSInst_OPCODE(ir));
187b0a668fbSLeonid Yegoshin 	}
188b0a668fbSLeonid Yegoshin 
189b0a668fbSLeonid Yegoshin 	return SIGILL;
190b0a668fbSLeonid Yegoshin }
191b0a668fbSLeonid Yegoshin 
192b0a668fbSLeonid Yegoshin /**
193241e9c46SMaciej W. Rozycki  * movf_func - Emulate a MOVF instruction
194b0a668fbSLeonid Yegoshin  * @regs: Process register set
195b0a668fbSLeonid Yegoshin  * @ir: Instruction
196b0a668fbSLeonid Yegoshin  *
197b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
198b0a668fbSLeonid Yegoshin  */
movf_func(struct pt_regs * regs,u32 ir)199b0a668fbSLeonid Yegoshin static int movf_func(struct pt_regs *regs, u32 ir)
200b0a668fbSLeonid Yegoshin {
201b0a668fbSLeonid Yegoshin 	u32 csr;
202b0a668fbSLeonid Yegoshin 	u32 cond;
203b0a668fbSLeonid Yegoshin 
204b0a668fbSLeonid Yegoshin 	csr = current->thread.fpu.fcr31;
205b0a668fbSLeonid Yegoshin 	cond = fpucondbit[MIPSInst_RT(ir) >> 2];
206241e9c46SMaciej W. Rozycki 
207b0a668fbSLeonid Yegoshin 	if (((csr & cond) == 0) && MIPSInst_RD(ir))
208b0a668fbSLeonid Yegoshin 		regs->regs[MIPSInst_RD(ir)] = regs->regs[MIPSInst_RS(ir)];
209241e9c46SMaciej W. Rozycki 
210b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(movs);
211241e9c46SMaciej W. Rozycki 
212b0a668fbSLeonid Yegoshin 	return 0;
213b0a668fbSLeonid Yegoshin }
214b0a668fbSLeonid Yegoshin 
215b0a668fbSLeonid Yegoshin /**
216b0a668fbSLeonid Yegoshin  * movt_func - Emulate a MOVT instruction
217b0a668fbSLeonid Yegoshin  * @regs: Process register set
218b0a668fbSLeonid Yegoshin  * @ir: Instruction
219b0a668fbSLeonid Yegoshin  *
220b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
221b0a668fbSLeonid Yegoshin  */
movt_func(struct pt_regs * regs,u32 ir)222b0a668fbSLeonid Yegoshin static int movt_func(struct pt_regs *regs, u32 ir)
223b0a668fbSLeonid Yegoshin {
224b0a668fbSLeonid Yegoshin 	u32 csr;
225b0a668fbSLeonid Yegoshin 	u32 cond;
226b0a668fbSLeonid Yegoshin 
227b0a668fbSLeonid Yegoshin 	csr = current->thread.fpu.fcr31;
228b0a668fbSLeonid Yegoshin 	cond = fpucondbit[MIPSInst_RT(ir) >> 2];
229b0a668fbSLeonid Yegoshin 
230b0a668fbSLeonid Yegoshin 	if (((csr & cond) != 0) && MIPSInst_RD(ir))
231b0a668fbSLeonid Yegoshin 		regs->regs[MIPSInst_RD(ir)] = regs->regs[MIPSInst_RS(ir)];
232b0a668fbSLeonid Yegoshin 
233b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(movs);
234b0a668fbSLeonid Yegoshin 
235b0a668fbSLeonid Yegoshin 	return 0;
236b0a668fbSLeonid Yegoshin }
237b0a668fbSLeonid Yegoshin 
238b0a668fbSLeonid Yegoshin /**
239b0a668fbSLeonid Yegoshin  * jr_func - Emulate a JR instruction.
240b0a668fbSLeonid Yegoshin  * @pt_regs: Process register set
241b0a668fbSLeonid Yegoshin  * @ir: Instruction
242b0a668fbSLeonid Yegoshin  *
243b0a668fbSLeonid Yegoshin  * Returns SIGILL if JR was in delay slot, SIGEMT if we
244b0a668fbSLeonid Yegoshin  * can't compute the EPC, SIGSEGV if we can't access the
245b0a668fbSLeonid Yegoshin  * userland instruction or 0 on success.
246b0a668fbSLeonid Yegoshin  */
jr_func(struct pt_regs * regs,u32 ir)247b0a668fbSLeonid Yegoshin static int jr_func(struct pt_regs *regs, u32 ir)
248b0a668fbSLeonid Yegoshin {
249b0a668fbSLeonid Yegoshin 	int err;
250b0a668fbSLeonid Yegoshin 	unsigned long cepc, epc, nepc;
251b0a668fbSLeonid Yegoshin 	u32 nir;
252b0a668fbSLeonid Yegoshin 
253b0a668fbSLeonid Yegoshin 	if (delay_slot(regs))
254b0a668fbSLeonid Yegoshin 		return SIGILL;
255b0a668fbSLeonid Yegoshin 
256b0a668fbSLeonid Yegoshin 	/* EPC after the RI/JR instruction */
257b0a668fbSLeonid Yegoshin 	nepc = regs->cp0_epc;
258b0a668fbSLeonid Yegoshin 	/* Roll back to the reserved R2 JR instruction */
259b0a668fbSLeonid Yegoshin 	regs->cp0_epc -= 4;
260b0a668fbSLeonid Yegoshin 	epc = regs->cp0_epc;
261b0a668fbSLeonid Yegoshin 	err = __compute_return_epc(regs);
262b0a668fbSLeonid Yegoshin 
263b0a668fbSLeonid Yegoshin 	if (err < 0)
264b0a668fbSLeonid Yegoshin 		return SIGEMT;
265b0a668fbSLeonid Yegoshin 
266b0a668fbSLeonid Yegoshin 
267b0a668fbSLeonid Yegoshin 	/* Computed EPC */
268b0a668fbSLeonid Yegoshin 	cepc = regs->cp0_epc;
269b0a668fbSLeonid Yegoshin 
270b0a668fbSLeonid Yegoshin 	/* Get DS instruction */
271b0a668fbSLeonid Yegoshin 	err = __get_user(nir, (u32 __user *)nepc);
272b0a668fbSLeonid Yegoshin 	if (err)
273b0a668fbSLeonid Yegoshin 		return SIGSEGV;
274b0a668fbSLeonid Yegoshin 
275b0a668fbSLeonid Yegoshin 	MIPS_R2BR_STATS(jrs);
276b0a668fbSLeonid Yegoshin 
277b0a668fbSLeonid Yegoshin 	/* If nir == 0(NOP), then nothing else to do */
278b0a668fbSLeonid Yegoshin 	if (nir) {
279b0a668fbSLeonid Yegoshin 		/*
280b0a668fbSLeonid Yegoshin 		 * Negative err means FPU instruction in BD-slot,
281b0a668fbSLeonid Yegoshin 		 * Zero err means 'BD-slot emulation done'
282b0a668fbSLeonid Yegoshin 		 * For anything else we go back to trampoline emulation.
283b0a668fbSLeonid Yegoshin 		 */
284b0a668fbSLeonid Yegoshin 		err = mipsr6_emul(regs, nir);
285b0a668fbSLeonid Yegoshin 		if (err > 0) {
286b0a668fbSLeonid Yegoshin 			regs->cp0_epc = nepc;
287432c6bacSPaul Burton 			err = mips_dsemul(regs, nir, epc, cepc);
288b0a668fbSLeonid Yegoshin 			if (err == SIGILL)
289b0a668fbSLeonid Yegoshin 				err = SIGEMT;
290b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(dsemul);
291b0a668fbSLeonid Yegoshin 		}
292b0a668fbSLeonid Yegoshin 	}
293b0a668fbSLeonid Yegoshin 
294b0a668fbSLeonid Yegoshin 	return err;
295b0a668fbSLeonid Yegoshin }
296b0a668fbSLeonid Yegoshin 
297b0a668fbSLeonid Yegoshin /**
298b0a668fbSLeonid Yegoshin  * movz_func - Emulate a MOVZ instruction
299b0a668fbSLeonid Yegoshin  * @regs: Process register set
300b0a668fbSLeonid Yegoshin  * @ir: Instruction
301b0a668fbSLeonid Yegoshin  *
302b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
303b0a668fbSLeonid Yegoshin  */
movz_func(struct pt_regs * regs,u32 ir)304b0a668fbSLeonid Yegoshin static int movz_func(struct pt_regs *regs, u32 ir)
305b0a668fbSLeonid Yegoshin {
306b0a668fbSLeonid Yegoshin 	if (((regs->regs[MIPSInst_RT(ir)]) == 0) && MIPSInst_RD(ir))
307b0a668fbSLeonid Yegoshin 		regs->regs[MIPSInst_RD(ir)] = regs->regs[MIPSInst_RS(ir)];
308b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(movs);
309b0a668fbSLeonid Yegoshin 
310b0a668fbSLeonid Yegoshin 	return 0;
311b0a668fbSLeonid Yegoshin }
312b0a668fbSLeonid Yegoshin 
313b0a668fbSLeonid Yegoshin /**
314b0a668fbSLeonid Yegoshin  * movn_func - Emulate a MOVZ instruction
315b0a668fbSLeonid Yegoshin  * @regs: Process register set
316b0a668fbSLeonid Yegoshin  * @ir: Instruction
317b0a668fbSLeonid Yegoshin  *
318b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
319b0a668fbSLeonid Yegoshin  */
movn_func(struct pt_regs * regs,u32 ir)320b0a668fbSLeonid Yegoshin static int movn_func(struct pt_regs *regs, u32 ir)
321b0a668fbSLeonid Yegoshin {
322b0a668fbSLeonid Yegoshin 	if (((regs->regs[MIPSInst_RT(ir)]) != 0) && MIPSInst_RD(ir))
323b0a668fbSLeonid Yegoshin 		regs->regs[MIPSInst_RD(ir)] = regs->regs[MIPSInst_RS(ir)];
324b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(movs);
325b0a668fbSLeonid Yegoshin 
326b0a668fbSLeonid Yegoshin 	return 0;
327b0a668fbSLeonid Yegoshin }
328b0a668fbSLeonid Yegoshin 
329b0a668fbSLeonid Yegoshin /**
330b0a668fbSLeonid Yegoshin  * mfhi_func - Emulate a MFHI instruction
331b0a668fbSLeonid Yegoshin  * @regs: Process register set
332b0a668fbSLeonid Yegoshin  * @ir: Instruction
333b0a668fbSLeonid Yegoshin  *
334b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
335b0a668fbSLeonid Yegoshin  */
mfhi_func(struct pt_regs * regs,u32 ir)336b0a668fbSLeonid Yegoshin static int mfhi_func(struct pt_regs *regs, u32 ir)
337b0a668fbSLeonid Yegoshin {
338b0a668fbSLeonid Yegoshin 	if (MIPSInst_RD(ir))
339b0a668fbSLeonid Yegoshin 		regs->regs[MIPSInst_RD(ir)] = regs->hi;
340b0a668fbSLeonid Yegoshin 
341b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(hilo);
342b0a668fbSLeonid Yegoshin 
343b0a668fbSLeonid Yegoshin 	return 0;
344b0a668fbSLeonid Yegoshin }
345b0a668fbSLeonid Yegoshin 
346b0a668fbSLeonid Yegoshin /**
347b0a668fbSLeonid Yegoshin  * mthi_func - Emulate a MTHI instruction
348b0a668fbSLeonid Yegoshin  * @regs: Process register set
349b0a668fbSLeonid Yegoshin  * @ir: Instruction
350b0a668fbSLeonid Yegoshin  *
351b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
352b0a668fbSLeonid Yegoshin  */
mthi_func(struct pt_regs * regs,u32 ir)353b0a668fbSLeonid Yegoshin static int mthi_func(struct pt_regs *regs, u32 ir)
354b0a668fbSLeonid Yegoshin {
355b0a668fbSLeonid Yegoshin 	regs->hi = regs->regs[MIPSInst_RS(ir)];
356b0a668fbSLeonid Yegoshin 
357b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(hilo);
358b0a668fbSLeonid Yegoshin 
359b0a668fbSLeonid Yegoshin 	return 0;
360b0a668fbSLeonid Yegoshin }
361b0a668fbSLeonid Yegoshin 
362b0a668fbSLeonid Yegoshin /**
363b0a668fbSLeonid Yegoshin  * mflo_func - Emulate a MFLO instruction
364b0a668fbSLeonid Yegoshin  * @regs: Process register set
365b0a668fbSLeonid Yegoshin  * @ir: Instruction
366b0a668fbSLeonid Yegoshin  *
367b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
368b0a668fbSLeonid Yegoshin  */
mflo_func(struct pt_regs * regs,u32 ir)369b0a668fbSLeonid Yegoshin static int mflo_func(struct pt_regs *regs, u32 ir)
370b0a668fbSLeonid Yegoshin {
371b0a668fbSLeonid Yegoshin 	if (MIPSInst_RD(ir))
372b0a668fbSLeonid Yegoshin 		regs->regs[MIPSInst_RD(ir)] = regs->lo;
373b0a668fbSLeonid Yegoshin 
374b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(hilo);
375b0a668fbSLeonid Yegoshin 
376b0a668fbSLeonid Yegoshin 	return 0;
377b0a668fbSLeonid Yegoshin }
378b0a668fbSLeonid Yegoshin 
379b0a668fbSLeonid Yegoshin /**
380b0a668fbSLeonid Yegoshin  * mtlo_func - Emulate a MTLO instruction
381b0a668fbSLeonid Yegoshin  * @regs: Process register set
382b0a668fbSLeonid Yegoshin  * @ir: Instruction
383b0a668fbSLeonid Yegoshin  *
384b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
385b0a668fbSLeonid Yegoshin  */
mtlo_func(struct pt_regs * regs,u32 ir)386b0a668fbSLeonid Yegoshin static int mtlo_func(struct pt_regs *regs, u32 ir)
387b0a668fbSLeonid Yegoshin {
388b0a668fbSLeonid Yegoshin 	regs->lo = regs->regs[MIPSInst_RS(ir)];
389b0a668fbSLeonid Yegoshin 
390b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(hilo);
391b0a668fbSLeonid Yegoshin 
392b0a668fbSLeonid Yegoshin 	return 0;
393b0a668fbSLeonid Yegoshin }
394b0a668fbSLeonid Yegoshin 
395b0a668fbSLeonid Yegoshin /**
396b0a668fbSLeonid Yegoshin  * mult_func - Emulate a MULT instruction
397b0a668fbSLeonid Yegoshin  * @regs: Process register set
398b0a668fbSLeonid Yegoshin  * @ir: Instruction
399b0a668fbSLeonid Yegoshin  *
400b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
401b0a668fbSLeonid Yegoshin  */
mult_func(struct pt_regs * regs,u32 ir)402b0a668fbSLeonid Yegoshin static int mult_func(struct pt_regs *regs, u32 ir)
403b0a668fbSLeonid Yegoshin {
404b0a668fbSLeonid Yegoshin 	s64 res;
405b0a668fbSLeonid Yegoshin 	s32 rt, rs;
406b0a668fbSLeonid Yegoshin 
407b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
408b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
409b0a668fbSLeonid Yegoshin 	res = (s64)rt * (s64)rs;
410b0a668fbSLeonid Yegoshin 
411b0a668fbSLeonid Yegoshin 	rs = res;
412b0a668fbSLeonid Yegoshin 	regs->lo = (s64)rs;
413b0a668fbSLeonid Yegoshin 	rt = res >> 32;
414b0a668fbSLeonid Yegoshin 	res = (s64)rt;
415b0a668fbSLeonid Yegoshin 	regs->hi = res;
416b0a668fbSLeonid Yegoshin 
417b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(muls);
418b0a668fbSLeonid Yegoshin 
419b0a668fbSLeonid Yegoshin 	return 0;
420b0a668fbSLeonid Yegoshin }
421b0a668fbSLeonid Yegoshin 
422b0a668fbSLeonid Yegoshin /**
423b0a668fbSLeonid Yegoshin  * multu_func - Emulate a MULTU instruction
424b0a668fbSLeonid Yegoshin  * @regs: Process register set
425b0a668fbSLeonid Yegoshin  * @ir: Instruction
426b0a668fbSLeonid Yegoshin  *
427b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
428b0a668fbSLeonid Yegoshin  */
multu_func(struct pt_regs * regs,u32 ir)429b0a668fbSLeonid Yegoshin static int multu_func(struct pt_regs *regs, u32 ir)
430b0a668fbSLeonid Yegoshin {
431b0a668fbSLeonid Yegoshin 	u64 res;
432b0a668fbSLeonid Yegoshin 	u32 rt, rs;
433b0a668fbSLeonid Yegoshin 
434b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
435b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
436b0a668fbSLeonid Yegoshin 	res = (u64)rt * (u64)rs;
437b0a668fbSLeonid Yegoshin 	rt = res;
438d65e5677SLeonid Yegoshin 	regs->lo = (s64)(s32)rt;
439d65e5677SLeonid Yegoshin 	regs->hi = (s64)(s32)(res >> 32);
440b0a668fbSLeonid Yegoshin 
441b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(muls);
442b0a668fbSLeonid Yegoshin 
443b0a668fbSLeonid Yegoshin 	return 0;
444b0a668fbSLeonid Yegoshin }
445b0a668fbSLeonid Yegoshin 
446b0a668fbSLeonid Yegoshin /**
447b0a668fbSLeonid Yegoshin  * div_func - Emulate a DIV instruction
448b0a668fbSLeonid Yegoshin  * @regs: Process register set
449b0a668fbSLeonid Yegoshin  * @ir: Instruction
450b0a668fbSLeonid Yegoshin  *
451b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
452b0a668fbSLeonid Yegoshin  */
div_func(struct pt_regs * regs,u32 ir)453b0a668fbSLeonid Yegoshin static int div_func(struct pt_regs *regs, u32 ir)
454b0a668fbSLeonid Yegoshin {
455b0a668fbSLeonid Yegoshin 	s32 rt, rs;
456b0a668fbSLeonid Yegoshin 
457b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
458b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
459b0a668fbSLeonid Yegoshin 
460b0a668fbSLeonid Yegoshin 	regs->lo = (s64)(rs / rt);
461b0a668fbSLeonid Yegoshin 	regs->hi = (s64)(rs % rt);
462b0a668fbSLeonid Yegoshin 
463b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(divs);
464b0a668fbSLeonid Yegoshin 
465b0a668fbSLeonid Yegoshin 	return 0;
466b0a668fbSLeonid Yegoshin }
467b0a668fbSLeonid Yegoshin 
468b0a668fbSLeonid Yegoshin /**
469b0a668fbSLeonid Yegoshin  * divu_func - Emulate a DIVU instruction
470b0a668fbSLeonid Yegoshin  * @regs: Process register set
471b0a668fbSLeonid Yegoshin  * @ir: Instruction
472b0a668fbSLeonid Yegoshin  *
473b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
474b0a668fbSLeonid Yegoshin  */
divu_func(struct pt_regs * regs,u32 ir)475b0a668fbSLeonid Yegoshin static int divu_func(struct pt_regs *regs, u32 ir)
476b0a668fbSLeonid Yegoshin {
477b0a668fbSLeonid Yegoshin 	u32 rt, rs;
478b0a668fbSLeonid Yegoshin 
479b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
480b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
481b0a668fbSLeonid Yegoshin 
482b0a668fbSLeonid Yegoshin 	regs->lo = (s64)(rs / rt);
483b0a668fbSLeonid Yegoshin 	regs->hi = (s64)(rs % rt);
484b0a668fbSLeonid Yegoshin 
485b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(divs);
486b0a668fbSLeonid Yegoshin 
487b0a668fbSLeonid Yegoshin 	return 0;
488b0a668fbSLeonid Yegoshin }
489b0a668fbSLeonid Yegoshin 
490b0a668fbSLeonid Yegoshin /**
491b0a668fbSLeonid Yegoshin  * dmult_func - Emulate a DMULT instruction
492b0a668fbSLeonid Yegoshin  * @regs: Process register set
493b0a668fbSLeonid Yegoshin  * @ir: Instruction
494b0a668fbSLeonid Yegoshin  *
495b0a668fbSLeonid Yegoshin  * Returns 0 on success or SIGILL for 32-bit kernels.
496b0a668fbSLeonid Yegoshin  */
dmult_func(struct pt_regs * regs,u32 ir)497b0a668fbSLeonid Yegoshin static int dmult_func(struct pt_regs *regs, u32 ir)
498b0a668fbSLeonid Yegoshin {
499b0a668fbSLeonid Yegoshin 	s64 res;
500b0a668fbSLeonid Yegoshin 	s64 rt, rs;
501b0a668fbSLeonid Yegoshin 
50297f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_32BIT))
503b0a668fbSLeonid Yegoshin 		return SIGILL;
504b0a668fbSLeonid Yegoshin 
505b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
506b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
507b0a668fbSLeonid Yegoshin 	res = rt * rs;
508b0a668fbSLeonid Yegoshin 
509b0a668fbSLeonid Yegoshin 	regs->lo = res;
510b0a668fbSLeonid Yegoshin 	__asm__ __volatile__(
511b0a668fbSLeonid Yegoshin 		"dmuh %0, %1, %2\t\n"
512b0a668fbSLeonid Yegoshin 		: "=r"(res)
513b0a668fbSLeonid Yegoshin 		: "r"(rt), "r"(rs));
514b0a668fbSLeonid Yegoshin 
515b0a668fbSLeonid Yegoshin 	regs->hi = res;
516b0a668fbSLeonid Yegoshin 
517b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(muls);
518b0a668fbSLeonid Yegoshin 
519b0a668fbSLeonid Yegoshin 	return 0;
520b0a668fbSLeonid Yegoshin }
521b0a668fbSLeonid Yegoshin 
522b0a668fbSLeonid Yegoshin /**
523b0a668fbSLeonid Yegoshin  * dmultu_func - Emulate a DMULTU instruction
524b0a668fbSLeonid Yegoshin  * @regs: Process register set
525b0a668fbSLeonid Yegoshin  * @ir: Instruction
526b0a668fbSLeonid Yegoshin  *
527b0a668fbSLeonid Yegoshin  * Returns 0 on success or SIGILL for 32-bit kernels.
528b0a668fbSLeonid Yegoshin  */
dmultu_func(struct pt_regs * regs,u32 ir)529b0a668fbSLeonid Yegoshin static int dmultu_func(struct pt_regs *regs, u32 ir)
530b0a668fbSLeonid Yegoshin {
531b0a668fbSLeonid Yegoshin 	u64 res;
532b0a668fbSLeonid Yegoshin 	u64 rt, rs;
533b0a668fbSLeonid Yegoshin 
53497f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_32BIT))
535b0a668fbSLeonid Yegoshin 		return SIGILL;
536b0a668fbSLeonid Yegoshin 
537b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
538b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
539b0a668fbSLeonid Yegoshin 	res = rt * rs;
540b0a668fbSLeonid Yegoshin 
541b0a668fbSLeonid Yegoshin 	regs->lo = res;
542b0a668fbSLeonid Yegoshin 	__asm__ __volatile__(
543b0a668fbSLeonid Yegoshin 		"dmuhu %0, %1, %2\t\n"
544b0a668fbSLeonid Yegoshin 		: "=r"(res)
545b0a668fbSLeonid Yegoshin 		: "r"(rt), "r"(rs));
546b0a668fbSLeonid Yegoshin 
547b0a668fbSLeonid Yegoshin 	regs->hi = res;
548b0a668fbSLeonid Yegoshin 
549b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(muls);
550b0a668fbSLeonid Yegoshin 
551b0a668fbSLeonid Yegoshin 	return 0;
552b0a668fbSLeonid Yegoshin }
553b0a668fbSLeonid Yegoshin 
554b0a668fbSLeonid Yegoshin /**
555b0a668fbSLeonid Yegoshin  * ddiv_func - Emulate a DDIV instruction
556b0a668fbSLeonid Yegoshin  * @regs: Process register set
557b0a668fbSLeonid Yegoshin  * @ir: Instruction
558b0a668fbSLeonid Yegoshin  *
559b0a668fbSLeonid Yegoshin  * Returns 0 on success or SIGILL for 32-bit kernels.
560b0a668fbSLeonid Yegoshin  */
ddiv_func(struct pt_regs * regs,u32 ir)561b0a668fbSLeonid Yegoshin static int ddiv_func(struct pt_regs *regs, u32 ir)
562b0a668fbSLeonid Yegoshin {
563b0a668fbSLeonid Yegoshin 	s64 rt, rs;
564b0a668fbSLeonid Yegoshin 
56597f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_32BIT))
566b0a668fbSLeonid Yegoshin 		return SIGILL;
567b0a668fbSLeonid Yegoshin 
568b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
569b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
570b0a668fbSLeonid Yegoshin 
571b0a668fbSLeonid Yegoshin 	regs->lo = rs / rt;
572b0a668fbSLeonid Yegoshin 	regs->hi = rs % rt;
573b0a668fbSLeonid Yegoshin 
574b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(divs);
575b0a668fbSLeonid Yegoshin 
576b0a668fbSLeonid Yegoshin 	return 0;
577b0a668fbSLeonid Yegoshin }
578b0a668fbSLeonid Yegoshin 
579b0a668fbSLeonid Yegoshin /**
580b0a668fbSLeonid Yegoshin  * ddivu_func - Emulate a DDIVU instruction
581b0a668fbSLeonid Yegoshin  * @regs: Process register set
582b0a668fbSLeonid Yegoshin  * @ir: Instruction
583b0a668fbSLeonid Yegoshin  *
584b0a668fbSLeonid Yegoshin  * Returns 0 on success or SIGILL for 32-bit kernels.
585b0a668fbSLeonid Yegoshin  */
ddivu_func(struct pt_regs * regs,u32 ir)586b0a668fbSLeonid Yegoshin static int ddivu_func(struct pt_regs *regs, u32 ir)
587b0a668fbSLeonid Yegoshin {
588b0a668fbSLeonid Yegoshin 	u64 rt, rs;
589b0a668fbSLeonid Yegoshin 
59097f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_32BIT))
591b0a668fbSLeonid Yegoshin 		return SIGILL;
592b0a668fbSLeonid Yegoshin 
593b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
594b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
595b0a668fbSLeonid Yegoshin 
596b0a668fbSLeonid Yegoshin 	regs->lo = rs / rt;
597b0a668fbSLeonid Yegoshin 	regs->hi = rs % rt;
598b0a668fbSLeonid Yegoshin 
599b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(divs);
600b0a668fbSLeonid Yegoshin 
601b0a668fbSLeonid Yegoshin 	return 0;
602b0a668fbSLeonid Yegoshin }
603b0a668fbSLeonid Yegoshin 
604b0a668fbSLeonid Yegoshin /* R6 removed instructions for the SPECIAL opcode */
605114c3708SMatt Redfearn static const struct r2_decoder_table spec_op_table[] = {
606b0a668fbSLeonid Yegoshin 	{ 0xfc1ff83f, 0x00000008, jr_func },
607b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x00000018, mult_func },
608b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x00000019, multu_func },
609b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x0000001c, dmult_func },
610b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x0000001d, dmultu_func },
611b0a668fbSLeonid Yegoshin 	{ 0xffff07ff, 0x00000010, mfhi_func },
612b0a668fbSLeonid Yegoshin 	{ 0xfc1fffff, 0x00000011, mthi_func },
613b0a668fbSLeonid Yegoshin 	{ 0xffff07ff, 0x00000012, mflo_func },
614b0a668fbSLeonid Yegoshin 	{ 0xfc1fffff, 0x00000013, mtlo_func },
615b0a668fbSLeonid Yegoshin 	{ 0xfc0307ff, 0x00000001, movf_func },
616b0a668fbSLeonid Yegoshin 	{ 0xfc0307ff, 0x00010001, movt_func },
617b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x0000000a, movz_func },
618b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x0000000b, movn_func },
619b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x0000001a, div_func },
620b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x0000001b, divu_func },
621b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x0000001e, ddiv_func },
622b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x0000001f, ddivu_func },
623b0a668fbSLeonid Yegoshin 	{}
624b0a668fbSLeonid Yegoshin };
625b0a668fbSLeonid Yegoshin 
626b0a668fbSLeonid Yegoshin /**
627b0a668fbSLeonid Yegoshin  * madd_func - Emulate a MADD instruction
628b0a668fbSLeonid Yegoshin  * @regs: Process register set
629b0a668fbSLeonid Yegoshin  * @ir: Instruction
630b0a668fbSLeonid Yegoshin  *
631b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
632b0a668fbSLeonid Yegoshin  */
madd_func(struct pt_regs * regs,u32 ir)633b0a668fbSLeonid Yegoshin static int madd_func(struct pt_regs *regs, u32 ir)
634b0a668fbSLeonid Yegoshin {
635b0a668fbSLeonid Yegoshin 	s64 res;
636b0a668fbSLeonid Yegoshin 	s32 rt, rs;
637b0a668fbSLeonid Yegoshin 
638b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
639b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
640b0a668fbSLeonid Yegoshin 	res = (s64)rt * (s64)rs;
641b0a668fbSLeonid Yegoshin 	rt = regs->hi;
642b0a668fbSLeonid Yegoshin 	rs = regs->lo;
643b0a668fbSLeonid Yegoshin 	res += ((((s64)rt) << 32) | (u32)rs);
644b0a668fbSLeonid Yegoshin 
645b0a668fbSLeonid Yegoshin 	rt = res;
646b0a668fbSLeonid Yegoshin 	regs->lo = (s64)rt;
647b0a668fbSLeonid Yegoshin 	rs = res >> 32;
648b0a668fbSLeonid Yegoshin 	regs->hi = (s64)rs;
649b0a668fbSLeonid Yegoshin 
650b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(dsps);
651b0a668fbSLeonid Yegoshin 
652b0a668fbSLeonid Yegoshin 	return 0;
653b0a668fbSLeonid Yegoshin }
654b0a668fbSLeonid Yegoshin 
655b0a668fbSLeonid Yegoshin /**
656b0a668fbSLeonid Yegoshin  * maddu_func - Emulate a MADDU instruction
657b0a668fbSLeonid Yegoshin  * @regs: Process register set
658b0a668fbSLeonid Yegoshin  * @ir: Instruction
659b0a668fbSLeonid Yegoshin  *
660b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
661b0a668fbSLeonid Yegoshin  */
maddu_func(struct pt_regs * regs,u32 ir)662b0a668fbSLeonid Yegoshin static int maddu_func(struct pt_regs *regs, u32 ir)
663b0a668fbSLeonid Yegoshin {
664b0a668fbSLeonid Yegoshin 	u64 res;
665b0a668fbSLeonid Yegoshin 	u32 rt, rs;
666b0a668fbSLeonid Yegoshin 
667b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
668b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
669b0a668fbSLeonid Yegoshin 	res = (u64)rt * (u64)rs;
670b0a668fbSLeonid Yegoshin 	rt = regs->hi;
671b0a668fbSLeonid Yegoshin 	rs = regs->lo;
672b0a668fbSLeonid Yegoshin 	res += ((((s64)rt) << 32) | (u32)rs);
673b0a668fbSLeonid Yegoshin 
674b0a668fbSLeonid Yegoshin 	rt = res;
675d65e5677SLeonid Yegoshin 	regs->lo = (s64)(s32)rt;
676b0a668fbSLeonid Yegoshin 	rs = res >> 32;
677d65e5677SLeonid Yegoshin 	regs->hi = (s64)(s32)rs;
678b0a668fbSLeonid Yegoshin 
679b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(dsps);
680b0a668fbSLeonid Yegoshin 
681b0a668fbSLeonid Yegoshin 	return 0;
682b0a668fbSLeonid Yegoshin }
683b0a668fbSLeonid Yegoshin 
684b0a668fbSLeonid Yegoshin /**
685b0a668fbSLeonid Yegoshin  * msub_func - Emulate a MSUB instruction
686b0a668fbSLeonid Yegoshin  * @regs: Process register set
687b0a668fbSLeonid Yegoshin  * @ir: Instruction
688b0a668fbSLeonid Yegoshin  *
689b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
690b0a668fbSLeonid Yegoshin  */
msub_func(struct pt_regs * regs,u32 ir)691b0a668fbSLeonid Yegoshin static int msub_func(struct pt_regs *regs, u32 ir)
692b0a668fbSLeonid Yegoshin {
693b0a668fbSLeonid Yegoshin 	s64 res;
694b0a668fbSLeonid Yegoshin 	s32 rt, rs;
695b0a668fbSLeonid Yegoshin 
696b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
697b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
698b0a668fbSLeonid Yegoshin 	res = (s64)rt * (s64)rs;
699b0a668fbSLeonid Yegoshin 	rt = regs->hi;
700b0a668fbSLeonid Yegoshin 	rs = regs->lo;
701b0a668fbSLeonid Yegoshin 	res = ((((s64)rt) << 32) | (u32)rs) - res;
702b0a668fbSLeonid Yegoshin 
703b0a668fbSLeonid Yegoshin 	rt = res;
704b0a668fbSLeonid Yegoshin 	regs->lo = (s64)rt;
705b0a668fbSLeonid Yegoshin 	rs = res >> 32;
706b0a668fbSLeonid Yegoshin 	regs->hi = (s64)rs;
707b0a668fbSLeonid Yegoshin 
708b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(dsps);
709b0a668fbSLeonid Yegoshin 
710b0a668fbSLeonid Yegoshin 	return 0;
711b0a668fbSLeonid Yegoshin }
712b0a668fbSLeonid Yegoshin 
713b0a668fbSLeonid Yegoshin /**
714b0a668fbSLeonid Yegoshin  * msubu_func - Emulate a MSUBU instruction
715b0a668fbSLeonid Yegoshin  * @regs: Process register set
716b0a668fbSLeonid Yegoshin  * @ir: Instruction
717b0a668fbSLeonid Yegoshin  *
718b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
719b0a668fbSLeonid Yegoshin  */
msubu_func(struct pt_regs * regs,u32 ir)720b0a668fbSLeonid Yegoshin static int msubu_func(struct pt_regs *regs, u32 ir)
721b0a668fbSLeonid Yegoshin {
722b0a668fbSLeonid Yegoshin 	u64 res;
723b0a668fbSLeonid Yegoshin 	u32 rt, rs;
724b0a668fbSLeonid Yegoshin 
725b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
726b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
727b0a668fbSLeonid Yegoshin 	res = (u64)rt * (u64)rs;
728b0a668fbSLeonid Yegoshin 	rt = regs->hi;
729b0a668fbSLeonid Yegoshin 	rs = regs->lo;
730b0a668fbSLeonid Yegoshin 	res = ((((s64)rt) << 32) | (u32)rs) - res;
731b0a668fbSLeonid Yegoshin 
732b0a668fbSLeonid Yegoshin 	rt = res;
733d65e5677SLeonid Yegoshin 	regs->lo = (s64)(s32)rt;
734b0a668fbSLeonid Yegoshin 	rs = res >> 32;
735d65e5677SLeonid Yegoshin 	regs->hi = (s64)(s32)rs;
736b0a668fbSLeonid Yegoshin 
737b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(dsps);
738b0a668fbSLeonid Yegoshin 
739b0a668fbSLeonid Yegoshin 	return 0;
740b0a668fbSLeonid Yegoshin }
741b0a668fbSLeonid Yegoshin 
742b0a668fbSLeonid Yegoshin /**
743b0a668fbSLeonid Yegoshin  * mul_func - Emulate a MUL instruction
744b0a668fbSLeonid Yegoshin  * @regs: Process register set
745b0a668fbSLeonid Yegoshin  * @ir: Instruction
746b0a668fbSLeonid Yegoshin  *
747b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
748b0a668fbSLeonid Yegoshin  */
mul_func(struct pt_regs * regs,u32 ir)749b0a668fbSLeonid Yegoshin static int mul_func(struct pt_regs *regs, u32 ir)
750b0a668fbSLeonid Yegoshin {
751b0a668fbSLeonid Yegoshin 	s64 res;
752b0a668fbSLeonid Yegoshin 	s32 rt, rs;
753b0a668fbSLeonid Yegoshin 
754b0a668fbSLeonid Yegoshin 	if (!MIPSInst_RD(ir))
755b0a668fbSLeonid Yegoshin 		return 0;
756b0a668fbSLeonid Yegoshin 	rt = regs->regs[MIPSInst_RT(ir)];
757b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
758b0a668fbSLeonid Yegoshin 	res = (s64)rt * (s64)rs;
759b0a668fbSLeonid Yegoshin 
760b0a668fbSLeonid Yegoshin 	rs = res;
761b0a668fbSLeonid Yegoshin 	regs->regs[MIPSInst_RD(ir)] = (s64)rs;
762b0a668fbSLeonid Yegoshin 
763b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(muls);
764b0a668fbSLeonid Yegoshin 
765b0a668fbSLeonid Yegoshin 	return 0;
766b0a668fbSLeonid Yegoshin }
767b0a668fbSLeonid Yegoshin 
768b0a668fbSLeonid Yegoshin /**
769b0a668fbSLeonid Yegoshin  * clz_func - Emulate a CLZ instruction
770b0a668fbSLeonid Yegoshin  * @regs: Process register set
771b0a668fbSLeonid Yegoshin  * @ir: Instruction
772b0a668fbSLeonid Yegoshin  *
773b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
774b0a668fbSLeonid Yegoshin  */
clz_func(struct pt_regs * regs,u32 ir)775b0a668fbSLeonid Yegoshin static int clz_func(struct pt_regs *regs, u32 ir)
776b0a668fbSLeonid Yegoshin {
777b0a668fbSLeonid Yegoshin 	u32 res;
778b0a668fbSLeonid Yegoshin 	u32 rs;
779b0a668fbSLeonid Yegoshin 
780b0a668fbSLeonid Yegoshin 	if (!MIPSInst_RD(ir))
781b0a668fbSLeonid Yegoshin 		return 0;
782b0a668fbSLeonid Yegoshin 
783b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
784b0a668fbSLeonid Yegoshin 	__asm__ __volatile__("clz %0, %1" : "=r"(res) : "r"(rs));
785b0a668fbSLeonid Yegoshin 	regs->regs[MIPSInst_RD(ir)] = res;
786b0a668fbSLeonid Yegoshin 
787b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(bops);
788b0a668fbSLeonid Yegoshin 
789b0a668fbSLeonid Yegoshin 	return 0;
790b0a668fbSLeonid Yegoshin }
791b0a668fbSLeonid Yegoshin 
792b0a668fbSLeonid Yegoshin /**
793b0a668fbSLeonid Yegoshin  * clo_func - Emulate a CLO instruction
794b0a668fbSLeonid Yegoshin  * @regs: Process register set
795b0a668fbSLeonid Yegoshin  * @ir: Instruction
796b0a668fbSLeonid Yegoshin  *
797b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
798b0a668fbSLeonid Yegoshin  */
799b0a668fbSLeonid Yegoshin 
clo_func(struct pt_regs * regs,u32 ir)800b0a668fbSLeonid Yegoshin static int clo_func(struct pt_regs *regs, u32 ir)
801b0a668fbSLeonid Yegoshin {
802b0a668fbSLeonid Yegoshin 	u32 res;
803b0a668fbSLeonid Yegoshin 	u32 rs;
804b0a668fbSLeonid Yegoshin 
805b0a668fbSLeonid Yegoshin 	if (!MIPSInst_RD(ir))
806b0a668fbSLeonid Yegoshin 		return 0;
807b0a668fbSLeonid Yegoshin 
808b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
809b0a668fbSLeonid Yegoshin 	__asm__ __volatile__("clo %0, %1" : "=r"(res) : "r"(rs));
810b0a668fbSLeonid Yegoshin 	regs->regs[MIPSInst_RD(ir)] = res;
811b0a668fbSLeonid Yegoshin 
812b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(bops);
813b0a668fbSLeonid Yegoshin 
814b0a668fbSLeonid Yegoshin 	return 0;
815b0a668fbSLeonid Yegoshin }
816b0a668fbSLeonid Yegoshin 
817b0a668fbSLeonid Yegoshin /**
818b0a668fbSLeonid Yegoshin  * dclz_func - Emulate a DCLZ instruction
819b0a668fbSLeonid Yegoshin  * @regs: Process register set
820b0a668fbSLeonid Yegoshin  * @ir: Instruction
821b0a668fbSLeonid Yegoshin  *
822b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
823b0a668fbSLeonid Yegoshin  */
dclz_func(struct pt_regs * regs,u32 ir)824b0a668fbSLeonid Yegoshin static int dclz_func(struct pt_regs *regs, u32 ir)
825b0a668fbSLeonid Yegoshin {
826b0a668fbSLeonid Yegoshin 	u64 res;
827b0a668fbSLeonid Yegoshin 	u64 rs;
828b0a668fbSLeonid Yegoshin 
82997f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_32BIT))
830b0a668fbSLeonid Yegoshin 		return SIGILL;
831b0a668fbSLeonid Yegoshin 
832b0a668fbSLeonid Yegoshin 	if (!MIPSInst_RD(ir))
833b0a668fbSLeonid Yegoshin 		return 0;
834b0a668fbSLeonid Yegoshin 
835b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
836b0a668fbSLeonid Yegoshin 	__asm__ __volatile__("dclz %0, %1" : "=r"(res) : "r"(rs));
837b0a668fbSLeonid Yegoshin 	regs->regs[MIPSInst_RD(ir)] = res;
838b0a668fbSLeonid Yegoshin 
839b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(bops);
840b0a668fbSLeonid Yegoshin 
841b0a668fbSLeonid Yegoshin 	return 0;
842b0a668fbSLeonid Yegoshin }
843b0a668fbSLeonid Yegoshin 
844b0a668fbSLeonid Yegoshin /**
845b0a668fbSLeonid Yegoshin  * dclo_func - Emulate a DCLO instruction
846b0a668fbSLeonid Yegoshin  * @regs: Process register set
847b0a668fbSLeonid Yegoshin  * @ir: Instruction
848b0a668fbSLeonid Yegoshin  *
849b0a668fbSLeonid Yegoshin  * Returns 0 since it always succeeds.
850b0a668fbSLeonid Yegoshin  */
dclo_func(struct pt_regs * regs,u32 ir)851b0a668fbSLeonid Yegoshin static int dclo_func(struct pt_regs *regs, u32 ir)
852b0a668fbSLeonid Yegoshin {
853b0a668fbSLeonid Yegoshin 	u64 res;
854b0a668fbSLeonid Yegoshin 	u64 rs;
855b0a668fbSLeonid Yegoshin 
85697f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_32BIT))
857b0a668fbSLeonid Yegoshin 		return SIGILL;
858b0a668fbSLeonid Yegoshin 
859b0a668fbSLeonid Yegoshin 	if (!MIPSInst_RD(ir))
860b0a668fbSLeonid Yegoshin 		return 0;
861b0a668fbSLeonid Yegoshin 
862b0a668fbSLeonid Yegoshin 	rs = regs->regs[MIPSInst_RS(ir)];
863b0a668fbSLeonid Yegoshin 	__asm__ __volatile__("dclo %0, %1" : "=r"(res) : "r"(rs));
864b0a668fbSLeonid Yegoshin 	regs->regs[MIPSInst_RD(ir)] = res;
865b0a668fbSLeonid Yegoshin 
866b0a668fbSLeonid Yegoshin 	MIPS_R2_STATS(bops);
867b0a668fbSLeonid Yegoshin 
868b0a668fbSLeonid Yegoshin 	return 0;
869b0a668fbSLeonid Yegoshin }
870b0a668fbSLeonid Yegoshin 
871b0a668fbSLeonid Yegoshin /* R6 removed instructions for the SPECIAL2 opcode */
872114c3708SMatt Redfearn static const struct r2_decoder_table spec2_op_table[] = {
873b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x70000000, madd_func },
874b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x70000001, maddu_func },
875b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x70000002, mul_func },
876b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x70000004, msub_func },
877b0a668fbSLeonid Yegoshin 	{ 0xfc00ffff, 0x70000005, msubu_func },
878b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x70000020, clz_func },
879b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x70000021, clo_func },
880b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x70000024, dclz_func },
881b0a668fbSLeonid Yegoshin 	{ 0xfc0007ff, 0x70000025, dclo_func },
882b0a668fbSLeonid Yegoshin 	{ }
883b0a668fbSLeonid Yegoshin };
884b0a668fbSLeonid Yegoshin 
mipsr2_find_op_func(struct pt_regs * regs,u32 inst,const struct r2_decoder_table * table)885b0a668fbSLeonid Yegoshin static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst,
886114c3708SMatt Redfearn 				      const struct r2_decoder_table *table)
887b0a668fbSLeonid Yegoshin {
888114c3708SMatt Redfearn 	const struct r2_decoder_table *p;
889b0a668fbSLeonid Yegoshin 	int err;
890b0a668fbSLeonid Yegoshin 
891b0a668fbSLeonid Yegoshin 	for (p = table; p->func; p++) {
892b0a668fbSLeonid Yegoshin 		if ((inst & p->mask) == p->code) {
893b0a668fbSLeonid Yegoshin 			err = (p->func)(regs, inst);
894b0a668fbSLeonid Yegoshin 			return err;
895b0a668fbSLeonid Yegoshin 		}
896b0a668fbSLeonid Yegoshin 	}
897b0a668fbSLeonid Yegoshin 	return SIGILL;
898b0a668fbSLeonid Yegoshin }
899b0a668fbSLeonid Yegoshin 
900b0a668fbSLeonid Yegoshin /**
901b0a668fbSLeonid Yegoshin  * mipsr2_decoder: Decode and emulate a MIPS R2 instruction
902b0a668fbSLeonid Yegoshin  * @regs: Process register set
903b0a668fbSLeonid Yegoshin  * @inst: Instruction to decode and emulate
9045a1aca44SMaciej W. Rozycki  * @fcr31: Floating Point Control and Status Register Cause bits returned
905b0a668fbSLeonid Yegoshin  */
mipsr2_decoder(struct pt_regs * regs,u32 inst,unsigned long * fcr31)906304acb71SMaciej W. Rozycki int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
907b0a668fbSLeonid Yegoshin {
908b0a668fbSLeonid Yegoshin 	int err = 0;
909b0a668fbSLeonid Yegoshin 	unsigned long vaddr;
910b0a668fbSLeonid Yegoshin 	u32 nir;
911b0a668fbSLeonid Yegoshin 	unsigned long cpc, epc, nepc, r31, res, rs, rt;
912b0a668fbSLeonid Yegoshin 
913b0a668fbSLeonid Yegoshin 	void __user *fault_addr = NULL;
914b0a668fbSLeonid Yegoshin 	int pass = 0;
915b0a668fbSLeonid Yegoshin 
916b0a668fbSLeonid Yegoshin repeat:
917b0a668fbSLeonid Yegoshin 	r31 = regs->regs[31];
918b0a668fbSLeonid Yegoshin 	epc = regs->cp0_epc;
919b0a668fbSLeonid Yegoshin 	err = compute_return_epc(regs);
920b0a668fbSLeonid Yegoshin 	if (err < 0) {
921b0a668fbSLeonid Yegoshin 		BUG();
922b0a668fbSLeonid Yegoshin 		return SIGEMT;
923b0a668fbSLeonid Yegoshin 	}
924b0a668fbSLeonid Yegoshin 	pr_debug("Emulating the 0x%08x R2 instruction @ 0x%08lx (pass=%d))\n",
925b0a668fbSLeonid Yegoshin 		 inst, epc, pass);
926b0a668fbSLeonid Yegoshin 
927b0a668fbSLeonid Yegoshin 	switch (MIPSInst_OPCODE(inst)) {
928b0a668fbSLeonid Yegoshin 	case spec_op:
929b0a668fbSLeonid Yegoshin 		err = mipsr2_find_op_func(regs, inst, spec_op_table);
930b0a668fbSLeonid Yegoshin 		if (err < 0) {
931b0a668fbSLeonid Yegoshin 			/* FPU instruction under JR */
932b0a668fbSLeonid Yegoshin 			regs->cp0_cause |= CAUSEF_BD;
933b0a668fbSLeonid Yegoshin 			goto fpu_emul;
934b0a668fbSLeonid Yegoshin 		}
935b0a668fbSLeonid Yegoshin 		break;
936b0a668fbSLeonid Yegoshin 	case spec2_op:
937b0a668fbSLeonid Yegoshin 		err = mipsr2_find_op_func(regs, inst, spec2_op_table);
938b0a668fbSLeonid Yegoshin 		break;
939b0a668fbSLeonid Yegoshin 	case bcond_op:
940b0a668fbSLeonid Yegoshin 		rt = MIPSInst_RT(inst);
941b0a668fbSLeonid Yegoshin 		rs = MIPSInst_RS(inst);
942b0a668fbSLeonid Yegoshin 		switch (rt) {
943b0a668fbSLeonid Yegoshin 		case tgei_op:
944b0a668fbSLeonid Yegoshin 			if ((long)regs->regs[rs] >= MIPSInst_SIMM(inst))
9453b143ccaSMaciej W. Rozycki 				do_trap_or_bp(regs, 0, 0, "TGEI");
946b0a668fbSLeonid Yegoshin 
947b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(traps);
948b0a668fbSLeonid Yegoshin 
949b0a668fbSLeonid Yegoshin 			break;
950b0a668fbSLeonid Yegoshin 		case tgeiu_op:
951b0a668fbSLeonid Yegoshin 			if (regs->regs[rs] >= MIPSInst_UIMM(inst))
9523b143ccaSMaciej W. Rozycki 				do_trap_or_bp(regs, 0, 0, "TGEIU");
953b0a668fbSLeonid Yegoshin 
954b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(traps);
955b0a668fbSLeonid Yegoshin 
956b0a668fbSLeonid Yegoshin 			break;
957b0a668fbSLeonid Yegoshin 		case tlti_op:
958b0a668fbSLeonid Yegoshin 			if ((long)regs->regs[rs] < MIPSInst_SIMM(inst))
9593b143ccaSMaciej W. Rozycki 				do_trap_or_bp(regs, 0, 0, "TLTI");
960b0a668fbSLeonid Yegoshin 
961b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(traps);
962b0a668fbSLeonid Yegoshin 
963b0a668fbSLeonid Yegoshin 			break;
964b0a668fbSLeonid Yegoshin 		case tltiu_op:
965b0a668fbSLeonid Yegoshin 			if (regs->regs[rs] < MIPSInst_UIMM(inst))
9663b143ccaSMaciej W. Rozycki 				do_trap_or_bp(regs, 0, 0, "TLTIU");
967b0a668fbSLeonid Yegoshin 
968b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(traps);
969b0a668fbSLeonid Yegoshin 
970b0a668fbSLeonid Yegoshin 			break;
971b0a668fbSLeonid Yegoshin 		case teqi_op:
972b0a668fbSLeonid Yegoshin 			if (regs->regs[rs] == MIPSInst_SIMM(inst))
9733b143ccaSMaciej W. Rozycki 				do_trap_or_bp(regs, 0, 0, "TEQI");
974b0a668fbSLeonid Yegoshin 
975b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(traps);
976b0a668fbSLeonid Yegoshin 
977b0a668fbSLeonid Yegoshin 			break;
978b0a668fbSLeonid Yegoshin 		case tnei_op:
979b0a668fbSLeonid Yegoshin 			if (regs->regs[rs] != MIPSInst_SIMM(inst))
9803b143ccaSMaciej W. Rozycki 				do_trap_or_bp(regs, 0, 0, "TNEI");
981b0a668fbSLeonid Yegoshin 
982b0a668fbSLeonid Yegoshin 			MIPS_R2_STATS(traps);
983b0a668fbSLeonid Yegoshin 
984b0a668fbSLeonid Yegoshin 			break;
985b0a668fbSLeonid Yegoshin 		case bltzl_op:
986b0a668fbSLeonid Yegoshin 		case bgezl_op:
987b0a668fbSLeonid Yegoshin 		case bltzall_op:
988b0a668fbSLeonid Yegoshin 		case bgezall_op:
989b0a668fbSLeonid Yegoshin 			if (delay_slot(regs)) {
990b0a668fbSLeonid Yegoshin 				err = SIGILL;
991b0a668fbSLeonid Yegoshin 				break;
992b0a668fbSLeonid Yegoshin 			}
993b0a668fbSLeonid Yegoshin 			regs->regs[31] = r31;
994b0a668fbSLeonid Yegoshin 			regs->cp0_epc = epc;
995b0a668fbSLeonid Yegoshin 			err = __compute_return_epc(regs);
996b0a668fbSLeonid Yegoshin 			if (err < 0)
997b0a668fbSLeonid Yegoshin 				return SIGEMT;
998b0a668fbSLeonid Yegoshin 			if (err != BRANCH_LIKELY_TAKEN)
999b0a668fbSLeonid Yegoshin 				break;
1000b0a668fbSLeonid Yegoshin 			cpc = regs->cp0_epc;
1001b0a668fbSLeonid Yegoshin 			nepc = epc + 4;
1002b0a668fbSLeonid Yegoshin 			err = __get_user(nir, (u32 __user *)nepc);
1003b0a668fbSLeonid Yegoshin 			if (err) {
1004b0a668fbSLeonid Yegoshin 				err = SIGSEGV;
1005b0a668fbSLeonid Yegoshin 				break;
1006b0a668fbSLeonid Yegoshin 			}
1007b0a668fbSLeonid Yegoshin 			/*
1008b0a668fbSLeonid Yegoshin 			 * This will probably be optimized away when
1009b0a668fbSLeonid Yegoshin 			 * CONFIG_DEBUG_FS is not enabled
1010b0a668fbSLeonid Yegoshin 			 */
1011b0a668fbSLeonid Yegoshin 			switch (rt) {
1012b0a668fbSLeonid Yegoshin 			case bltzl_op:
1013b0a668fbSLeonid Yegoshin 				MIPS_R2BR_STATS(bltzl);
1014b0a668fbSLeonid Yegoshin 				break;
1015b0a668fbSLeonid Yegoshin 			case bgezl_op:
1016b0a668fbSLeonid Yegoshin 				MIPS_R2BR_STATS(bgezl);
1017b0a668fbSLeonid Yegoshin 				break;
1018b0a668fbSLeonid Yegoshin 			case bltzall_op:
1019b0a668fbSLeonid Yegoshin 				MIPS_R2BR_STATS(bltzall);
1020b0a668fbSLeonid Yegoshin 				break;
1021b0a668fbSLeonid Yegoshin 			case bgezall_op:
1022b0a668fbSLeonid Yegoshin 				MIPS_R2BR_STATS(bgezall);
1023b0a668fbSLeonid Yegoshin 				break;
1024b0a668fbSLeonid Yegoshin 			}
1025b0a668fbSLeonid Yegoshin 
1026b0a668fbSLeonid Yegoshin 			switch (MIPSInst_OPCODE(nir)) {
1027b0a668fbSLeonid Yegoshin 			case cop1_op:
1028b0a668fbSLeonid Yegoshin 			case cop1x_op:
1029b0a668fbSLeonid Yegoshin 			case lwc1_op:
1030b0a668fbSLeonid Yegoshin 			case swc1_op:
1031b0a668fbSLeonid Yegoshin 				regs->cp0_cause |= CAUSEF_BD;
1032b0a668fbSLeonid Yegoshin 				goto fpu_emul;
1033b0a668fbSLeonid Yegoshin 			}
1034b0a668fbSLeonid Yegoshin 			if (nir) {
1035b0a668fbSLeonid Yegoshin 				err = mipsr6_emul(regs, nir);
1036b0a668fbSLeonid Yegoshin 				if (err > 0) {
1037432c6bacSPaul Burton 					err = mips_dsemul(regs, nir, epc, cpc);
1038b0a668fbSLeonid Yegoshin 					if (err == SIGILL)
1039b0a668fbSLeonid Yegoshin 						err = SIGEMT;
1040b0a668fbSLeonid Yegoshin 					MIPS_R2_STATS(dsemul);
1041b0a668fbSLeonid Yegoshin 				}
1042b0a668fbSLeonid Yegoshin 			}
1043b0a668fbSLeonid Yegoshin 			break;
1044b0a668fbSLeonid Yegoshin 		case bltzal_op:
1045b0a668fbSLeonid Yegoshin 		case bgezal_op:
1046b0a668fbSLeonid Yegoshin 			if (delay_slot(regs)) {
1047b0a668fbSLeonid Yegoshin 				err = SIGILL;
1048b0a668fbSLeonid Yegoshin 				break;
1049b0a668fbSLeonid Yegoshin 			}
1050b0a668fbSLeonid Yegoshin 			regs->regs[31] = r31;
1051b0a668fbSLeonid Yegoshin 			regs->cp0_epc = epc;
1052b0a668fbSLeonid Yegoshin 			err = __compute_return_epc(regs);
1053b0a668fbSLeonid Yegoshin 			if (err < 0)
1054b0a668fbSLeonid Yegoshin 				return SIGEMT;
1055b0a668fbSLeonid Yegoshin 			cpc = regs->cp0_epc;
1056b0a668fbSLeonid Yegoshin 			nepc = epc + 4;
1057b0a668fbSLeonid Yegoshin 			err = __get_user(nir, (u32 __user *)nepc);
1058b0a668fbSLeonid Yegoshin 			if (err) {
1059b0a668fbSLeonid Yegoshin 				err = SIGSEGV;
1060b0a668fbSLeonid Yegoshin 				break;
1061b0a668fbSLeonid Yegoshin 			}
1062b0a668fbSLeonid Yegoshin 			/*
1063b0a668fbSLeonid Yegoshin 			 * This will probably be optimized away when
1064b0a668fbSLeonid Yegoshin 			 * CONFIG_DEBUG_FS is not enabled
1065b0a668fbSLeonid Yegoshin 			 */
1066b0a668fbSLeonid Yegoshin 			switch (rt) {
1067b0a668fbSLeonid Yegoshin 			case bltzal_op:
1068b0a668fbSLeonid Yegoshin 				MIPS_R2BR_STATS(bltzal);
1069b0a668fbSLeonid Yegoshin 				break;
1070b0a668fbSLeonid Yegoshin 			case bgezal_op:
1071b0a668fbSLeonid Yegoshin 				MIPS_R2BR_STATS(bgezal);
1072b0a668fbSLeonid Yegoshin 				break;
1073b0a668fbSLeonid Yegoshin 			}
1074b0a668fbSLeonid Yegoshin 
1075b0a668fbSLeonid Yegoshin 			switch (MIPSInst_OPCODE(nir)) {
1076b0a668fbSLeonid Yegoshin 			case cop1_op:
1077b0a668fbSLeonid Yegoshin 			case cop1x_op:
1078b0a668fbSLeonid Yegoshin 			case lwc1_op:
1079b0a668fbSLeonid Yegoshin 			case swc1_op:
1080b0a668fbSLeonid Yegoshin 				regs->cp0_cause |= CAUSEF_BD;
1081b0a668fbSLeonid Yegoshin 				goto fpu_emul;
1082b0a668fbSLeonid Yegoshin 			}
1083b0a668fbSLeonid Yegoshin 			if (nir) {
1084b0a668fbSLeonid Yegoshin 				err = mipsr6_emul(regs, nir);
1085b0a668fbSLeonid Yegoshin 				if (err > 0) {
1086432c6bacSPaul Burton 					err = mips_dsemul(regs, nir, epc, cpc);
1087b0a668fbSLeonid Yegoshin 					if (err == SIGILL)
1088b0a668fbSLeonid Yegoshin 						err = SIGEMT;
1089b0a668fbSLeonid Yegoshin 					MIPS_R2_STATS(dsemul);
1090b0a668fbSLeonid Yegoshin 				}
1091b0a668fbSLeonid Yegoshin 			}
1092b0a668fbSLeonid Yegoshin 			break;
1093b0a668fbSLeonid Yegoshin 		default:
1094b0a668fbSLeonid Yegoshin 			regs->regs[31] = r31;
1095b0a668fbSLeonid Yegoshin 			regs->cp0_epc = epc;
1096b0a668fbSLeonid Yegoshin 			err = SIGILL;
1097b0a668fbSLeonid Yegoshin 			break;
1098b0a668fbSLeonid Yegoshin 		}
1099b0a668fbSLeonid Yegoshin 		break;
1100b0a668fbSLeonid Yegoshin 
1101b0a668fbSLeonid Yegoshin 	case blezl_op:
1102b0a668fbSLeonid Yegoshin 	case bgtzl_op:
11035bba7aa4SLeonid Yegoshin 		/*
11045bba7aa4SLeonid Yegoshin 		 * For BLEZL and BGTZL, rt field must be set to 0. If this
11055bba7aa4SLeonid Yegoshin 		 * is not the case, this may be an encoding of a MIPS R6
11065bba7aa4SLeonid Yegoshin 		 * instruction, so return to CPU execution if this occurs
11075bba7aa4SLeonid Yegoshin 		 */
11085bba7aa4SLeonid Yegoshin 		if (MIPSInst_RT(inst)) {
11095bba7aa4SLeonid Yegoshin 			err = SIGILL;
11105bba7aa4SLeonid Yegoshin 			break;
11115bba7aa4SLeonid Yegoshin 		}
1112c9b02990SLiangliang Huang 		fallthrough;
11135bba7aa4SLeonid Yegoshin 	case beql_op:
11145bba7aa4SLeonid Yegoshin 	case bnel_op:
1115b0a668fbSLeonid Yegoshin 		if (delay_slot(regs)) {
1116b0a668fbSLeonid Yegoshin 			err = SIGILL;
1117b0a668fbSLeonid Yegoshin 			break;
1118b0a668fbSLeonid Yegoshin 		}
1119b0a668fbSLeonid Yegoshin 		regs->regs[31] = r31;
1120b0a668fbSLeonid Yegoshin 		regs->cp0_epc = epc;
1121b0a668fbSLeonid Yegoshin 		err = __compute_return_epc(regs);
1122b0a668fbSLeonid Yegoshin 		if (err < 0)
1123b0a668fbSLeonid Yegoshin 			return SIGEMT;
1124b0a668fbSLeonid Yegoshin 		if (err != BRANCH_LIKELY_TAKEN)
1125b0a668fbSLeonid Yegoshin 			break;
1126b0a668fbSLeonid Yegoshin 		cpc = regs->cp0_epc;
1127b0a668fbSLeonid Yegoshin 		nepc = epc + 4;
1128b0a668fbSLeonid Yegoshin 		err = __get_user(nir, (u32 __user *)nepc);
1129b0a668fbSLeonid Yegoshin 		if (err) {
1130b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1131b0a668fbSLeonid Yegoshin 			break;
1132b0a668fbSLeonid Yegoshin 		}
1133b0a668fbSLeonid Yegoshin 		/*
1134b0a668fbSLeonid Yegoshin 		 * This will probably be optimized away when
1135b0a668fbSLeonid Yegoshin 		 * CONFIG_DEBUG_FS is not enabled
1136b0a668fbSLeonid Yegoshin 		 */
1137b0a668fbSLeonid Yegoshin 		switch (MIPSInst_OPCODE(inst)) {
1138b0a668fbSLeonid Yegoshin 		case beql_op:
1139b0a668fbSLeonid Yegoshin 			MIPS_R2BR_STATS(beql);
1140b0a668fbSLeonid Yegoshin 			break;
1141b0a668fbSLeonid Yegoshin 		case bnel_op:
1142b0a668fbSLeonid Yegoshin 			MIPS_R2BR_STATS(bnel);
1143b0a668fbSLeonid Yegoshin 			break;
1144b0a668fbSLeonid Yegoshin 		case blezl_op:
1145b0a668fbSLeonid Yegoshin 			MIPS_R2BR_STATS(blezl);
1146b0a668fbSLeonid Yegoshin 			break;
1147b0a668fbSLeonid Yegoshin 		case bgtzl_op:
1148b0a668fbSLeonid Yegoshin 			MIPS_R2BR_STATS(bgtzl);
1149b0a668fbSLeonid Yegoshin 			break;
1150b0a668fbSLeonid Yegoshin 		}
1151b0a668fbSLeonid Yegoshin 
1152b0a668fbSLeonid Yegoshin 		switch (MIPSInst_OPCODE(nir)) {
1153b0a668fbSLeonid Yegoshin 		case cop1_op:
1154b0a668fbSLeonid Yegoshin 		case cop1x_op:
1155b0a668fbSLeonid Yegoshin 		case lwc1_op:
1156b0a668fbSLeonid Yegoshin 		case swc1_op:
1157b0a668fbSLeonid Yegoshin 			regs->cp0_cause |= CAUSEF_BD;
1158b0a668fbSLeonid Yegoshin 			goto fpu_emul;
1159b0a668fbSLeonid Yegoshin 		}
1160b0a668fbSLeonid Yegoshin 		if (nir) {
1161b0a668fbSLeonid Yegoshin 			err = mipsr6_emul(regs, nir);
1162b0a668fbSLeonid Yegoshin 			if (err > 0) {
1163432c6bacSPaul Burton 				err = mips_dsemul(regs, nir, epc, cpc);
1164b0a668fbSLeonid Yegoshin 				if (err == SIGILL)
1165b0a668fbSLeonid Yegoshin 					err = SIGEMT;
1166b0a668fbSLeonid Yegoshin 				MIPS_R2_STATS(dsemul);
1167b0a668fbSLeonid Yegoshin 			}
1168b0a668fbSLeonid Yegoshin 		}
1169b0a668fbSLeonid Yegoshin 		break;
1170b0a668fbSLeonid Yegoshin 	case lwc1_op:
1171b0a668fbSLeonid Yegoshin 	case swc1_op:
1172b0a668fbSLeonid Yegoshin 	case cop1_op:
1173b0a668fbSLeonid Yegoshin 	case cop1x_op:
1174b0a668fbSLeonid Yegoshin fpu_emul:
1175b0a668fbSLeonid Yegoshin 		regs->regs[31] = r31;
1176b0a668fbSLeonid Yegoshin 		regs->cp0_epc = epc;
1177cc97ab23SPaul Burton 
1178b0a668fbSLeonid Yegoshin 		err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
1179b0a668fbSLeonid Yegoshin 					       &fault_addr);
1180b0a668fbSLeonid Yegoshin 
1181b0a668fbSLeonid Yegoshin 		/*
11825a1aca44SMaciej W. Rozycki 		 * We can't allow the emulated instruction to leave any
11835a1aca44SMaciej W. Rozycki 		 * enabled Cause bits set in $fcr31.
1184443c4403SMaciej W. Rozycki 		 */
11855a1aca44SMaciej W. Rozycki 		*fcr31 = res = mask_fcr31_x(current->thread.fpu.fcr31);
11865a1aca44SMaciej W. Rozycki 		current->thread.fpu.fcr31 &= ~res;
1187443c4403SMaciej W. Rozycki 
1188443c4403SMaciej W. Rozycki 		/*
1189b0a668fbSLeonid Yegoshin 		 * this is a tricky issue - lose_fpu() uses LL/SC atomics
1190b0a668fbSLeonid Yegoshin 		 * if FPU is owned and effectively cancels user level LL/SC.
1191b0a668fbSLeonid Yegoshin 		 * So, it could be logical to don't restore FPU ownership here.
1192b0a668fbSLeonid Yegoshin 		 * But the sequence of multiple FPU instructions is much much
1193b0a668fbSLeonid Yegoshin 		 * more often than LL-FPU-SC and I prefer loop here until
1194b0a668fbSLeonid Yegoshin 		 * next scheduler cycle cancels FPU ownership
1195b0a668fbSLeonid Yegoshin 		 */
1196b0a668fbSLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
1197b0a668fbSLeonid Yegoshin 
1198b0a668fbSLeonid Yegoshin 		if (err)
1199b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = (unsigned long)fault_addr;
1200b0a668fbSLeonid Yegoshin 
1201b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(fpus);
1202b0a668fbSLeonid Yegoshin 
1203b0a668fbSLeonid Yegoshin 		break;
1204b0a668fbSLeonid Yegoshin 
1205b0a668fbSLeonid Yegoshin 	case lwl_op:
1206b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1207b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
120896d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 4)) {
1209b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1210b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1211b0a668fbSLeonid Yegoshin 			break;
1212b0a668fbSLeonid Yegoshin 		}
1213b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1214b0a668fbSLeonid Yegoshin 			"	.set	push\n"
1215b0a668fbSLeonid Yegoshin 			"	.set	reorder\n"
1216b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1217b0a668fbSLeonid Yegoshin 			"1:"	LB	"%1, 0(%2)\n"
1218b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 24, 8\n"
1219b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1220b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1221b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1222b0a668fbSLeonid Yegoshin 			"2:"	LB	"%1, 0(%2)\n"
1223b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 16, 8\n"
1224b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1225b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1226b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1227b0a668fbSLeonid Yegoshin 			"3:"	LB	"%1, 0(%2)\n"
1228b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 8, 8\n"
1229b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1230b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1231b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1232b0a668fbSLeonid Yegoshin 			"4:"	LB	"%1, 0(%2)\n"
1233b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 0, 8\n"
1234b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1235b0a668fbSLeonid Yegoshin 			"1:"	LB	"%1, 0(%2)\n"
1236b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 24, 8\n"
1237b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1238b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1239b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1240b0a668fbSLeonid Yegoshin 			"2:"	LB	"%1, 0(%2)\n"
1241b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 16, 8\n"
1242b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1243b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1244b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1245b0a668fbSLeonid Yegoshin 			"3:"	LB	"%1, 0(%2)\n"
1246b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 8, 8\n"
1247b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1248b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1249b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1250b0a668fbSLeonid Yegoshin 			"4:"	LB	"%1, 0(%2)\n"
1251b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 0, 8\n"
1252b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1253b0a668fbSLeonid Yegoshin 			"9:	sll	%0, %0, 0\n"
1254b0a668fbSLeonid Yegoshin 			"10:\n"
1255b0a668fbSLeonid Yegoshin 			"	.insn\n"
1256b0a668fbSLeonid Yegoshin 			"	.section	.fixup,\"ax\"\n"
1257b0a668fbSLeonid Yegoshin 			"8:	li	%3,%4\n"
1258b0a668fbSLeonid Yegoshin 			"	j	10b\n"
1259b0a668fbSLeonid Yegoshin 			"	.previous\n"
1260b0a668fbSLeonid Yegoshin 			"	.section	__ex_table,\"a\"\n"
1261*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1262*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1263*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1264*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1265b0a668fbSLeonid Yegoshin 			"	.previous\n"
1266b0a668fbSLeonid Yegoshin 			"	.set	pop\n"
1267b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1268b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1269b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV));
1270b0a668fbSLeonid Yegoshin 
1271b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
1272b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = rt;
1273b0a668fbSLeonid Yegoshin 
1274b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(loads);
1275b0a668fbSLeonid Yegoshin 
1276b0a668fbSLeonid Yegoshin 		break;
1277b0a668fbSLeonid Yegoshin 
1278b0a668fbSLeonid Yegoshin 	case lwr_op:
1279b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1280b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
128196d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 4)) {
1282b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1283b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1284b0a668fbSLeonid Yegoshin 			break;
1285b0a668fbSLeonid Yegoshin 		}
1286b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1287b0a668fbSLeonid Yegoshin 			"       .set	push\n"
1288b0a668fbSLeonid Yegoshin 			"       .set	reorder\n"
1289b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1290b0a668fbSLeonid Yegoshin 			"1:"    LB	"%1, 0(%2)\n"
1291b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 0, 8\n"
1292b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1293b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x3\n"
1294b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1295b0a668fbSLeonid Yegoshin 			"2:"    LB	"%1, 0(%2)\n"
1296b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 8, 8\n"
1297b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1298b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x3\n"
1299b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1300b0a668fbSLeonid Yegoshin 			"3:"    LB	"%1, 0(%2)\n"
1301b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 16, 8\n"
1302b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1303b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x3\n"
1304b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1305b0a668fbSLeonid Yegoshin 			"4:"    LB	"%1, 0(%2)\n"
1306b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 24, 8\n"
1307b0a668fbSLeonid Yegoshin 			"       sll	%0, %0, 0\n"
1308b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1309b0a668fbSLeonid Yegoshin 			"1:"    LB	"%1, 0(%2)\n"
1310b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 0, 8\n"
1311b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x3\n"
1312b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1313b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1314b0a668fbSLeonid Yegoshin 			"2:"    LB	"%1, 0(%2)\n"
1315b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 8, 8\n"
1316b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x3\n"
1317b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1318b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1319b0a668fbSLeonid Yegoshin 			"3:"    LB	"%1, 0(%2)\n"
1320b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 16, 8\n"
1321b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x3\n"
1322b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1323b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1324b0a668fbSLeonid Yegoshin 			"4:"    LB	"%1, 0(%2)\n"
1325b0a668fbSLeonid Yegoshin 				INS	"%0, %1, 24, 8\n"
1326b0a668fbSLeonid Yegoshin 			"       sll	%0, %0, 0\n"
1327b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1328b0a668fbSLeonid Yegoshin 			"9:\n"
1329b0a668fbSLeonid Yegoshin 			"10:\n"
1330b0a668fbSLeonid Yegoshin 			"	.insn\n"
1331b0a668fbSLeonid Yegoshin 			"	.section	.fixup,\"ax\"\n"
1332b0a668fbSLeonid Yegoshin 			"8:	li	%3,%4\n"
1333b0a668fbSLeonid Yegoshin 			"	j	10b\n"
1334b0a668fbSLeonid Yegoshin 			"       .previous\n"
1335b0a668fbSLeonid Yegoshin 			"	.section	__ex_table,\"a\"\n"
1336*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1337*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1338*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1339*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1340b0a668fbSLeonid Yegoshin 			"	.previous\n"
1341b0a668fbSLeonid Yegoshin 			"	.set	pop\n"
1342b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1343b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1344b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV));
1345b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
1346b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = rt;
1347b0a668fbSLeonid Yegoshin 
1348b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(loads);
1349b0a668fbSLeonid Yegoshin 
1350b0a668fbSLeonid Yegoshin 		break;
1351b0a668fbSLeonid Yegoshin 
1352b0a668fbSLeonid Yegoshin 	case swl_op:
1353b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1354b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
135596d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 4)) {
1356b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1357b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1358b0a668fbSLeonid Yegoshin 			break;
1359b0a668fbSLeonid Yegoshin 		}
1360b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1361b0a668fbSLeonid Yegoshin 			"	.set	push\n"
1362b0a668fbSLeonid Yegoshin 			"	.set	reorder\n"
1363b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1364b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 24, 8\n"
1365b0a668fbSLeonid Yegoshin 			"1:"	SB	"%1, 0(%2)\n"
1366b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1367b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1368b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1369b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 16, 8\n"
1370b0a668fbSLeonid Yegoshin 			"2:"	SB	"%1, 0(%2)\n"
1371b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1372b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1373b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1374b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 8, 8\n"
1375b0a668fbSLeonid Yegoshin 			"3:"	SB	"%1, 0(%2)\n"
1376b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1377b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1378b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1379b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 0, 8\n"
1380b0a668fbSLeonid Yegoshin 			"4:"	SB	"%1, 0(%2)\n"
1381b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1382b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 24, 8\n"
1383b0a668fbSLeonid Yegoshin 			"1:"	SB	"%1, 0(%2)\n"
1384b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1385b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1386b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1387b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 16, 8\n"
1388b0a668fbSLeonid Yegoshin 			"2:"	SB	"%1, 0(%2)\n"
1389b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1390b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1391b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1392b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 8, 8\n"
1393b0a668fbSLeonid Yegoshin 			"3:"	SB	"%1, 0(%2)\n"
1394b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1395b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1396b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1397b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 0, 8\n"
1398b0a668fbSLeonid Yegoshin 			"4:"	SB	"%1, 0(%2)\n"
1399b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1400b0a668fbSLeonid Yegoshin 			"9:\n"
1401b0a668fbSLeonid Yegoshin 			"	.insn\n"
1402b0a668fbSLeonid Yegoshin 			"       .section        .fixup,\"ax\"\n"
1403b0a668fbSLeonid Yegoshin 			"8:	li	%3,%4\n"
1404b0a668fbSLeonid Yegoshin 			"	j	9b\n"
1405b0a668fbSLeonid Yegoshin 			"	.previous\n"
1406b0a668fbSLeonid Yegoshin 			"	.section        __ex_table,\"a\"\n"
1407*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1408*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1409*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1410*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1411b0a668fbSLeonid Yegoshin 			"	.previous\n"
1412b0a668fbSLeonid Yegoshin 			"	.set	pop\n"
1413b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1414b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1415b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV)
1416b0a668fbSLeonid Yegoshin 			: "memory");
1417b0a668fbSLeonid Yegoshin 
1418b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(stores);
1419b0a668fbSLeonid Yegoshin 
1420b0a668fbSLeonid Yegoshin 		break;
1421b0a668fbSLeonid Yegoshin 
1422b0a668fbSLeonid Yegoshin 	case swr_op:
1423b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1424b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
142596d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 4)) {
1426b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1427b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1428b0a668fbSLeonid Yegoshin 			break;
1429b0a668fbSLeonid Yegoshin 		}
1430b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1431b0a668fbSLeonid Yegoshin 			"	.set	push\n"
1432b0a668fbSLeonid Yegoshin 			"	.set	reorder\n"
1433b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1434b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 0, 8\n"
1435b0a668fbSLeonid Yegoshin 			"1:"	SB	"%1, 0(%2)\n"
1436b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1437b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1438b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1439b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 8, 8\n"
1440b0a668fbSLeonid Yegoshin 			"2:"	SB	"%1, 0(%2)\n"
1441b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1442b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1443b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1444b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 16, 8\n"
1445b0a668fbSLeonid Yegoshin 			"3:"	SB	"%1, 0(%2)\n"
1446b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, 1\n"
1447b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1448b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1449b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 24, 8\n"
1450b0a668fbSLeonid Yegoshin 			"4:"	SB	"%1, 0(%2)\n"
1451b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1452b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 0, 8\n"
1453b0a668fbSLeonid Yegoshin 			"1:"	SB	"%1, 0(%2)\n"
1454b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1455b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1456b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1457b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 8, 8\n"
1458b0a668fbSLeonid Yegoshin 			"2:"	SB	"%1, 0(%2)\n"
1459b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1460b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1461b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1462b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 16, 8\n"
1463b0a668fbSLeonid Yegoshin 			"3:"	SB	"%1, 0(%2)\n"
1464b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x3\n"
1465b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1466b0a668fbSLeonid Yegoshin 				ADDIU	"%2, %2, -1\n"
1467b0a668fbSLeonid Yegoshin 				EXT	"%1, %0, 24, 8\n"
1468b0a668fbSLeonid Yegoshin 			"4:"	SB	"%1, 0(%2)\n"
1469b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1470b0a668fbSLeonid Yegoshin 			"9:\n"
1471b0a668fbSLeonid Yegoshin 			"	.insn\n"
1472b0a668fbSLeonid Yegoshin 			"	.section        .fixup,\"ax\"\n"
1473b0a668fbSLeonid Yegoshin 			"8:	li	%3,%4\n"
1474b0a668fbSLeonid Yegoshin 			"	j	9b\n"
1475b0a668fbSLeonid Yegoshin 			"	.previous\n"
1476b0a668fbSLeonid Yegoshin 			"	.section        __ex_table,\"a\"\n"
1477*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1478*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1479*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1480*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1481b0a668fbSLeonid Yegoshin 			"	.previous\n"
1482b0a668fbSLeonid Yegoshin 			"	.set	pop\n"
1483b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1484b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1485b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV)
1486b0a668fbSLeonid Yegoshin 			: "memory");
1487b0a668fbSLeonid Yegoshin 
1488b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(stores);
1489b0a668fbSLeonid Yegoshin 
1490b0a668fbSLeonid Yegoshin 		break;
1491b0a668fbSLeonid Yegoshin 
1492b0a668fbSLeonid Yegoshin 	case ldl_op:
149397f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT)) {
1494b0a668fbSLeonid Yegoshin 		    err = SIGILL;
1495b0a668fbSLeonid Yegoshin 		    break;
1496b0a668fbSLeonid Yegoshin 		}
1497b0a668fbSLeonid Yegoshin 
1498b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1499b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
150096d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 8)) {
1501b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1502b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1503b0a668fbSLeonid Yegoshin 			break;
1504b0a668fbSLeonid Yegoshin 		}
1505b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1506b0a668fbSLeonid Yegoshin 			"	.set    push\n"
1507b0a668fbSLeonid Yegoshin 			"	.set    reorder\n"
1508b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1509b0a668fbSLeonid Yegoshin 			"1:	lb	%1, 0(%2)\n"
1510b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 56, 8\n"
1511b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1512b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1513b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1514b0a668fbSLeonid Yegoshin 			"2:	lb	%1, 0(%2)\n"
1515b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 48, 8\n"
1516b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1517b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1518b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1519b0a668fbSLeonid Yegoshin 			"3:	lb	%1, 0(%2)\n"
1520b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 40, 8\n"
1521b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1522b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1523b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1524b0a668fbSLeonid Yegoshin 			"4:	lb	%1, 0(%2)\n"
1525b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 32, 8\n"
1526b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1527b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1528b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1529b0a668fbSLeonid Yegoshin 			"5:	lb	%1, 0(%2)\n"
1530b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 24, 8\n"
1531b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1532b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1533b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1534b0a668fbSLeonid Yegoshin 			"6:	lb	%1, 0(%2)\n"
1535b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 16, 8\n"
1536b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1537b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1538b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1539b0a668fbSLeonid Yegoshin 			"7:	lb	%1, 0(%2)\n"
1540b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 8, 8\n"
1541b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1542b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1543b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1544b0a668fbSLeonid Yegoshin 			"0:	lb	%1, 0(%2)\n"
1545b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 0, 8\n"
1546b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1547b0a668fbSLeonid Yegoshin 			"1:	lb	%1, 0(%2)\n"
1548b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 56, 8\n"
1549b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1550b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1551b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1552b0a668fbSLeonid Yegoshin 			"2:	lb	%1, 0(%2)\n"
1553b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 48, 8\n"
1554b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1555b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1556b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1557b0a668fbSLeonid Yegoshin 			"3:	lb	%1, 0(%2)\n"
1558b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 40, 8\n"
1559b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1560b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1561b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1562b0a668fbSLeonid Yegoshin 			"4:	lb	%1, 0(%2)\n"
1563b0a668fbSLeonid Yegoshin 			"	dinsu	%0, %1, 32, 8\n"
1564b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1565b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1566b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1567b0a668fbSLeonid Yegoshin 			"5:	lb	%1, 0(%2)\n"
1568b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 24, 8\n"
1569b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1570b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1571b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1572b0a668fbSLeonid Yegoshin 			"6:	lb	%1, 0(%2)\n"
1573b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 16, 8\n"
1574b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1575b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1576b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1577b0a668fbSLeonid Yegoshin 			"7:	lb	%1, 0(%2)\n"
1578b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 8, 8\n"
1579b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1580b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1581b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1582b0a668fbSLeonid Yegoshin 			"0:	lb	%1, 0(%2)\n"
1583b0a668fbSLeonid Yegoshin 			"	dins	%0, %1, 0, 8\n"
1584b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1585b0a668fbSLeonid Yegoshin 			"9:\n"
1586b0a668fbSLeonid Yegoshin 			"	.insn\n"
1587b0a668fbSLeonid Yegoshin 			"	.section        .fixup,\"ax\"\n"
1588b0a668fbSLeonid Yegoshin 			"8:	li	%3,%4\n"
1589b0a668fbSLeonid Yegoshin 			"	j	9b\n"
1590b0a668fbSLeonid Yegoshin 			"	.previous\n"
1591b0a668fbSLeonid Yegoshin 			"	.section        __ex_table,\"a\"\n"
1592*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1593*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1594*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1595*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1596*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 5b,8b\n"
1597*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 6b,8b\n"
1598*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 7b,8b\n"
1599*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 0b,8b\n"
1600b0a668fbSLeonid Yegoshin 			"	.previous\n"
1601b0a668fbSLeonid Yegoshin 			"	.set	pop\n"
1602b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1603b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1604b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV));
1605b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
1606b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = rt;
1607b0a668fbSLeonid Yegoshin 
1608b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(loads);
1609b0a668fbSLeonid Yegoshin 		break;
1610b0a668fbSLeonid Yegoshin 
1611b0a668fbSLeonid Yegoshin 	case ldr_op:
161297f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT)) {
1613b0a668fbSLeonid Yegoshin 		    err = SIGILL;
1614b0a668fbSLeonid Yegoshin 		    break;
1615b0a668fbSLeonid Yegoshin 		}
1616b0a668fbSLeonid Yegoshin 
1617b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1618b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
161996d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 8)) {
1620b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1621b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1622b0a668fbSLeonid Yegoshin 			break;
1623b0a668fbSLeonid Yegoshin 		}
1624b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1625b0a668fbSLeonid Yegoshin 			"	.set    push\n"
1626b0a668fbSLeonid Yegoshin 			"	.set    reorder\n"
1627b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1628b0a668fbSLeonid Yegoshin 			"1:	lb      %1, 0(%2)\n"
1629b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 0, 8\n"
1630b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1631b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1632b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1633b0a668fbSLeonid Yegoshin 			"2:	lb      %1, 0(%2)\n"
1634b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 8, 8\n"
1635b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1636b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1637b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1638b0a668fbSLeonid Yegoshin 			"3:	lb      %1, 0(%2)\n"
1639b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 16, 8\n"
1640b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1641b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1642b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1643b0a668fbSLeonid Yegoshin 			"4:	lb      %1, 0(%2)\n"
1644b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 24, 8\n"
1645b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1646b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1647b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1648b0a668fbSLeonid Yegoshin 			"5:	lb      %1, 0(%2)\n"
1649b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 32, 8\n"
1650b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1651b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1652b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1653b0a668fbSLeonid Yegoshin 			"6:	lb      %1, 0(%2)\n"
1654b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 40, 8\n"
1655b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1656b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1657b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1658b0a668fbSLeonid Yegoshin 			"7:	lb      %1, 0(%2)\n"
1659b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 48, 8\n"
1660b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, 1\n"
1661b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1662b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1663b0a668fbSLeonid Yegoshin 			"0:	lb      %1, 0(%2)\n"
1664b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 56, 8\n"
1665b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1666b0a668fbSLeonid Yegoshin 			"1:	lb      %1, 0(%2)\n"
1667b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 0, 8\n"
1668b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1669b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1670b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1671b0a668fbSLeonid Yegoshin 			"2:	lb      %1, 0(%2)\n"
1672b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 8, 8\n"
1673b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1674b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1675b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1676b0a668fbSLeonid Yegoshin 			"3:	lb      %1, 0(%2)\n"
1677b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 16, 8\n"
1678b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1679b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1680b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1681b0a668fbSLeonid Yegoshin 			"4:	lb      %1, 0(%2)\n"
1682b0a668fbSLeonid Yegoshin 			"	dins   %0, %1, 24, 8\n"
1683b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1684b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1685b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1686b0a668fbSLeonid Yegoshin 			"5:	lb      %1, 0(%2)\n"
1687b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 32, 8\n"
1688b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1689b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1690b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1691b0a668fbSLeonid Yegoshin 			"6:	lb      %1, 0(%2)\n"
1692b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 40, 8\n"
1693b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1694b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1695b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1696b0a668fbSLeonid Yegoshin 			"7:	lb      %1, 0(%2)\n"
1697b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 48, 8\n"
1698b0a668fbSLeonid Yegoshin 			"	andi    %1, %2, 0x7\n"
1699b0a668fbSLeonid Yegoshin 			"	beq     $0, %1, 9f\n"
1700b0a668fbSLeonid Yegoshin 			"	daddiu  %2, %2, -1\n"
1701b0a668fbSLeonid Yegoshin 			"0:	lb      %1, 0(%2)\n"
1702b0a668fbSLeonid Yegoshin 			"	dinsu    %0, %1, 56, 8\n"
1703b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1704b0a668fbSLeonid Yegoshin 			"9:\n"
1705b0a668fbSLeonid Yegoshin 			"	.insn\n"
1706b0a668fbSLeonid Yegoshin 			"	.section        .fixup,\"ax\"\n"
1707b0a668fbSLeonid Yegoshin 			"8:	li     %3,%4\n"
1708b0a668fbSLeonid Yegoshin 			"	j      9b\n"
1709b0a668fbSLeonid Yegoshin 			"	.previous\n"
1710b0a668fbSLeonid Yegoshin 			"	.section        __ex_table,\"a\"\n"
1711*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1712*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1713*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1714*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1715*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 5b,8b\n"
1716*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 6b,8b\n"
1717*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 7b,8b\n"
1718*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 0b,8b\n"
1719b0a668fbSLeonid Yegoshin 			"	.previous\n"
1720b0a668fbSLeonid Yegoshin 			"	.set    pop\n"
1721b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1722b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1723b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV));
1724b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
1725b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = rt;
1726b0a668fbSLeonid Yegoshin 
1727b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(loads);
1728b0a668fbSLeonid Yegoshin 		break;
1729b0a668fbSLeonid Yegoshin 
1730b0a668fbSLeonid Yegoshin 	case sdl_op:
173197f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT)) {
1732b0a668fbSLeonid Yegoshin 		    err = SIGILL;
1733b0a668fbSLeonid Yegoshin 		    break;
1734b0a668fbSLeonid Yegoshin 		}
1735b0a668fbSLeonid Yegoshin 
1736b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1737b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
173896d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 8)) {
1739b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1740b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1741b0a668fbSLeonid Yegoshin 			break;
1742b0a668fbSLeonid Yegoshin 		}
1743b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1744b0a668fbSLeonid Yegoshin 			"	.set	push\n"
1745b0a668fbSLeonid Yegoshin 			"	.set	reorder\n"
1746b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1747b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 56, 8\n"
1748b0a668fbSLeonid Yegoshin 			"1:	sb	%1, 0(%2)\n"
1749b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1750b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1751b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1752b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 48, 8\n"
1753b0a668fbSLeonid Yegoshin 			"2:	sb	%1, 0(%2)\n"
1754b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1755b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1756b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1757b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 40, 8\n"
1758b0a668fbSLeonid Yegoshin 			"3:	sb	%1, 0(%2)\n"
1759b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1760b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1761b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1762b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 32, 8\n"
1763b0a668fbSLeonid Yegoshin 			"4:	sb	%1, 0(%2)\n"
1764b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1765b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1766b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1767b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 24, 8\n"
1768b0a668fbSLeonid Yegoshin 			"5:	sb	%1, 0(%2)\n"
1769b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1770b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1771b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1772b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 16, 8\n"
1773b0a668fbSLeonid Yegoshin 			"6:	sb	%1, 0(%2)\n"
1774b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1775b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1776b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1777b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 8, 8\n"
1778b0a668fbSLeonid Yegoshin 			"7:	sb	%1, 0(%2)\n"
1779b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1780b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1781b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, -1\n"
1782b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 0, 8\n"
1783b0a668fbSLeonid Yegoshin 			"0:	sb	%1, 0(%2)\n"
1784b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1785b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 56, 8\n"
1786b0a668fbSLeonid Yegoshin 			"1:	sb	%1, 0(%2)\n"
1787b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1788b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1789b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1790b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 48, 8\n"
1791b0a668fbSLeonid Yegoshin 			"2:	sb	%1, 0(%2)\n"
1792b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1793b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1794b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1795b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 40, 8\n"
1796b0a668fbSLeonid Yegoshin 			"3:	sb	%1, 0(%2)\n"
1797b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1798b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1799b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1800b0a668fbSLeonid Yegoshin 			"	dextu	%1, %0, 32, 8\n"
1801b0a668fbSLeonid Yegoshin 			"4:	sb	%1, 0(%2)\n"
1802b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1803b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1804b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1805b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 24, 8\n"
1806b0a668fbSLeonid Yegoshin 			"5:	sb	%1, 0(%2)\n"
1807b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1808b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1809b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1810b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 16, 8\n"
1811b0a668fbSLeonid Yegoshin 			"6:	sb	%1, 0(%2)\n"
1812b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1813b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1814b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1815b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 8, 8\n"
1816b0a668fbSLeonid Yegoshin 			"7:	sb	%1, 0(%2)\n"
1817b0a668fbSLeonid Yegoshin 			"	daddiu	%2, %2, 1\n"
1818b0a668fbSLeonid Yegoshin 			"	andi	%1, %2, 0x7\n"
1819b0a668fbSLeonid Yegoshin 			"	beq	$0, %1, 9f\n"
1820b0a668fbSLeonid Yegoshin 			"	dext	%1, %0, 0, 8\n"
1821b0a668fbSLeonid Yegoshin 			"0:	sb	%1, 0(%2)\n"
1822b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1823b0a668fbSLeonid Yegoshin 			"9:\n"
1824b0a668fbSLeonid Yegoshin 			"	.insn\n"
1825b0a668fbSLeonid Yegoshin 			"	.section        .fixup,\"ax\"\n"
1826b0a668fbSLeonid Yegoshin 			"8:	li	%3,%4\n"
1827b0a668fbSLeonid Yegoshin 			"	j	9b\n"
1828b0a668fbSLeonid Yegoshin 			"	.previous\n"
1829b0a668fbSLeonid Yegoshin 			"	.section        __ex_table,\"a\"\n"
1830*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1831*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1832*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1833*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1834*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 5b,8b\n"
1835*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 6b,8b\n"
1836*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 7b,8b\n"
1837*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 0b,8b\n"
1838b0a668fbSLeonid Yegoshin 			"	.previous\n"
1839b0a668fbSLeonid Yegoshin 			"	.set	pop\n"
1840b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1841b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1842b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV)
1843b0a668fbSLeonid Yegoshin 			: "memory");
1844b0a668fbSLeonid Yegoshin 
1845b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(stores);
1846b0a668fbSLeonid Yegoshin 		break;
1847b0a668fbSLeonid Yegoshin 
1848b0a668fbSLeonid Yegoshin 	case sdr_op:
184997f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT)) {
1850b0a668fbSLeonid Yegoshin 		    err = SIGILL;
1851b0a668fbSLeonid Yegoshin 		    break;
1852b0a668fbSLeonid Yegoshin 		}
1853b0a668fbSLeonid Yegoshin 
1854b0a668fbSLeonid Yegoshin 		rt = regs->regs[MIPSInst_RT(inst)];
1855b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
185696d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 8)) {
1857b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1858b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
1859b0a668fbSLeonid Yegoshin 			break;
1860b0a668fbSLeonid Yegoshin 		}
1861b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
1862b0a668fbSLeonid Yegoshin 			"       .set	push\n"
1863b0a668fbSLeonid Yegoshin 			"       .set	reorder\n"
1864b0a668fbSLeonid Yegoshin #ifdef CONFIG_CPU_LITTLE_ENDIAN
1865b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 0, 8\n"
1866b0a668fbSLeonid Yegoshin 			"1:     sb	%1, 0(%2)\n"
1867b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1868b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1869b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1870b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 8, 8\n"
1871b0a668fbSLeonid Yegoshin 			"2:     sb	%1, 0(%2)\n"
1872b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1873b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1874b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1875b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 16, 8\n"
1876b0a668fbSLeonid Yegoshin 			"3:     sb	%1, 0(%2)\n"
1877b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1878b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1879b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1880b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 24, 8\n"
1881b0a668fbSLeonid Yegoshin 			"4:     sb	%1, 0(%2)\n"
1882b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1883b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1884b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1885b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 32, 8\n"
1886b0a668fbSLeonid Yegoshin 			"5:     sb	%1, 0(%2)\n"
1887b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1888b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1889b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1890b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 40, 8\n"
1891b0a668fbSLeonid Yegoshin 			"6:     sb	%1, 0(%2)\n"
1892b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1893b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1894b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1895b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 48, 8\n"
1896b0a668fbSLeonid Yegoshin 			"7:     sb	%1, 0(%2)\n"
1897b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, 1\n"
1898b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1899b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1900b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 56, 8\n"
1901b0a668fbSLeonid Yegoshin 			"0:     sb	%1, 0(%2)\n"
1902b0a668fbSLeonid Yegoshin #else /* !CONFIG_CPU_LITTLE_ENDIAN */
1903b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 0, 8\n"
1904b0a668fbSLeonid Yegoshin 			"1:     sb	%1, 0(%2)\n"
1905b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1906b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1907b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1908b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 8, 8\n"
1909b0a668fbSLeonid Yegoshin 			"2:     sb	%1, 0(%2)\n"
1910b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1911b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1912b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1913b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 16, 8\n"
1914b0a668fbSLeonid Yegoshin 			"3:     sb	%1, 0(%2)\n"
1915b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1916b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1917b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1918b0a668fbSLeonid Yegoshin 			"       dext	%1, %0, 24, 8\n"
1919b0a668fbSLeonid Yegoshin 			"4:     sb	%1, 0(%2)\n"
1920b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1921b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1922b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1923b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 32, 8\n"
1924b0a668fbSLeonid Yegoshin 			"5:     sb	%1, 0(%2)\n"
1925b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1926b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1927b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1928b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 40, 8\n"
1929b0a668fbSLeonid Yegoshin 			"6:     sb	%1, 0(%2)\n"
1930b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1931b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1932b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1933b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 48, 8\n"
1934b0a668fbSLeonid Yegoshin 			"7:     sb	%1, 0(%2)\n"
1935b0a668fbSLeonid Yegoshin 			"       andi	%1, %2, 0x7\n"
1936b0a668fbSLeonid Yegoshin 			"       beq	$0, %1, 9f\n"
1937b0a668fbSLeonid Yegoshin 			"       daddiu	%2, %2, -1\n"
1938b0a668fbSLeonid Yegoshin 			"       dextu	%1, %0, 56, 8\n"
1939b0a668fbSLeonid Yegoshin 			"0:     sb	%1, 0(%2)\n"
1940b0a668fbSLeonid Yegoshin #endif /* CONFIG_CPU_LITTLE_ENDIAN */
1941b0a668fbSLeonid Yegoshin 			"9:\n"
1942b0a668fbSLeonid Yegoshin 			"       .insn\n"
1943b0a668fbSLeonid Yegoshin 			"       .section        .fixup,\"ax\"\n"
1944b0a668fbSLeonid Yegoshin 			"8:     li	%3,%4\n"
1945b0a668fbSLeonid Yegoshin 			"       j	9b\n"
1946b0a668fbSLeonid Yegoshin 			"       .previous\n"
1947b0a668fbSLeonid Yegoshin 			"       .section        __ex_table,\"a\"\n"
1948*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,8b\n"
1949*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 2b,8b\n"
1950*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 3b,8b\n"
1951*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 4b,8b\n"
1952*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 5b,8b\n"
1953*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 6b,8b\n"
1954*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 7b,8b\n"
1955*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 0b,8b\n"
1956b0a668fbSLeonid Yegoshin 			"       .previous\n"
1957b0a668fbSLeonid Yegoshin 			"       .set	pop\n"
1958b0a668fbSLeonid Yegoshin 			: "+&r"(rt), "=&r"(rs),
1959b0a668fbSLeonid Yegoshin 			  "+&r"(vaddr), "+&r"(err)
1960b0a668fbSLeonid Yegoshin 			: "i"(SIGSEGV)
1961b0a668fbSLeonid Yegoshin 			: "memory");
1962b0a668fbSLeonid Yegoshin 
1963b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(stores);
1964b0a668fbSLeonid Yegoshin 
1965b0a668fbSLeonid Yegoshin 		break;
1966b0a668fbSLeonid Yegoshin 	case ll_op:
1967b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
1968b0a668fbSLeonid Yegoshin 		if (vaddr & 0x3) {
1969b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1970b0a668fbSLeonid Yegoshin 			err = SIGBUS;
1971b0a668fbSLeonid Yegoshin 			break;
1972b0a668fbSLeonid Yegoshin 		}
197396d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 4)) {
1974b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
1975b0a668fbSLeonid Yegoshin 			err = SIGBUS;
1976b0a668fbSLeonid Yegoshin 			break;
1977b0a668fbSLeonid Yegoshin 		}
1978b0a668fbSLeonid Yegoshin 
1979b0a668fbSLeonid Yegoshin 		if (!cpu_has_rw_llb) {
1980b0a668fbSLeonid Yegoshin 			/*
1981b0a668fbSLeonid Yegoshin 			 * An LL/SC block can't be safely emulated without
1982b0a668fbSLeonid Yegoshin 			 * a Config5/LLB availability. So it's probably time to
1983b0a668fbSLeonid Yegoshin 			 * kill our process before things get any worse. This is
1984b0a668fbSLeonid Yegoshin 			 * because Config5/LLB allows us to use ERETNC so that
1985b0a668fbSLeonid Yegoshin 			 * the LLAddr/LLB bit is not cleared when we return from
1986b0a668fbSLeonid Yegoshin 			 * an exception. MIPS R2 LL/SC instructions trap with an
1987b0a668fbSLeonid Yegoshin 			 * RI exception so once we emulate them here, we return
1988b0a668fbSLeonid Yegoshin 			 * back to userland with ERETNC. That preserves the
1989b0a668fbSLeonid Yegoshin 			 * LLAddr/LLB so the subsequent SC instruction will
1990b0a668fbSLeonid Yegoshin 			 * succeed preserving the atomic semantics of the LL/SC
1991b0a668fbSLeonid Yegoshin 			 * block. Without that, there is no safe way to emulate
1992b0a668fbSLeonid Yegoshin 			 * an LL/SC block in MIPSR2 userland.
1993b0a668fbSLeonid Yegoshin 			 */
1994b0a668fbSLeonid Yegoshin 			pr_err("Can't emulate MIPSR2 LL/SC without Config5/LLB\n");
1995b0a668fbSLeonid Yegoshin 			err = SIGKILL;
1996b0a668fbSLeonid Yegoshin 			break;
1997b0a668fbSLeonid Yegoshin 		}
1998b0a668fbSLeonid Yegoshin 
1999b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
2000b0a668fbSLeonid Yegoshin 			"1:\n"
2001b0a668fbSLeonid Yegoshin 			"ll	%0, 0(%2)\n"
2002b0a668fbSLeonid Yegoshin 			"2:\n"
2003b0a668fbSLeonid Yegoshin 			".insn\n"
2004b0a668fbSLeonid Yegoshin 			".section        .fixup,\"ax\"\n"
2005b0a668fbSLeonid Yegoshin 			"3:\n"
2006b0a668fbSLeonid Yegoshin 			"li	%1, %3\n"
2007b0a668fbSLeonid Yegoshin 			"j	2b\n"
2008b0a668fbSLeonid Yegoshin 			".previous\n"
2009b0a668fbSLeonid Yegoshin 			".section        __ex_table,\"a\"\n"
2010*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,3b\n"
2011b0a668fbSLeonid Yegoshin 			".previous\n"
2012b0a668fbSLeonid Yegoshin 			: "=&r"(res), "+&r"(err)
2013b0a668fbSLeonid Yegoshin 			: "r"(vaddr), "i"(SIGSEGV)
2014b0a668fbSLeonid Yegoshin 			: "memory");
2015b0a668fbSLeonid Yegoshin 
2016b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
2017b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = res;
2018b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(llsc);
2019b0a668fbSLeonid Yegoshin 
2020b0a668fbSLeonid Yegoshin 		break;
2021b0a668fbSLeonid Yegoshin 
2022b0a668fbSLeonid Yegoshin 	case sc_op:
2023b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
2024b0a668fbSLeonid Yegoshin 		if (vaddr & 0x3) {
2025b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
2026b0a668fbSLeonid Yegoshin 			err = SIGBUS;
2027b0a668fbSLeonid Yegoshin 			break;
2028b0a668fbSLeonid Yegoshin 		}
202996d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 4)) {
2030b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
2031b0a668fbSLeonid Yegoshin 			err = SIGBUS;
2032b0a668fbSLeonid Yegoshin 			break;
2033b0a668fbSLeonid Yegoshin 		}
2034b0a668fbSLeonid Yegoshin 
2035b0a668fbSLeonid Yegoshin 		if (!cpu_has_rw_llb) {
2036b0a668fbSLeonid Yegoshin 			/*
2037b0a668fbSLeonid Yegoshin 			 * An LL/SC block can't be safely emulated without
2038b0a668fbSLeonid Yegoshin 			 * a Config5/LLB availability. So it's probably time to
2039b0a668fbSLeonid Yegoshin 			 * kill our process before things get any worse. This is
2040b0a668fbSLeonid Yegoshin 			 * because Config5/LLB allows us to use ERETNC so that
2041b0a668fbSLeonid Yegoshin 			 * the LLAddr/LLB bit is not cleared when we return from
2042b0a668fbSLeonid Yegoshin 			 * an exception. MIPS R2 LL/SC instructions trap with an
2043b0a668fbSLeonid Yegoshin 			 * RI exception so once we emulate them here, we return
2044b0a668fbSLeonid Yegoshin 			 * back to userland with ERETNC. That preserves the
2045b0a668fbSLeonid Yegoshin 			 * LLAddr/LLB so the subsequent SC instruction will
2046b0a668fbSLeonid Yegoshin 			 * succeed preserving the atomic semantics of the LL/SC
2047b0a668fbSLeonid Yegoshin 			 * block. Without that, there is no safe way to emulate
2048b0a668fbSLeonid Yegoshin 			 * an LL/SC block in MIPSR2 userland.
2049b0a668fbSLeonid Yegoshin 			 */
2050b0a668fbSLeonid Yegoshin 			pr_err("Can't emulate MIPSR2 LL/SC without Config5/LLB\n");
2051b0a668fbSLeonid Yegoshin 			err = SIGKILL;
2052b0a668fbSLeonid Yegoshin 			break;
2053b0a668fbSLeonid Yegoshin 		}
2054b0a668fbSLeonid Yegoshin 
2055b0a668fbSLeonid Yegoshin 		res = regs->regs[MIPSInst_RT(inst)];
2056b0a668fbSLeonid Yegoshin 
2057b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
2058b0a668fbSLeonid Yegoshin 			"1:\n"
2059b0a668fbSLeonid Yegoshin 			"sc	%0, 0(%2)\n"
2060b0a668fbSLeonid Yegoshin 			"2:\n"
2061b0a668fbSLeonid Yegoshin 			".insn\n"
2062b0a668fbSLeonid Yegoshin 			".section        .fixup,\"ax\"\n"
2063b0a668fbSLeonid Yegoshin 			"3:\n"
2064b0a668fbSLeonid Yegoshin 			"li	%1, %3\n"
2065b0a668fbSLeonid Yegoshin 			"j	2b\n"
2066b0a668fbSLeonid Yegoshin 			".previous\n"
2067b0a668fbSLeonid Yegoshin 			".section        __ex_table,\"a\"\n"
2068*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,3b\n"
2069b0a668fbSLeonid Yegoshin 			".previous\n"
2070b0a668fbSLeonid Yegoshin 			: "+&r"(res), "+&r"(err)
2071b0a668fbSLeonid Yegoshin 			: "r"(vaddr), "i"(SIGSEGV));
2072b0a668fbSLeonid Yegoshin 
2073b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
2074b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = res;
2075b0a668fbSLeonid Yegoshin 
2076b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(llsc);
2077b0a668fbSLeonid Yegoshin 
2078b0a668fbSLeonid Yegoshin 		break;
2079b0a668fbSLeonid Yegoshin 
2080b0a668fbSLeonid Yegoshin 	case lld_op:
208197f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT)) {
2082b0a668fbSLeonid Yegoshin 		    err = SIGILL;
2083b0a668fbSLeonid Yegoshin 		    break;
2084b0a668fbSLeonid Yegoshin 		}
2085b0a668fbSLeonid Yegoshin 
2086b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
2087b0a668fbSLeonid Yegoshin 		if (vaddr & 0x7) {
2088b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
2089b0a668fbSLeonid Yegoshin 			err = SIGBUS;
2090b0a668fbSLeonid Yegoshin 			break;
2091b0a668fbSLeonid Yegoshin 		}
209296d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 8)) {
2093b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
2094b0a668fbSLeonid Yegoshin 			err = SIGBUS;
2095b0a668fbSLeonid Yegoshin 			break;
2096b0a668fbSLeonid Yegoshin 		}
2097b0a668fbSLeonid Yegoshin 
2098b0a668fbSLeonid Yegoshin 		if (!cpu_has_rw_llb) {
2099b0a668fbSLeonid Yegoshin 			/*
2100b0a668fbSLeonid Yegoshin 			 * An LL/SC block can't be safely emulated without
2101b0a668fbSLeonid Yegoshin 			 * a Config5/LLB availability. So it's probably time to
2102b0a668fbSLeonid Yegoshin 			 * kill our process before things get any worse. This is
2103b0a668fbSLeonid Yegoshin 			 * because Config5/LLB allows us to use ERETNC so that
2104b0a668fbSLeonid Yegoshin 			 * the LLAddr/LLB bit is not cleared when we return from
2105b0a668fbSLeonid Yegoshin 			 * an exception. MIPS R2 LL/SC instructions trap with an
2106b0a668fbSLeonid Yegoshin 			 * RI exception so once we emulate them here, we return
2107b0a668fbSLeonid Yegoshin 			 * back to userland with ERETNC. That preserves the
2108b0a668fbSLeonid Yegoshin 			 * LLAddr/LLB so the subsequent SC instruction will
2109b0a668fbSLeonid Yegoshin 			 * succeed preserving the atomic semantics of the LL/SC
2110b0a668fbSLeonid Yegoshin 			 * block. Without that, there is no safe way to emulate
2111b0a668fbSLeonid Yegoshin 			 * an LL/SC block in MIPSR2 userland.
2112b0a668fbSLeonid Yegoshin 			 */
2113b0a668fbSLeonid Yegoshin 			pr_err("Can't emulate MIPSR2 LL/SC without Config5/LLB\n");
2114b0a668fbSLeonid Yegoshin 			err = SIGKILL;
2115b0a668fbSLeonid Yegoshin 			break;
2116b0a668fbSLeonid Yegoshin 		}
2117b0a668fbSLeonid Yegoshin 
2118b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
2119b0a668fbSLeonid Yegoshin 			"1:\n"
2120b0a668fbSLeonid Yegoshin 			"lld	%0, 0(%2)\n"
2121b0a668fbSLeonid Yegoshin 			"2:\n"
2122b0a668fbSLeonid Yegoshin 			".insn\n"
2123b0a668fbSLeonid Yegoshin 			".section        .fixup,\"ax\"\n"
2124b0a668fbSLeonid Yegoshin 			"3:\n"
2125b0a668fbSLeonid Yegoshin 			"li	%1, %3\n"
2126b0a668fbSLeonid Yegoshin 			"j	2b\n"
2127b0a668fbSLeonid Yegoshin 			".previous\n"
2128b0a668fbSLeonid Yegoshin 			".section        __ex_table,\"a\"\n"
2129*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,3b\n"
2130b0a668fbSLeonid Yegoshin 			".previous\n"
2131b0a668fbSLeonid Yegoshin 			: "=&r"(res), "+&r"(err)
2132b0a668fbSLeonid Yegoshin 			: "r"(vaddr), "i"(SIGSEGV)
2133b0a668fbSLeonid Yegoshin 			: "memory");
2134b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
2135b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = res;
2136b0a668fbSLeonid Yegoshin 
2137b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(llsc);
2138b0a668fbSLeonid Yegoshin 
2139b0a668fbSLeonid Yegoshin 		break;
2140b0a668fbSLeonid Yegoshin 
2141b0a668fbSLeonid Yegoshin 	case scd_op:
214297f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_32BIT)) {
2143b0a668fbSLeonid Yegoshin 		    err = SIGILL;
2144b0a668fbSLeonid Yegoshin 		    break;
2145b0a668fbSLeonid Yegoshin 		}
2146b0a668fbSLeonid Yegoshin 
2147b0a668fbSLeonid Yegoshin 		vaddr = regs->regs[MIPSInst_RS(inst)] + MIPSInst_SIMM(inst);
2148b0a668fbSLeonid Yegoshin 		if (vaddr & 0x7) {
2149b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
2150b0a668fbSLeonid Yegoshin 			err = SIGBUS;
2151b0a668fbSLeonid Yegoshin 			break;
2152b0a668fbSLeonid Yegoshin 		}
215396d4f267SLinus Torvalds 		if (!access_ok((void __user *)vaddr, 8)) {
2154b0a668fbSLeonid Yegoshin 			current->thread.cp0_baduaddr = vaddr;
2155b0a668fbSLeonid Yegoshin 			err = SIGBUS;
2156b0a668fbSLeonid Yegoshin 			break;
2157b0a668fbSLeonid Yegoshin 		}
2158b0a668fbSLeonid Yegoshin 
2159b0a668fbSLeonid Yegoshin 		if (!cpu_has_rw_llb) {
2160b0a668fbSLeonid Yegoshin 			/*
2161b0a668fbSLeonid Yegoshin 			 * An LL/SC block can't be safely emulated without
2162b0a668fbSLeonid Yegoshin 			 * a Config5/LLB availability. So it's probably time to
2163b0a668fbSLeonid Yegoshin 			 * kill our process before things get any worse. This is
2164b0a668fbSLeonid Yegoshin 			 * because Config5/LLB allows us to use ERETNC so that
2165b0a668fbSLeonid Yegoshin 			 * the LLAddr/LLB bit is not cleared when we return from
2166b0a668fbSLeonid Yegoshin 			 * an exception. MIPS R2 LL/SC instructions trap with an
2167b0a668fbSLeonid Yegoshin 			 * RI exception so once we emulate them here, we return
2168b0a668fbSLeonid Yegoshin 			 * back to userland with ERETNC. That preserves the
2169b0a668fbSLeonid Yegoshin 			 * LLAddr/LLB so the subsequent SC instruction will
2170b0a668fbSLeonid Yegoshin 			 * succeed preserving the atomic semantics of the LL/SC
2171b0a668fbSLeonid Yegoshin 			 * block. Without that, there is no safe way to emulate
2172b0a668fbSLeonid Yegoshin 			 * an LL/SC block in MIPSR2 userland.
2173b0a668fbSLeonid Yegoshin 			 */
2174b0a668fbSLeonid Yegoshin 			pr_err("Can't emulate MIPSR2 LL/SC without Config5/LLB\n");
2175b0a668fbSLeonid Yegoshin 			err = SIGKILL;
2176b0a668fbSLeonid Yegoshin 			break;
2177b0a668fbSLeonid Yegoshin 		}
2178b0a668fbSLeonid Yegoshin 
2179b0a668fbSLeonid Yegoshin 		res = regs->regs[MIPSInst_RT(inst)];
2180b0a668fbSLeonid Yegoshin 
2181b0a668fbSLeonid Yegoshin 		__asm__ __volatile__(
2182b0a668fbSLeonid Yegoshin 			"1:\n"
2183b0a668fbSLeonid Yegoshin 			"scd	%0, 0(%2)\n"
2184b0a668fbSLeonid Yegoshin 			"2:\n"
2185b0a668fbSLeonid Yegoshin 			".insn\n"
2186b0a668fbSLeonid Yegoshin 			".section        .fixup,\"ax\"\n"
2187b0a668fbSLeonid Yegoshin 			"3:\n"
2188b0a668fbSLeonid Yegoshin 			"li	%1, %3\n"
2189b0a668fbSLeonid Yegoshin 			"j	2b\n"
2190b0a668fbSLeonid Yegoshin 			".previous\n"
2191b0a668fbSLeonid Yegoshin 			".section        __ex_table,\"a\"\n"
2192*a3ba49c1SThomas Bogendoerfer 			STR(PTR_WD) " 1b,3b\n"
2193b0a668fbSLeonid Yegoshin 			".previous\n"
2194b0a668fbSLeonid Yegoshin 			: "+&r"(res), "+&r"(err)
2195b0a668fbSLeonid Yegoshin 			: "r"(vaddr), "i"(SIGSEGV));
2196b0a668fbSLeonid Yegoshin 
2197b0a668fbSLeonid Yegoshin 		if (MIPSInst_RT(inst) && !err)
2198b0a668fbSLeonid Yegoshin 			regs->regs[MIPSInst_RT(inst)] = res;
2199b0a668fbSLeonid Yegoshin 
2200b0a668fbSLeonid Yegoshin 		MIPS_R2_STATS(llsc);
2201b0a668fbSLeonid Yegoshin 
2202b0a668fbSLeonid Yegoshin 		break;
2203b0a668fbSLeonid Yegoshin 	case pref_op:
2204b0a668fbSLeonid Yegoshin 		/* skip it */
2205b0a668fbSLeonid Yegoshin 		break;
2206b0a668fbSLeonid Yegoshin 	default:
2207b0a668fbSLeonid Yegoshin 		err = SIGILL;
2208b0a668fbSLeonid Yegoshin 	}
2209b0a668fbSLeonid Yegoshin 
2210b0a668fbSLeonid Yegoshin 	/*
22114939788eSRalf Baechle 	 * Let's not return to userland just yet. It's costly and
2212b0a668fbSLeonid Yegoshin 	 * it's likely we have more R2 instructions to emulate
2213b0a668fbSLeonid Yegoshin 	 */
2214b0a668fbSLeonid Yegoshin 	if (!err && (pass++ < MIPS_R2_EMUL_TOTAL_PASS)) {
2215b0a668fbSLeonid Yegoshin 		regs->cp0_cause &= ~CAUSEF_BD;
2216b0a668fbSLeonid Yegoshin 		err = get_user(inst, (u32 __user *)regs->cp0_epc);
2217b0a668fbSLeonid Yegoshin 		if (!err)
2218b0a668fbSLeonid Yegoshin 			goto repeat;
2219b0a668fbSLeonid Yegoshin 
2220b0a668fbSLeonid Yegoshin 		if (err < 0)
2221b0a668fbSLeonid Yegoshin 			err = SIGSEGV;
2222b0a668fbSLeonid Yegoshin 	}
2223b0a668fbSLeonid Yegoshin 
2224b0a668fbSLeonid Yegoshin 	if (err && (err != SIGEMT)) {
2225b0a668fbSLeonid Yegoshin 		regs->regs[31] = r31;
2226b0a668fbSLeonid Yegoshin 		regs->cp0_epc = epc;
2227b0a668fbSLeonid Yegoshin 	}
2228b0a668fbSLeonid Yegoshin 
2229b0a668fbSLeonid Yegoshin 	/* Likely a MIPS R6 compatible instruction */
2230b0a668fbSLeonid Yegoshin 	if (pass && (err == SIGILL))
2231b0a668fbSLeonid Yegoshin 		err = 0;
2232b0a668fbSLeonid Yegoshin 
2233b0a668fbSLeonid Yegoshin 	return err;
2234b0a668fbSLeonid Yegoshin }
2235b0a668fbSLeonid Yegoshin 
2236b0a668fbSLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
2237b0a668fbSLeonid Yegoshin 
mipsr2_emul_show(struct seq_file * s,void * unused)223843da4e3eSYangtao Li static int mipsr2_emul_show(struct seq_file *s, void *unused)
2239b0a668fbSLeonid Yegoshin {
2240b0a668fbSLeonid Yegoshin 
2241b0a668fbSLeonid Yegoshin 	seq_printf(s, "Instruction\tTotal\tBDslot\n------------------------------\n");
2242b0a668fbSLeonid Yegoshin 	seq_printf(s, "movs\t\t%ld\t%ld\n",
2243b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.movs),
2244b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.movs));
2245b0a668fbSLeonid Yegoshin 	seq_printf(s, "hilo\t\t%ld\t%ld\n",
2246b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.hilo),
2247b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.hilo));
2248b0a668fbSLeonid Yegoshin 	seq_printf(s, "muls\t\t%ld\t%ld\n",
2249b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.muls),
2250b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.muls));
2251b0a668fbSLeonid Yegoshin 	seq_printf(s, "divs\t\t%ld\t%ld\n",
2252b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.divs),
2253b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.divs));
2254b0a668fbSLeonid Yegoshin 	seq_printf(s, "dsps\t\t%ld\t%ld\n",
2255b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.dsps),
2256b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.dsps));
2257b0a668fbSLeonid Yegoshin 	seq_printf(s, "bops\t\t%ld\t%ld\n",
2258b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.bops),
2259b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.bops));
2260b0a668fbSLeonid Yegoshin 	seq_printf(s, "traps\t\t%ld\t%ld\n",
2261b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.traps),
2262b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.traps));
2263b0a668fbSLeonid Yegoshin 	seq_printf(s, "fpus\t\t%ld\t%ld\n",
2264b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.fpus),
2265b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.fpus));
2266b0a668fbSLeonid Yegoshin 	seq_printf(s, "loads\t\t%ld\t%ld\n",
2267b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.loads),
2268b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.loads));
2269b0a668fbSLeonid Yegoshin 	seq_printf(s, "stores\t\t%ld\t%ld\n",
2270b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.stores),
2271b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.stores));
2272b0a668fbSLeonid Yegoshin 	seq_printf(s, "llsc\t\t%ld\t%ld\n",
2273b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.llsc),
2274b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.llsc));
2275b0a668fbSLeonid Yegoshin 	seq_printf(s, "dsemul\t\t%ld\t%ld\n",
2276b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2emustats.dsemul),
2277b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bdemustats.dsemul));
2278b0a668fbSLeonid Yegoshin 	seq_printf(s, "jr\t\t%ld\n",
2279b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.jrs));
2280b0a668fbSLeonid Yegoshin 	seq_printf(s, "bltzl\t\t%ld\n",
2281b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bltzl));
2282b0a668fbSLeonid Yegoshin 	seq_printf(s, "bgezl\t\t%ld\n",
2283b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bgezl));
2284b0a668fbSLeonid Yegoshin 	seq_printf(s, "bltzll\t\t%ld\n",
2285b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bltzll));
2286b0a668fbSLeonid Yegoshin 	seq_printf(s, "bgezll\t\t%ld\n",
2287b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bgezll));
2288b0a668fbSLeonid Yegoshin 	seq_printf(s, "bltzal\t\t%ld\n",
2289b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bltzal));
2290b0a668fbSLeonid Yegoshin 	seq_printf(s, "bgezal\t\t%ld\n",
2291b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bgezal));
2292b0a668fbSLeonid Yegoshin 	seq_printf(s, "beql\t\t%ld\n",
2293b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.beql));
2294b0a668fbSLeonid Yegoshin 	seq_printf(s, "bnel\t\t%ld\n",
2295b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bnel));
2296b0a668fbSLeonid Yegoshin 	seq_printf(s, "blezl\t\t%ld\n",
2297b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.blezl));
2298b0a668fbSLeonid Yegoshin 	seq_printf(s, "bgtzl\t\t%ld\n",
2299b0a668fbSLeonid Yegoshin 		   (unsigned long)__this_cpu_read(mipsr2bremustats.bgtzl));
2300b0a668fbSLeonid Yegoshin 
2301b0a668fbSLeonid Yegoshin 	return 0;
2302b0a668fbSLeonid Yegoshin }
2303b0a668fbSLeonid Yegoshin 
mipsr2_clear_show(struct seq_file * s,void * unused)230443da4e3eSYangtao Li static int mipsr2_clear_show(struct seq_file *s, void *unused)
2305b0a668fbSLeonid Yegoshin {
230643da4e3eSYangtao Li 	mipsr2_emul_show(s, unused);
2307b0a668fbSLeonid Yegoshin 
2308b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).movs, 0);
2309b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).movs, 0);
2310b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).hilo, 0);
2311b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).hilo, 0);
2312b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).muls, 0);
2313b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).muls, 0);
2314b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).divs, 0);
2315b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).divs, 0);
2316b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).dsps, 0);
2317b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).dsps, 0);
2318b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).bops, 0);
2319b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).bops, 0);
2320b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).traps, 0);
2321b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).traps, 0);
2322b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).fpus, 0);
2323b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).fpus, 0);
2324b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).loads, 0);
2325b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).loads, 0);
2326b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).stores, 0);
2327b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).stores, 0);
2328b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).llsc, 0);
2329b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).llsc, 0);
2330b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2emustats).dsemul, 0);
2331b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bdemustats).dsemul, 0);
2332b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).jrs, 0);
2333b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bltzl, 0);
2334b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bgezl, 0);
2335b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bltzll, 0);
2336b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bgezll, 0);
2337411dac79SAleksandar Markovic 	__this_cpu_write((mipsr2bremustats).bltzall, 0);
2338411dac79SAleksandar Markovic 	__this_cpu_write((mipsr2bremustats).bgezall, 0);
2339b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bltzal, 0);
2340b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bgezal, 0);
2341b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).beql, 0);
2342b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bnel, 0);
2343b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).blezl, 0);
2344b0a668fbSLeonid Yegoshin 	__this_cpu_write((mipsr2bremustats).bgtzl, 0);
2345b0a668fbSLeonid Yegoshin 
2346b0a668fbSLeonid Yegoshin 	return 0;
2347b0a668fbSLeonid Yegoshin }
2348b0a668fbSLeonid Yegoshin 
234943da4e3eSYangtao Li DEFINE_SHOW_ATTRIBUTE(mipsr2_emul);
235043da4e3eSYangtao Li DEFINE_SHOW_ATTRIBUTE(mipsr2_clear);
2351b0a668fbSLeonid Yegoshin 
mipsr2_init_debugfs(void)2352b0a668fbSLeonid Yegoshin static int __init mipsr2_init_debugfs(void)
2353b0a668fbSLeonid Yegoshin {
2354d8140426SGreg Kroah-Hartman 	debugfs_create_file("r2_emul_stats", S_IRUGO, mips_debugfs_dir, NULL,
2355b0a668fbSLeonid Yegoshin 			    &mipsr2_emul_fops);
2356d8140426SGreg Kroah-Hartman 	debugfs_create_file("r2_emul_stats_clear", S_IRUGO, mips_debugfs_dir,
2357d8140426SGreg Kroah-Hartman 			    NULL, &mipsr2_clear_fops);
2358b0a668fbSLeonid Yegoshin 	return 0;
2359b0a668fbSLeonid Yegoshin }
2360b0a668fbSLeonid Yegoshin 
2361b0a668fbSLeonid Yegoshin device_initcall(mipsr2_init_debugfs);
2362b0a668fbSLeonid Yegoshin 
2363b0a668fbSLeonid Yegoshin #endif /* CONFIG_DEBUG_FS */
2364