xref: /openbmc/linux/arch/mips/kernel/unaligned.c (revision 6673c276)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Handle unaligned accesses by emulation.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
51da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
61da177e4SLinus Torvalds  * for more details.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
91da177e4SLinus Torvalds  * Copyright (C) 1999 Silicon Graphics, Inc.
109d8e5736SMarkos Chandras  * Copyright (C) 2014 Imagination Technologies Ltd.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * This file contains exception handler for address error exception with the
131da177e4SLinus Torvalds  * special capability to execute faulting instructions in software.  The
141da177e4SLinus Torvalds  * handler does not try to handle the case when the program counter points
151da177e4SLinus Torvalds  * to an address not aligned to a word boundary.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * Putting data to unaligned addresses is a bad practice even on Intel where
181da177e4SLinus Torvalds  * only the performance is affected.  Much worse is that such code is non-
191da177e4SLinus Torvalds  * portable.  Due to several programs that die on MIPS due to alignment
201da177e4SLinus Torvalds  * problems I decided to implement this handler anyway though I originally
211da177e4SLinus Torvalds  * didn't intend to do this at all for user code.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * For now I enable fixing of address errors by default to make life easier.
241da177e4SLinus Torvalds  * I however intend to disable this somewhen in the future when the alignment
251da177e4SLinus Torvalds  * problems with user programs have been fixed.	 For programmers this is the
261da177e4SLinus Torvalds  * right way to go.
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  * Fixing address errors is a per process option.  The option is inherited
291da177e4SLinus Torvalds  * across fork(2) and execve(2) calls.	If you really want to use the
301da177e4SLinus Torvalds  * option in your user programs - I discourage the use of the software
311da177e4SLinus Torvalds  * emulation strongly - use the following code in your userland stuff:
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * #include <sys/sysmips.h>
341da177e4SLinus Torvalds  *
351da177e4SLinus Torvalds  * ...
361da177e4SLinus Torvalds  * sysmips(MIPS_FIXADE, x);
371da177e4SLinus Torvalds  * ...
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds  * The argument x is 0 for disabling software emulation, enabled otherwise.
401da177e4SLinus Torvalds  *
411da177e4SLinus Torvalds  * Below a little program to play around with this feature.
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * #include <stdio.h>
441da177e4SLinus Torvalds  * #include <sys/sysmips.h>
451da177e4SLinus Torvalds  *
461da177e4SLinus Torvalds  * struct foo {
471da177e4SLinus Torvalds  *	   unsigned char bar[8];
481da177e4SLinus Torvalds  * };
491da177e4SLinus Torvalds  *
501da177e4SLinus Torvalds  * main(int argc, char *argv[])
511da177e4SLinus Torvalds  * {
521da177e4SLinus Torvalds  *	   struct foo x = {0, 1, 2, 3, 4, 5, 6, 7};
531da177e4SLinus Torvalds  *	   unsigned int *p = (unsigned int *) (x.bar + 3);
541da177e4SLinus Torvalds  *	   int i;
551da177e4SLinus Torvalds  *
561da177e4SLinus Torvalds  *	   if (argc > 1)
571da177e4SLinus Torvalds  *		   sysmips(MIPS_FIXADE, atoi(argv[1]));
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  *	   printf("*p = %08lx\n", *p);
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  *	   *p = 0xdeadface;
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  *	   for(i = 0; i <= 7; i++)
641da177e4SLinus Torvalds  *	   printf("%02x ", x.bar[i]);
651da177e4SLinus Torvalds  *	   printf("\n");
661da177e4SLinus Torvalds  * }
671da177e4SLinus Torvalds  *
681da177e4SLinus Torvalds  * Coprocessor loads are not supported; I think this case is unimportant
691da177e4SLinus Torvalds  * in the practice.
701da177e4SLinus Torvalds  *
711da177e4SLinus Torvalds  * TODO: Handle ndc (attempted store to doubleword in uncached memory)
721da177e4SLinus Torvalds  *	 exception for the R6000.
731da177e4SLinus Torvalds  *	 A store crossing a page boundary might be executed only partially.
741da177e4SLinus Torvalds  *	 Undo the partial store in this case.
751da177e4SLinus Torvalds  */
76c3fc5cd5SRalf Baechle #include <linux/context_tracking.h>
771da177e4SLinus Torvalds #include <linux/mm.h>
781da177e4SLinus Torvalds #include <linux/signal.h>
791da177e4SLinus Torvalds #include <linux/smp.h>
80e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
816312e0eeSAtsushi Nemoto #include <linux/debugfs.h>
827f788d2dSDeng-Cheng Zhu #include <linux/perf_event.h>
837f788d2dSDeng-Cheng Zhu 
841da177e4SLinus Torvalds #include <asm/asm.h>
851da177e4SLinus Torvalds #include <asm/branch.h>
861da177e4SLinus Torvalds #include <asm/byteorder.h>
8769f3a7deSRalf Baechle #include <asm/cop2.h>
8875dcfc1dSPaul Burton #include <asm/debug.h>
89102cedc3SLeonid Yegoshin #include <asm/fpu.h>
90102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h>
911da177e4SLinus Torvalds #include <asm/inst.h>
92b3878a6aSThomas Bogendoerfer #include <asm/unaligned-emul.h>
93c8790d65SPaul Burton #include <asm/mmu_context.h>
947c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
951da177e4SLinus Torvalds 
9645deb5faSThomas Bogendoerfer #include "access-helper.h"
9745deb5faSThomas Bogendoerfer 
986312e0eeSAtsushi Nemoto enum {
996312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_QUIET,
1006312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SIGNAL,
1016312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SHOW,
1026312e0eeSAtsushi Nemoto };
1036312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
1046312e0eeSAtsushi Nemoto static u32 unaligned_instructions;
1056312e0eeSAtsushi Nemoto static u32 unaligned_action;
1066312e0eeSAtsushi Nemoto #else
1076312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET
1081da177e4SLinus Torvalds #endif
1096312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs);
1101da177e4SLinus Torvalds 
emulate_load_store_insn(struct pt_regs * regs,void __user * addr,unsigned int * pc)1117f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs,
1127cba4128SThomas Bogendoerfer 	void __user *addr, unsigned int *pc)
1131da177e4SLinus Torvalds {
11485164fd8SPaul Burton 	unsigned long origpc, orig31, value;
1151da177e4SLinus Torvalds 	union mips_instruction insn;
11685164fd8SPaul Burton 	unsigned int res;
11745deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
11845deb5faSThomas Bogendoerfer 
11934c2f668SLeonid Yegoshin 	origpc = (unsigned long)pc;
12034c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
12134c2f668SLeonid Yegoshin 
122a8b0ca17SPeter Zijlstra 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
1237f788d2dSDeng-Cheng Zhu 
1241da177e4SLinus Torvalds 	/*
1251da177e4SLinus Torvalds 	 * This load never faults.
1261da177e4SLinus Torvalds 	 */
12745deb5faSThomas Bogendoerfer 	__get_inst32(&insn.word, pc, user);
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds 	switch (insn.i_format.opcode) {
1301da177e4SLinus Torvalds 		/*
1311da177e4SLinus Torvalds 		 * These are instructions that a compiler doesn't generate.  We
1321da177e4SLinus Torvalds 		 * can assume therefore that the code is MIPS-aware and
1331da177e4SLinus Torvalds 		 * really buggy.  Emulating these instructions would break the
1341da177e4SLinus Torvalds 		 * semantics anyway.
1351da177e4SLinus Torvalds 		 */
1361da177e4SLinus Torvalds 	case ll_op:
1371da177e4SLinus Torvalds 	case lld_op:
1381da177e4SLinus Torvalds 	case sc_op:
1391da177e4SLinus Torvalds 	case scd_op:
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 		/*
1421da177e4SLinus Torvalds 		 * For these instructions the only way to create an address
1431da177e4SLinus Torvalds 		 * error is an attempted access to kernel/supervisor address
1441da177e4SLinus Torvalds 		 * space.
1451da177e4SLinus Torvalds 		 */
1461da177e4SLinus Torvalds 	case ldl_op:
1471da177e4SLinus Torvalds 	case ldr_op:
1481da177e4SLinus Torvalds 	case lwl_op:
1491da177e4SLinus Torvalds 	case lwr_op:
1501da177e4SLinus Torvalds 	case sdl_op:
1511da177e4SLinus Torvalds 	case sdr_op:
1521da177e4SLinus Torvalds 	case swl_op:
1531da177e4SLinus Torvalds 	case swr_op:
1541da177e4SLinus Torvalds 	case lb_op:
1551da177e4SLinus Torvalds 	case lbu_op:
1561da177e4SLinus Torvalds 	case sb_op:
1571da177e4SLinus Torvalds 		goto sigbus;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 		/*
16034c2f668SLeonid Yegoshin 		 * The remaining opcodes are the ones that are really of
16134c2f668SLeonid Yegoshin 		 * interest.
1621da177e4SLinus Torvalds 		 */
163*6673c276SSiarhei Volkau #ifdef CONFIG_MACH_INGENIC
164*6673c276SSiarhei Volkau 	case spec2_op:
165*6673c276SSiarhei Volkau 		if (insn.mxu_lx_format.func != mxu_lx_op)
166*6673c276SSiarhei Volkau 			goto sigbus; /* other MXU instructions we don't care */
167*6673c276SSiarhei Volkau 
168*6673c276SSiarhei Volkau 		switch (insn.mxu_lx_format.op) {
169*6673c276SSiarhei Volkau 		case mxu_lxw_op:
170*6673c276SSiarhei Volkau 			if (user && !access_ok(addr, 4))
171*6673c276SSiarhei Volkau 				goto sigbus;
172*6673c276SSiarhei Volkau 			LoadW(addr, value, res);
173*6673c276SSiarhei Volkau 			if (res)
174*6673c276SSiarhei Volkau 				goto fault;
175*6673c276SSiarhei Volkau 			compute_return_epc(regs);
176*6673c276SSiarhei Volkau 			regs->regs[insn.mxu_lx_format.rd] = value;
177*6673c276SSiarhei Volkau 			break;
178*6673c276SSiarhei Volkau 		case mxu_lxh_op:
179*6673c276SSiarhei Volkau 			if (user && !access_ok(addr, 2))
180*6673c276SSiarhei Volkau 				goto sigbus;
181*6673c276SSiarhei Volkau 			LoadHW(addr, value, res);
182*6673c276SSiarhei Volkau 			if (res)
183*6673c276SSiarhei Volkau 				goto fault;
184*6673c276SSiarhei Volkau 			compute_return_epc(regs);
185*6673c276SSiarhei Volkau 			regs->regs[insn.dsp_format.rd] = value;
186*6673c276SSiarhei Volkau 			break;
187*6673c276SSiarhei Volkau 		case mxu_lxhu_op:
188*6673c276SSiarhei Volkau 			if (user && !access_ok(addr, 2))
189*6673c276SSiarhei Volkau 				goto sigbus;
190*6673c276SSiarhei Volkau 			LoadHWU(addr, value, res);
191*6673c276SSiarhei Volkau 			if (res)
192*6673c276SSiarhei Volkau 				goto fault;
193*6673c276SSiarhei Volkau 			compute_return_epc(regs);
194*6673c276SSiarhei Volkau 			regs->regs[insn.dsp_format.rd] = value;
195*6673c276SSiarhei Volkau 			break;
196*6673c276SSiarhei Volkau 		case mxu_lxb_op:
197*6673c276SSiarhei Volkau 		case mxu_lxbu_op:
198*6673c276SSiarhei Volkau 			goto sigbus;
199*6673c276SSiarhei Volkau 		default:
200*6673c276SSiarhei Volkau 			goto sigill;
201*6673c276SSiarhei Volkau 		}
202*6673c276SSiarhei Volkau 		break;
203*6673c276SSiarhei Volkau #endif
204c1771216SLeonid Yegoshin 	case spec3_op:
2053f88ec63SMiodrag Dinic 		if (insn.dsp_format.func == lx_op) {
2063f88ec63SMiodrag Dinic 			switch (insn.dsp_format.op) {
2073f88ec63SMiodrag Dinic 			case lwx_op:
20845deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4))
2093f88ec63SMiodrag Dinic 					goto sigbus;
2103f88ec63SMiodrag Dinic 				LoadW(addr, value, res);
2113f88ec63SMiodrag Dinic 				if (res)
2123f88ec63SMiodrag Dinic 					goto fault;
2133f88ec63SMiodrag Dinic 				compute_return_epc(regs);
2143f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
2153f88ec63SMiodrag Dinic 				break;
2163f88ec63SMiodrag Dinic 			case lhx_op:
21745deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 2))
2183f88ec63SMiodrag Dinic 					goto sigbus;
2193f88ec63SMiodrag Dinic 				LoadHW(addr, value, res);
2203f88ec63SMiodrag Dinic 				if (res)
2213f88ec63SMiodrag Dinic 					goto fault;
2223f88ec63SMiodrag Dinic 				compute_return_epc(regs);
2233f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
2243f88ec63SMiodrag Dinic 				break;
2253f88ec63SMiodrag Dinic 			default:
2263f88ec63SMiodrag Dinic 				goto sigill;
2273f88ec63SMiodrag Dinic 			}
2283f88ec63SMiodrag Dinic 		}
2293f88ec63SMiodrag Dinic #ifdef CONFIG_EVA
2303f88ec63SMiodrag Dinic 		else {
231c1771216SLeonid Yegoshin 			/*
2323f88ec63SMiodrag Dinic 			 * we can land here only from kernel accessing user
2333f88ec63SMiodrag Dinic 			 * memory, so we need to "switch" the address limit to
2343f88ec63SMiodrag Dinic 			 * user space, so that address check can work properly.
235c1771216SLeonid Yegoshin 			 */
236c1771216SLeonid Yegoshin 			switch (insn.spec3_format.func) {
237c1771216SLeonid Yegoshin 			case lhe_op:
23845deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
239c1771216SLeonid Yegoshin 					goto sigbus;
240eeb53895SMarkos Chandras 				LoadHWE(addr, value, res);
24145deb5faSThomas Bogendoerfer 				if (res)
242c1771216SLeonid Yegoshin 					goto fault;
243c1771216SLeonid Yegoshin 				compute_return_epc(regs);
244c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
245c1771216SLeonid Yegoshin 				break;
246c1771216SLeonid Yegoshin 			case lwe_op:
24745deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 4))
248c1771216SLeonid Yegoshin 					goto sigbus;
249eeb53895SMarkos Chandras 				LoadWE(addr, value, res);
25045deb5faSThomas Bogendoerfer 				if (res)
251c1771216SLeonid Yegoshin 					goto fault;
252c1771216SLeonid Yegoshin 				compute_return_epc(regs);
253c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
254c1771216SLeonid Yegoshin 				break;
255c1771216SLeonid Yegoshin 			case lhue_op:
25645deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
257c1771216SLeonid Yegoshin 					goto sigbus;
258eeb53895SMarkos Chandras 				LoadHWUE(addr, value, res);
25945deb5faSThomas Bogendoerfer 				if (res)
260c1771216SLeonid Yegoshin 					goto fault;
261c1771216SLeonid Yegoshin 				compute_return_epc(regs);
262c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
263c1771216SLeonid Yegoshin 				break;
264c1771216SLeonid Yegoshin 			case she_op:
26545deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
266c1771216SLeonid Yegoshin 					goto sigbus;
267c1771216SLeonid Yegoshin 				compute_return_epc(regs);
268c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
269eeb53895SMarkos Chandras 				StoreHWE(addr, value, res);
27045deb5faSThomas Bogendoerfer 				if (res)
271c1771216SLeonid Yegoshin 					goto fault;
272c1771216SLeonid Yegoshin 				break;
273c1771216SLeonid Yegoshin 			case swe_op:
27445deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 4))
275c1771216SLeonid Yegoshin 					goto sigbus;
276c1771216SLeonid Yegoshin 				compute_return_epc(regs);
277c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
278eeb53895SMarkos Chandras 				StoreWE(addr, value, res);
27945deb5faSThomas Bogendoerfer 				if (res)
280c1771216SLeonid Yegoshin 					goto fault;
281c1771216SLeonid Yegoshin 				break;
282c1771216SLeonid Yegoshin 			default:
283c1771216SLeonid Yegoshin 				goto sigill;
284c1771216SLeonid Yegoshin 			}
2853f88ec63SMiodrag Dinic 		}
286c1771216SLeonid Yegoshin #endif
2873f88ec63SMiodrag Dinic 		break;
2881da177e4SLinus Torvalds 	case lh_op:
28945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
2901da177e4SLinus Torvalds 			goto sigbus;
2911da177e4SLinus Torvalds 
29245deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
2936eae3548SMarkos Chandras 			LoadHWE(addr, value, res);
29445deb5faSThomas Bogendoerfer 		else
2956eae3548SMarkos Chandras 			LoadHW(addr, value, res);
2966eae3548SMarkos Chandras 
2971da177e4SLinus Torvalds 		if (res)
2981da177e4SLinus Torvalds 			goto fault;
2997f18f151SRalf Baechle 		compute_return_epc(regs);
3007f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3011da177e4SLinus Torvalds 		break;
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	case lw_op:
30445deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3051da177e4SLinus Torvalds 			goto sigbus;
3061da177e4SLinus Torvalds 
30745deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3086eae3548SMarkos Chandras 			LoadWE(addr, value, res);
30945deb5faSThomas Bogendoerfer 		else
3106eae3548SMarkos Chandras 			LoadW(addr, value, res);
3116eae3548SMarkos Chandras 
3121da177e4SLinus Torvalds 		if (res)
3131da177e4SLinus Torvalds 			goto fault;
3147f18f151SRalf Baechle 		compute_return_epc(regs);
3157f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3161da177e4SLinus Torvalds 		break;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	case lhu_op:
31945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
3201da177e4SLinus Torvalds 			goto sigbus;
3211da177e4SLinus Torvalds 
32245deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3236eae3548SMarkos Chandras 			LoadHWUE(addr, value, res);
32445deb5faSThomas Bogendoerfer 		else
3256eae3548SMarkos Chandras 			LoadHWU(addr, value, res);
3266eae3548SMarkos Chandras 
3271da177e4SLinus Torvalds 		if (res)
3281da177e4SLinus Torvalds 			goto fault;
3297f18f151SRalf Baechle 		compute_return_epc(regs);
3307f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3311da177e4SLinus Torvalds 		break;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	case lwu_op:
334875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3351da177e4SLinus Torvalds 		/*
3361da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
3371da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
3381da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
3391da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
3401da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3411da177e4SLinus Torvalds 		 */
34245deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3431da177e4SLinus Torvalds 			goto sigbus;
3441da177e4SLinus Torvalds 
34534c2f668SLeonid Yegoshin 		LoadWU(addr, value, res);
3461da177e4SLinus Torvalds 		if (res)
3471da177e4SLinus Torvalds 			goto fault;
3487f18f151SRalf Baechle 		compute_return_epc(regs);
3497f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3501da177e4SLinus Torvalds 		break;
351875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3541da177e4SLinus Torvalds 		goto sigill;
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	case ld_op:
357875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3581da177e4SLinus Torvalds 		/*
3591da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
3601da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
3611da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
3621da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
3631da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3641da177e4SLinus Torvalds 		 */
36545deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
3661da177e4SLinus Torvalds 			goto sigbus;
3671da177e4SLinus Torvalds 
36834c2f668SLeonid Yegoshin 		LoadDW(addr, value, res);
3691da177e4SLinus Torvalds 		if (res)
3701da177e4SLinus Torvalds 			goto fault;
3717f18f151SRalf Baechle 		compute_return_epc(regs);
3727f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3731da177e4SLinus Torvalds 		break;
374875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3771da177e4SLinus Torvalds 		goto sigill;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	case sh_op:
38045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
3811da177e4SLinus Torvalds 			goto sigbus;
3821da177e4SLinus Torvalds 
38334c2f668SLeonid Yegoshin 		compute_return_epc(regs);
3841da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
3856eae3548SMarkos Chandras 
38645deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3876eae3548SMarkos Chandras 			StoreHWE(addr, value, res);
38845deb5faSThomas Bogendoerfer 		else
3896eae3548SMarkos Chandras 			StoreHW(addr, value, res);
3906eae3548SMarkos Chandras 
3911da177e4SLinus Torvalds 		if (res)
3921da177e4SLinus Torvalds 			goto fault;
3931da177e4SLinus Torvalds 		break;
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	case sw_op:
39645deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3971da177e4SLinus Torvalds 			goto sigbus;
3981da177e4SLinus Torvalds 
39934c2f668SLeonid Yegoshin 		compute_return_epc(regs);
4001da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
4016eae3548SMarkos Chandras 
40245deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
4036eae3548SMarkos Chandras 			StoreWE(addr, value, res);
40445deb5faSThomas Bogendoerfer 		else
4056eae3548SMarkos Chandras 			StoreW(addr, value, res);
4066eae3548SMarkos Chandras 
4071da177e4SLinus Torvalds 		if (res)
4081da177e4SLinus Torvalds 			goto fault;
4091da177e4SLinus Torvalds 		break;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	case sd_op:
412875d43e7SRalf Baechle #ifdef CONFIG_64BIT
4131da177e4SLinus Torvalds 		/*
4141da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
4151da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
4161da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
4171da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
4181da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
4191da177e4SLinus Torvalds 		 */
42045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
4211da177e4SLinus Torvalds 			goto sigbus;
4221da177e4SLinus Torvalds 
42334c2f668SLeonid Yegoshin 		compute_return_epc(regs);
4241da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
42534c2f668SLeonid Yegoshin 		StoreDW(addr, value, res);
4261da177e4SLinus Torvalds 		if (res)
4271da177e4SLinus Torvalds 			goto fault;
4281da177e4SLinus Torvalds 		break;
429875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
4321da177e4SLinus Torvalds 		goto sigill;
4331da177e4SLinus Torvalds 
43485164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
43585164fd8SPaul Burton 
4361da177e4SLinus Torvalds 	case lwc1_op:
4371da177e4SLinus Torvalds 	case ldc1_op:
4381da177e4SLinus Torvalds 	case swc1_op:
4391da177e4SLinus Torvalds 	case sdc1_op:
44085164fd8SPaul Burton 	case cop1x_op: {
44185164fd8SPaul Burton 		void __user *fault_addr = NULL;
44285164fd8SPaul Burton 
443102cedc3SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
444102cedc3SLeonid Yegoshin 		BUG_ON(!used_math());
445102cedc3SLeonid Yegoshin 
446102cedc3SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
447102cedc3SLeonid Yegoshin 					       &fault_addr);
448102cedc3SLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
449102cedc3SLeonid Yegoshin 
450102cedc3SLeonid Yegoshin 		/* Signal if something went wrong. */
451304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
452102cedc3SLeonid Yegoshin 
453102cedc3SLeonid Yegoshin 		if (res == 0)
454102cedc3SLeonid Yegoshin 			break;
455102cedc3SLeonid Yegoshin 		return;
45685164fd8SPaul Burton 	}
45785164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
4581da177e4SLinus Torvalds 
45985164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
46085164fd8SPaul Burton 
46185164fd8SPaul Burton 	case msa_op: {
46285164fd8SPaul Burton 		unsigned int wd, preempted;
46385164fd8SPaul Burton 		enum msa_2b_fmt df;
46485164fd8SPaul Burton 		union fpureg *fpr;
46585164fd8SPaul Burton 
466e4aa1f15SLeonid Yegoshin 		if (!cpu_has_msa)
467e4aa1f15SLeonid Yegoshin 			goto sigill;
468e4aa1f15SLeonid Yegoshin 
469e4aa1f15SLeonid Yegoshin 		/*
470e4aa1f15SLeonid Yegoshin 		 * If we've reached this point then userland should have taken
471e4aa1f15SLeonid Yegoshin 		 * the MSA disabled exception & initialised vector context at
472e4aa1f15SLeonid Yegoshin 		 * some point in the past.
473e4aa1f15SLeonid Yegoshin 		 */
474e4aa1f15SLeonid Yegoshin 		BUG_ON(!thread_msa_context_live());
475e4aa1f15SLeonid Yegoshin 
476e4aa1f15SLeonid Yegoshin 		df = insn.msa_mi10_format.df;
477e4aa1f15SLeonid Yegoshin 		wd = insn.msa_mi10_format.wd;
478e4aa1f15SLeonid Yegoshin 		fpr = &current->thread.fpu.fpr[wd];
479e4aa1f15SLeonid Yegoshin 
480e4aa1f15SLeonid Yegoshin 		switch (insn.msa_mi10_format.func) {
481e4aa1f15SLeonid Yegoshin 		case msa_ld_op:
48296d4f267SLinus Torvalds 			if (!access_ok(addr, sizeof(*fpr)))
483e4aa1f15SLeonid Yegoshin 				goto sigbus;
484e4aa1f15SLeonid Yegoshin 
485fa8ff601SPaul Burton 			do {
486e4aa1f15SLeonid Yegoshin 				/*
487fa8ff601SPaul Burton 				 * If we have live MSA context keep track of
488fa8ff601SPaul Burton 				 * whether we get preempted in order to avoid
489fa8ff601SPaul Burton 				 * the register context we load being clobbered
490fa8ff601SPaul Burton 				 * by the live context as it's saved during
491fa8ff601SPaul Burton 				 * preemption. If we don't have live context
492fa8ff601SPaul Burton 				 * then it can't be saved to clobber the value
493fa8ff601SPaul Burton 				 * we load.
494e4aa1f15SLeonid Yegoshin 				 */
495fa8ff601SPaul Burton 				preempted = test_thread_flag(TIF_USEDMSA);
496e4aa1f15SLeonid Yegoshin 
497e4aa1f15SLeonid Yegoshin 				res = __copy_from_user_inatomic(fpr, addr,
498e4aa1f15SLeonid Yegoshin 								sizeof(*fpr));
499e4aa1f15SLeonid Yegoshin 				if (res)
500e4aa1f15SLeonid Yegoshin 					goto fault;
501e4aa1f15SLeonid Yegoshin 
502e4aa1f15SLeonid Yegoshin 				/*
503fa8ff601SPaul Burton 				 * Update the hardware register if it is in use
504fa8ff601SPaul Burton 				 * by the task in this quantum, in order to
505fa8ff601SPaul Burton 				 * avoid having to save & restore the whole
506fa8ff601SPaul Burton 				 * vector context.
507e4aa1f15SLeonid Yegoshin 				 */
508fa8ff601SPaul Burton 				preempt_disable();
509fa8ff601SPaul Burton 				if (test_thread_flag(TIF_USEDMSA)) {
510e4aa1f15SLeonid Yegoshin 					write_msa_wr(wd, fpr, df);
511fa8ff601SPaul Burton 					preempted = 0;
512fa8ff601SPaul Burton 				}
513e4aa1f15SLeonid Yegoshin 				preempt_enable();
514fa8ff601SPaul Burton 			} while (preempted);
515e4aa1f15SLeonid Yegoshin 			break;
516e4aa1f15SLeonid Yegoshin 
517e4aa1f15SLeonid Yegoshin 		case msa_st_op:
51896d4f267SLinus Torvalds 			if (!access_ok(addr, sizeof(*fpr)))
519e4aa1f15SLeonid Yegoshin 				goto sigbus;
520e4aa1f15SLeonid Yegoshin 
521e4aa1f15SLeonid Yegoshin 			/*
522e4aa1f15SLeonid Yegoshin 			 * Update from the hardware register if it is in use by
523e4aa1f15SLeonid Yegoshin 			 * the task in this quantum, in order to avoid having to
524e4aa1f15SLeonid Yegoshin 			 * save & restore the whole vector context.
525e4aa1f15SLeonid Yegoshin 			 */
526e4aa1f15SLeonid Yegoshin 			preempt_disable();
527e4aa1f15SLeonid Yegoshin 			if (test_thread_flag(TIF_USEDMSA))
528e4aa1f15SLeonid Yegoshin 				read_msa_wr(wd, fpr, df);
529e4aa1f15SLeonid Yegoshin 			preempt_enable();
530e4aa1f15SLeonid Yegoshin 
531e4aa1f15SLeonid Yegoshin 			res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr));
532e4aa1f15SLeonid Yegoshin 			if (res)
533e4aa1f15SLeonid Yegoshin 				goto fault;
534e4aa1f15SLeonid Yegoshin 			break;
535e4aa1f15SLeonid Yegoshin 
536e4aa1f15SLeonid Yegoshin 		default:
537e4aa1f15SLeonid Yegoshin 			goto sigbus;
538e4aa1f15SLeonid Yegoshin 		}
539e4aa1f15SLeonid Yegoshin 
540e4aa1f15SLeonid Yegoshin 		compute_return_epc(regs);
541e4aa1f15SLeonid Yegoshin 		break;
54285164fd8SPaul Burton 	}
54385164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */
544e4aa1f15SLeonid Yegoshin 
5450593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
5461da177e4SLinus Torvalds 	/*
54769f3a7deSRalf Baechle 	 * COP2 is available to implementor for application specific use.
54869f3a7deSRalf Baechle 	 * It's up to applications to register a notifier chain and do
54969f3a7deSRalf Baechle 	 * whatever they have to do, including possible sending of signals.
5500593a44cSLeonid Yegoshin 	 *
5510593a44cSLeonid Yegoshin 	 * This instruction has been reallocated in Release 6
5521da177e4SLinus Torvalds 	 */
55369f3a7deSRalf Baechle 	case lwc2_op:
55469f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
55569f3a7deSRalf Baechle 		break;
55669f3a7deSRalf Baechle 
55769f3a7deSRalf Baechle 	case ldc2_op:
55869f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
55969f3a7deSRalf Baechle 		break;
56069f3a7deSRalf Baechle 
56169f3a7deSRalf Baechle 	case swc2_op:
56269f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
56369f3a7deSRalf Baechle 		break;
56469f3a7deSRalf Baechle 
56569f3a7deSRalf Baechle 	case sdc2_op:
56669f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
56769f3a7deSRalf Baechle 		break;
5680593a44cSLeonid Yegoshin #endif
5691da177e4SLinus Torvalds 	default:
5701da177e4SLinus Torvalds 		/*
5711da177e4SLinus Torvalds 		 * Pheeee...  We encountered an yet unknown instruction or
5721da177e4SLinus Torvalds 		 * cache coherence problem.  Die sucker, die ...
5731da177e4SLinus Torvalds 		 */
5741da177e4SLinus Torvalds 		goto sigill;
5751da177e4SLinus Torvalds 	}
5761da177e4SLinus Torvalds 
5776312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
5781da177e4SLinus Torvalds 	unaligned_instructions++;
5791da177e4SLinus Torvalds #endif
5801da177e4SLinus Torvalds 
5817f18f151SRalf Baechle 	return;
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds fault:
58434c2f668SLeonid Yegoshin 	/* roll back jump/branch */
58534c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
58634c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
5871da177e4SLinus Torvalds 	/* Did we have an exception handler installed? */
5881da177e4SLinus Torvalds 	if (fixup_exception(regs))
5897f18f151SRalf Baechle 		return;
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
5923cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
5931da177e4SLinus Torvalds 
5947f18f151SRalf Baechle 	return;
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds sigbus:
5971da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
5983cf5d076SEric W. Biederman 	force_sig(SIGBUS);
5991da177e4SLinus Torvalds 
6007f18f151SRalf Baechle 	return;
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds sigill:
60334c2f668SLeonid Yegoshin 	die_if_kernel
60434c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
6053cf5d076SEric W. Biederman 	force_sig(SIGILL);
60634c2f668SLeonid Yegoshin }
60734c2f668SLeonid Yegoshin 
60834c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
60934c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
61034c2f668SLeonid Yegoshin 
61134c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
612b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
61334c2f668SLeonid Yegoshin 
emulate_load_store_microMIPS(struct pt_regs * regs,void __user * addr)61474338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
61574338805SDavid Daney 					 void __user *addr)
61634c2f668SLeonid Yegoshin {
61734c2f668SLeonid Yegoshin 	unsigned long value;
61834c2f668SLeonid Yegoshin 	unsigned int res;
61934c2f668SLeonid Yegoshin 	int i;
62034c2f668SLeonid Yegoshin 	unsigned int reg = 0, rvar;
62134c2f668SLeonid Yegoshin 	unsigned long orig31;
62234c2f668SLeonid Yegoshin 	u16 __user *pc16;
62334c2f668SLeonid Yegoshin 	u16 halfword;
62434c2f668SLeonid Yegoshin 	unsigned int word;
62534c2f668SLeonid Yegoshin 	unsigned long origpc, contpc;
62634c2f668SLeonid Yegoshin 	union mips_instruction insn;
62734c2f668SLeonid Yegoshin 	struct mm_decoded_insn mminsn;
62845deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
62934c2f668SLeonid Yegoshin 
63034c2f668SLeonid Yegoshin 	origpc = regs->cp0_epc;
63134c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
63234c2f668SLeonid Yegoshin 
63334c2f668SLeonid Yegoshin 	mminsn.micro_mips_mode = 1;
63434c2f668SLeonid Yegoshin 
63534c2f668SLeonid Yegoshin 	/*
63634c2f668SLeonid Yegoshin 	 * This load never faults.
63734c2f668SLeonid Yegoshin 	 */
63834c2f668SLeonid Yegoshin 	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
63934c2f668SLeonid Yegoshin 	__get_user(halfword, pc16);
64034c2f668SLeonid Yegoshin 	pc16++;
64134c2f668SLeonid Yegoshin 	contpc = regs->cp0_epc + 2;
64234c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
64334c2f668SLeonid Yegoshin 	mminsn.pc_inc = 2;
64434c2f668SLeonid Yegoshin 
64534c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
64634c2f668SLeonid Yegoshin 		__get_user(halfword, pc16);
64734c2f668SLeonid Yegoshin 		pc16++;
64834c2f668SLeonid Yegoshin 		contpc = regs->cp0_epc + 4;
64934c2f668SLeonid Yegoshin 		mminsn.pc_inc = 4;
65034c2f668SLeonid Yegoshin 		word |= halfword;
65134c2f668SLeonid Yegoshin 	}
65234c2f668SLeonid Yegoshin 	mminsn.insn = word;
65334c2f668SLeonid Yegoshin 
65434c2f668SLeonid Yegoshin 	if (get_user(halfword, pc16))
65534c2f668SLeonid Yegoshin 		goto fault;
65634c2f668SLeonid Yegoshin 	mminsn.next_pc_inc = 2;
65734c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
65834c2f668SLeonid Yegoshin 
65934c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
66034c2f668SLeonid Yegoshin 		pc16++;
66134c2f668SLeonid Yegoshin 		if (get_user(halfword, pc16))
66234c2f668SLeonid Yegoshin 			goto fault;
66334c2f668SLeonid Yegoshin 		mminsn.next_pc_inc = 4;
66434c2f668SLeonid Yegoshin 		word |= halfword;
66534c2f668SLeonid Yegoshin 	}
66634c2f668SLeonid Yegoshin 	mminsn.next_insn = word;
66734c2f668SLeonid Yegoshin 
66834c2f668SLeonid Yegoshin 	insn = (union mips_instruction)(mminsn.insn);
66934c2f668SLeonid Yegoshin 	if (mm_isBranchInstr(regs, mminsn, &contpc))
67034c2f668SLeonid Yegoshin 		insn = (union mips_instruction)(mminsn.next_insn);
67134c2f668SLeonid Yegoshin 
67234c2f668SLeonid Yegoshin 	/*  Parse instruction to find what to do */
67334c2f668SLeonid Yegoshin 
67434c2f668SLeonid Yegoshin 	switch (insn.mm_i_format.opcode) {
67534c2f668SLeonid Yegoshin 
67634c2f668SLeonid Yegoshin 	case mm_pool32a_op:
67734c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
67834c2f668SLeonid Yegoshin 		case mm_lwxs_op:
67934c2f668SLeonid Yegoshin 			reg = insn.mm_x_format.rd;
68034c2f668SLeonid Yegoshin 			goto loadW;
68134c2f668SLeonid Yegoshin 		}
68234c2f668SLeonid Yegoshin 
68334c2f668SLeonid Yegoshin 		goto sigbus;
68434c2f668SLeonid Yegoshin 
68534c2f668SLeonid Yegoshin 	case mm_pool32b_op:
68634c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
68734c2f668SLeonid Yegoshin 		case mm_lwp_func:
68834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
68934c2f668SLeonid Yegoshin 			if (reg == 31)
69034c2f668SLeonid Yegoshin 				goto sigbus;
69134c2f668SLeonid Yegoshin 
69245deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 8))
69334c2f668SLeonid Yegoshin 				goto sigbus;
69434c2f668SLeonid Yegoshin 
69534c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
69634c2f668SLeonid Yegoshin 			if (res)
69734c2f668SLeonid Yegoshin 				goto fault;
69834c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
69934c2f668SLeonid Yegoshin 			addr += 4;
70034c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
70134c2f668SLeonid Yegoshin 			if (res)
70234c2f668SLeonid Yegoshin 				goto fault;
70334c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
70434c2f668SLeonid Yegoshin 			goto success;
70534c2f668SLeonid Yegoshin 
70634c2f668SLeonid Yegoshin 		case mm_swp_func:
70734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
70834c2f668SLeonid Yegoshin 			if (reg == 31)
70934c2f668SLeonid Yegoshin 				goto sigbus;
71034c2f668SLeonid Yegoshin 
71145deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 8))
71234c2f668SLeonid Yegoshin 				goto sigbus;
71334c2f668SLeonid Yegoshin 
71434c2f668SLeonid Yegoshin 			value = regs->regs[reg];
71534c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
71634c2f668SLeonid Yegoshin 			if (res)
71734c2f668SLeonid Yegoshin 				goto fault;
71834c2f668SLeonid Yegoshin 			addr += 4;
71934c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
72034c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
72134c2f668SLeonid Yegoshin 			if (res)
72234c2f668SLeonid Yegoshin 				goto fault;
72334c2f668SLeonid Yegoshin 			goto success;
72434c2f668SLeonid Yegoshin 
72534c2f668SLeonid Yegoshin 		case mm_ldp_func:
72634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
72734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
72834c2f668SLeonid Yegoshin 			if (reg == 31)
72934c2f668SLeonid Yegoshin 				goto sigbus;
73034c2f668SLeonid Yegoshin 
73145deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 16))
73234c2f668SLeonid Yegoshin 				goto sigbus;
73334c2f668SLeonid Yegoshin 
73434c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
73534c2f668SLeonid Yegoshin 			if (res)
73634c2f668SLeonid Yegoshin 				goto fault;
73734c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
73834c2f668SLeonid Yegoshin 			addr += 8;
73934c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
74034c2f668SLeonid Yegoshin 			if (res)
74134c2f668SLeonid Yegoshin 				goto fault;
74234c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
74334c2f668SLeonid Yegoshin 			goto success;
74434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
74534c2f668SLeonid Yegoshin 
74634c2f668SLeonid Yegoshin 			goto sigill;
74734c2f668SLeonid Yegoshin 
74834c2f668SLeonid Yegoshin 		case mm_sdp_func:
74934c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
75034c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
75134c2f668SLeonid Yegoshin 			if (reg == 31)
75234c2f668SLeonid Yegoshin 				goto sigbus;
75334c2f668SLeonid Yegoshin 
75445deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 16))
75534c2f668SLeonid Yegoshin 				goto sigbus;
75634c2f668SLeonid Yegoshin 
75734c2f668SLeonid Yegoshin 			value = regs->regs[reg];
75834c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
75934c2f668SLeonid Yegoshin 			if (res)
76034c2f668SLeonid Yegoshin 				goto fault;
76134c2f668SLeonid Yegoshin 			addr += 8;
76234c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
76334c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
76434c2f668SLeonid Yegoshin 			if (res)
76534c2f668SLeonid Yegoshin 				goto fault;
76634c2f668SLeonid Yegoshin 			goto success;
76734c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
76834c2f668SLeonid Yegoshin 
76934c2f668SLeonid Yegoshin 			goto sigill;
77034c2f668SLeonid Yegoshin 
77134c2f668SLeonid Yegoshin 		case mm_lwm32_func:
77234c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
77334c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
77434c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
77534c2f668SLeonid Yegoshin 				goto sigill;
77634c2f668SLeonid Yegoshin 			if (reg & 0x10) {
77745deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * (rvar + 1)))
77834c2f668SLeonid Yegoshin 					goto sigbus;
77934c2f668SLeonid Yegoshin 			} else {
78045deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * rvar))
78134c2f668SLeonid Yegoshin 					goto sigbus;
78234c2f668SLeonid Yegoshin 			}
78334c2f668SLeonid Yegoshin 			if (rvar == 9)
78434c2f668SLeonid Yegoshin 				rvar = 8;
78534c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
78634c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
78734c2f668SLeonid Yegoshin 				if (res)
78834c2f668SLeonid Yegoshin 					goto fault;
78934c2f668SLeonid Yegoshin 				addr += 4;
79034c2f668SLeonid Yegoshin 				regs->regs[i] = value;
79134c2f668SLeonid Yegoshin 			}
79234c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
79334c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
79434c2f668SLeonid Yegoshin 				if (res)
79534c2f668SLeonid Yegoshin 					goto fault;
79634c2f668SLeonid Yegoshin 				addr += 4;
79734c2f668SLeonid Yegoshin 				regs->regs[30] = value;
79834c2f668SLeonid Yegoshin 			}
79934c2f668SLeonid Yegoshin 			if (reg & 0x10) {
80034c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
80134c2f668SLeonid Yegoshin 				if (res)
80234c2f668SLeonid Yegoshin 					goto fault;
80334c2f668SLeonid Yegoshin 				regs->regs[31] = value;
80434c2f668SLeonid Yegoshin 			}
80534c2f668SLeonid Yegoshin 			goto success;
80634c2f668SLeonid Yegoshin 
80734c2f668SLeonid Yegoshin 		case mm_swm32_func:
80834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
80934c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
81034c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
81134c2f668SLeonid Yegoshin 				goto sigill;
81234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
81345deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * (rvar + 1)))
81434c2f668SLeonid Yegoshin 					goto sigbus;
81534c2f668SLeonid Yegoshin 			} else {
81645deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * rvar))
81734c2f668SLeonid Yegoshin 					goto sigbus;
81834c2f668SLeonid Yegoshin 			}
81934c2f668SLeonid Yegoshin 			if (rvar == 9)
82034c2f668SLeonid Yegoshin 				rvar = 8;
82134c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
82234c2f668SLeonid Yegoshin 				value = regs->regs[i];
82334c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
82434c2f668SLeonid Yegoshin 				if (res)
82534c2f668SLeonid Yegoshin 					goto fault;
82634c2f668SLeonid Yegoshin 				addr += 4;
82734c2f668SLeonid Yegoshin 			}
82834c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
82934c2f668SLeonid Yegoshin 				value = regs->regs[30];
83034c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
83134c2f668SLeonid Yegoshin 				if (res)
83234c2f668SLeonid Yegoshin 					goto fault;
83334c2f668SLeonid Yegoshin 				addr += 4;
83434c2f668SLeonid Yegoshin 			}
83534c2f668SLeonid Yegoshin 			if (reg & 0x10) {
83634c2f668SLeonid Yegoshin 				value = regs->regs[31];
83734c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
83834c2f668SLeonid Yegoshin 				if (res)
83934c2f668SLeonid Yegoshin 					goto fault;
84034c2f668SLeonid Yegoshin 			}
84134c2f668SLeonid Yegoshin 			goto success;
84234c2f668SLeonid Yegoshin 
84334c2f668SLeonid Yegoshin 		case mm_ldm_func:
84434c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
84534c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
84634c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
84734c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
84834c2f668SLeonid Yegoshin 				goto sigill;
84934c2f668SLeonid Yegoshin 			if (reg & 0x10) {
85045deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * (rvar + 1)))
85134c2f668SLeonid Yegoshin 					goto sigbus;
85234c2f668SLeonid Yegoshin 			} else {
85345deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * rvar))
85434c2f668SLeonid Yegoshin 					goto sigbus;
85534c2f668SLeonid Yegoshin 			}
85634c2f668SLeonid Yegoshin 			if (rvar == 9)
85734c2f668SLeonid Yegoshin 				rvar = 8;
85834c2f668SLeonid Yegoshin 
85934c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
86034c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
86134c2f668SLeonid Yegoshin 				if (res)
86234c2f668SLeonid Yegoshin 					goto fault;
86334c2f668SLeonid Yegoshin 				addr += 4;
86434c2f668SLeonid Yegoshin 				regs->regs[i] = value;
86534c2f668SLeonid Yegoshin 			}
86634c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
86734c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
86834c2f668SLeonid Yegoshin 				if (res)
86934c2f668SLeonid Yegoshin 					goto fault;
87034c2f668SLeonid Yegoshin 				addr += 8;
87134c2f668SLeonid Yegoshin 				regs->regs[30] = value;
87234c2f668SLeonid Yegoshin 			}
87334c2f668SLeonid Yegoshin 			if (reg & 0x10) {
87434c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
87534c2f668SLeonid Yegoshin 				if (res)
87634c2f668SLeonid Yegoshin 					goto fault;
87734c2f668SLeonid Yegoshin 				regs->regs[31] = value;
87834c2f668SLeonid Yegoshin 			}
87934c2f668SLeonid Yegoshin 			goto success;
88034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
88134c2f668SLeonid Yegoshin 
88234c2f668SLeonid Yegoshin 			goto sigill;
88334c2f668SLeonid Yegoshin 
88434c2f668SLeonid Yegoshin 		case mm_sdm_func:
88534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
88634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
88734c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
88834c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
88934c2f668SLeonid Yegoshin 				goto sigill;
89034c2f668SLeonid Yegoshin 			if (reg & 0x10) {
89145deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * (rvar + 1)))
89234c2f668SLeonid Yegoshin 					goto sigbus;
89334c2f668SLeonid Yegoshin 			} else {
89445deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * rvar))
89534c2f668SLeonid Yegoshin 					goto sigbus;
89634c2f668SLeonid Yegoshin 			}
89734c2f668SLeonid Yegoshin 			if (rvar == 9)
89834c2f668SLeonid Yegoshin 				rvar = 8;
89934c2f668SLeonid Yegoshin 
90034c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
90134c2f668SLeonid Yegoshin 				value = regs->regs[i];
90234c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
90334c2f668SLeonid Yegoshin 				if (res)
90434c2f668SLeonid Yegoshin 					goto fault;
90534c2f668SLeonid Yegoshin 				addr += 8;
90634c2f668SLeonid Yegoshin 			}
90734c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
90834c2f668SLeonid Yegoshin 				value = regs->regs[30];
90934c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
91034c2f668SLeonid Yegoshin 				if (res)
91134c2f668SLeonid Yegoshin 					goto fault;
91234c2f668SLeonid Yegoshin 				addr += 8;
91334c2f668SLeonid Yegoshin 			}
91434c2f668SLeonid Yegoshin 			if (reg & 0x10) {
91534c2f668SLeonid Yegoshin 				value = regs->regs[31];
91634c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
91734c2f668SLeonid Yegoshin 				if (res)
91834c2f668SLeonid Yegoshin 					goto fault;
91934c2f668SLeonid Yegoshin 			}
92034c2f668SLeonid Yegoshin 			goto success;
92134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
92234c2f668SLeonid Yegoshin 
92334c2f668SLeonid Yegoshin 			goto sigill;
92434c2f668SLeonid Yegoshin 
92534c2f668SLeonid Yegoshin 			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
92634c2f668SLeonid Yegoshin 		}
92734c2f668SLeonid Yegoshin 
92834c2f668SLeonid Yegoshin 		goto sigbus;
92934c2f668SLeonid Yegoshin 
93034c2f668SLeonid Yegoshin 	case mm_pool32c_op:
93134c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
93234c2f668SLeonid Yegoshin 		case mm_lwu_func:
93334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
93434c2f668SLeonid Yegoshin 			goto loadWU;
93534c2f668SLeonid Yegoshin 		}
93634c2f668SLeonid Yegoshin 
93734c2f668SLeonid Yegoshin 		/*  LL,SC,LLD,SCD are not serviced */
93834c2f668SLeonid Yegoshin 		goto sigbus;
93934c2f668SLeonid Yegoshin 
94085164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
94134c2f668SLeonid Yegoshin 	case mm_pool32f_op:
94234c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
94334c2f668SLeonid Yegoshin 		case mm_lwxc1_func:
94434c2f668SLeonid Yegoshin 		case mm_swxc1_func:
94534c2f668SLeonid Yegoshin 		case mm_ldxc1_func:
94634c2f668SLeonid Yegoshin 		case mm_sdxc1_func:
94734c2f668SLeonid Yegoshin 			goto fpu_emul;
94834c2f668SLeonid Yegoshin 		}
94934c2f668SLeonid Yegoshin 
95034c2f668SLeonid Yegoshin 		goto sigbus;
95134c2f668SLeonid Yegoshin 
95234c2f668SLeonid Yegoshin 	case mm_ldc132_op:
95334c2f668SLeonid Yegoshin 	case mm_sdc132_op:
95434c2f668SLeonid Yegoshin 	case mm_lwc132_op:
95585164fd8SPaul Burton 	case mm_swc132_op: {
95685164fd8SPaul Burton 		void __user *fault_addr = NULL;
95785164fd8SPaul Burton 
95834c2f668SLeonid Yegoshin fpu_emul:
95934c2f668SLeonid Yegoshin 		/* roll back jump/branch */
96034c2f668SLeonid Yegoshin 		regs->cp0_epc = origpc;
96134c2f668SLeonid Yegoshin 		regs->regs[31] = orig31;
96234c2f668SLeonid Yegoshin 
96334c2f668SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
96434c2f668SLeonid Yegoshin 		BUG_ON(!used_math());
96534c2f668SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
96634c2f668SLeonid Yegoshin 
96734c2f668SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
96834c2f668SLeonid Yegoshin 					       &fault_addr);
96934c2f668SLeonid Yegoshin 		own_fpu(1);	/* restore FPU state */
97034c2f668SLeonid Yegoshin 
97134c2f668SLeonid Yegoshin 		/* If something went wrong, signal */
972304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
97334c2f668SLeonid Yegoshin 
97434c2f668SLeonid Yegoshin 		if (res == 0)
97534c2f668SLeonid Yegoshin 			goto success;
97634c2f668SLeonid Yegoshin 		return;
97785164fd8SPaul Burton 	}
97885164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
97934c2f668SLeonid Yegoshin 
98034c2f668SLeonid Yegoshin 	case mm_lh32_op:
98134c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
98234c2f668SLeonid Yegoshin 		goto loadHW;
98334c2f668SLeonid Yegoshin 
98434c2f668SLeonid Yegoshin 	case mm_lhu32_op:
98534c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
98634c2f668SLeonid Yegoshin 		goto loadHWU;
98734c2f668SLeonid Yegoshin 
98834c2f668SLeonid Yegoshin 	case mm_lw32_op:
98934c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
99034c2f668SLeonid Yegoshin 		goto loadW;
99134c2f668SLeonid Yegoshin 
99234c2f668SLeonid Yegoshin 	case mm_sh32_op:
99334c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
99434c2f668SLeonid Yegoshin 		goto storeHW;
99534c2f668SLeonid Yegoshin 
99634c2f668SLeonid Yegoshin 	case mm_sw32_op:
99734c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
99834c2f668SLeonid Yegoshin 		goto storeW;
99934c2f668SLeonid Yegoshin 
100034c2f668SLeonid Yegoshin 	case mm_ld32_op:
100134c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
100234c2f668SLeonid Yegoshin 		goto loadDW;
100334c2f668SLeonid Yegoshin 
100434c2f668SLeonid Yegoshin 	case mm_sd32_op:
100534c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
100634c2f668SLeonid Yegoshin 		goto storeDW;
100734c2f668SLeonid Yegoshin 
100834c2f668SLeonid Yegoshin 	case mm_pool16c_op:
100934c2f668SLeonid Yegoshin 		switch (insn.mm16_m_format.func) {
101034c2f668SLeonid Yegoshin 		case mm_lwm16_op:
101134c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
101234c2f668SLeonid Yegoshin 			rvar = reg + 1;
101345deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 4 * rvar))
101434c2f668SLeonid Yegoshin 				goto sigbus;
101534c2f668SLeonid Yegoshin 
101634c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
101734c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
101834c2f668SLeonid Yegoshin 				if (res)
101934c2f668SLeonid Yegoshin 					goto fault;
102034c2f668SLeonid Yegoshin 				addr += 4;
102134c2f668SLeonid Yegoshin 				regs->regs[i] = value;
102234c2f668SLeonid Yegoshin 			}
102334c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
102434c2f668SLeonid Yegoshin 			if (res)
102534c2f668SLeonid Yegoshin 				goto fault;
102634c2f668SLeonid Yegoshin 			regs->regs[31] = value;
102734c2f668SLeonid Yegoshin 
102834c2f668SLeonid Yegoshin 			goto success;
102934c2f668SLeonid Yegoshin 
103034c2f668SLeonid Yegoshin 		case mm_swm16_op:
103134c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
103234c2f668SLeonid Yegoshin 			rvar = reg + 1;
103345deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 4 * rvar))
103434c2f668SLeonid Yegoshin 				goto sigbus;
103534c2f668SLeonid Yegoshin 
103634c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
103734c2f668SLeonid Yegoshin 				value = regs->regs[i];
103834c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
103934c2f668SLeonid Yegoshin 				if (res)
104034c2f668SLeonid Yegoshin 					goto fault;
104134c2f668SLeonid Yegoshin 				addr += 4;
104234c2f668SLeonid Yegoshin 			}
104334c2f668SLeonid Yegoshin 			value = regs->regs[31];
104434c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
104534c2f668SLeonid Yegoshin 			if (res)
104634c2f668SLeonid Yegoshin 				goto fault;
104734c2f668SLeonid Yegoshin 
104834c2f668SLeonid Yegoshin 			goto success;
104934c2f668SLeonid Yegoshin 
105034c2f668SLeonid Yegoshin 		}
105134c2f668SLeonid Yegoshin 
105234c2f668SLeonid Yegoshin 		goto sigbus;
105334c2f668SLeonid Yegoshin 
105434c2f668SLeonid Yegoshin 	case mm_lhu16_op:
105534c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
105634c2f668SLeonid Yegoshin 		goto loadHWU;
105734c2f668SLeonid Yegoshin 
105834c2f668SLeonid Yegoshin 	case mm_lw16_op:
105934c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
106034c2f668SLeonid Yegoshin 		goto loadW;
106134c2f668SLeonid Yegoshin 
106234c2f668SLeonid Yegoshin 	case mm_sh16_op:
106334c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
106434c2f668SLeonid Yegoshin 		goto storeHW;
106534c2f668SLeonid Yegoshin 
106634c2f668SLeonid Yegoshin 	case mm_sw16_op:
106734c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
106834c2f668SLeonid Yegoshin 		goto storeW;
106934c2f668SLeonid Yegoshin 
107034c2f668SLeonid Yegoshin 	case mm_lwsp16_op:
107134c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
107234c2f668SLeonid Yegoshin 		goto loadW;
107334c2f668SLeonid Yegoshin 
107434c2f668SLeonid Yegoshin 	case mm_swsp16_op:
107534c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
107634c2f668SLeonid Yegoshin 		goto storeW;
107734c2f668SLeonid Yegoshin 
107834c2f668SLeonid Yegoshin 	case mm_lwgp16_op:
107934c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_r3_format.rt];
108034c2f668SLeonid Yegoshin 		goto loadW;
108134c2f668SLeonid Yegoshin 
108234c2f668SLeonid Yegoshin 	default:
108334c2f668SLeonid Yegoshin 		goto sigill;
108434c2f668SLeonid Yegoshin 	}
108534c2f668SLeonid Yegoshin 
108634c2f668SLeonid Yegoshin loadHW:
108745deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
108834c2f668SLeonid Yegoshin 		goto sigbus;
108934c2f668SLeonid Yegoshin 
109034c2f668SLeonid Yegoshin 	LoadHW(addr, value, res);
109134c2f668SLeonid Yegoshin 	if (res)
109234c2f668SLeonid Yegoshin 		goto fault;
109334c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
109434c2f668SLeonid Yegoshin 	goto success;
109534c2f668SLeonid Yegoshin 
109634c2f668SLeonid Yegoshin loadHWU:
109745deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
109834c2f668SLeonid Yegoshin 		goto sigbus;
109934c2f668SLeonid Yegoshin 
110034c2f668SLeonid Yegoshin 	LoadHWU(addr, value, res);
110134c2f668SLeonid Yegoshin 	if (res)
110234c2f668SLeonid Yegoshin 		goto fault;
110334c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
110434c2f668SLeonid Yegoshin 	goto success;
110534c2f668SLeonid Yegoshin 
110634c2f668SLeonid Yegoshin loadW:
110745deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
110834c2f668SLeonid Yegoshin 		goto sigbus;
110934c2f668SLeonid Yegoshin 
111034c2f668SLeonid Yegoshin 	LoadW(addr, value, res);
111134c2f668SLeonid Yegoshin 	if (res)
111234c2f668SLeonid Yegoshin 		goto fault;
111334c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
111434c2f668SLeonid Yegoshin 	goto success;
111534c2f668SLeonid Yegoshin 
111634c2f668SLeonid Yegoshin loadWU:
111734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
111834c2f668SLeonid Yegoshin 	/*
111934c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
112034c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
112134c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
112234c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
112334c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
112434c2f668SLeonid Yegoshin 	 */
112545deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
112634c2f668SLeonid Yegoshin 		goto sigbus;
112734c2f668SLeonid Yegoshin 
112834c2f668SLeonid Yegoshin 	LoadWU(addr, value, res);
112934c2f668SLeonid Yegoshin 	if (res)
113034c2f668SLeonid Yegoshin 		goto fault;
113134c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
113234c2f668SLeonid Yegoshin 	goto success;
113334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
113434c2f668SLeonid Yegoshin 
113534c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
113634c2f668SLeonid Yegoshin 	goto sigill;
113734c2f668SLeonid Yegoshin 
113834c2f668SLeonid Yegoshin loadDW:
113934c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
114034c2f668SLeonid Yegoshin 	/*
114134c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
114234c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
114334c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
114434c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
114534c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
114634c2f668SLeonid Yegoshin 	 */
114745deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 8))
114834c2f668SLeonid Yegoshin 		goto sigbus;
114934c2f668SLeonid Yegoshin 
115034c2f668SLeonid Yegoshin 	LoadDW(addr, value, res);
115134c2f668SLeonid Yegoshin 	if (res)
115234c2f668SLeonid Yegoshin 		goto fault;
115334c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
115434c2f668SLeonid Yegoshin 	goto success;
115534c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
115634c2f668SLeonid Yegoshin 
115734c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
115834c2f668SLeonid Yegoshin 	goto sigill;
115934c2f668SLeonid Yegoshin 
116034c2f668SLeonid Yegoshin storeHW:
116145deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
116234c2f668SLeonid Yegoshin 		goto sigbus;
116334c2f668SLeonid Yegoshin 
116434c2f668SLeonid Yegoshin 	value = regs->regs[reg];
116534c2f668SLeonid Yegoshin 	StoreHW(addr, value, res);
116634c2f668SLeonid Yegoshin 	if (res)
116734c2f668SLeonid Yegoshin 		goto fault;
116834c2f668SLeonid Yegoshin 	goto success;
116934c2f668SLeonid Yegoshin 
117034c2f668SLeonid Yegoshin storeW:
117145deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
117234c2f668SLeonid Yegoshin 		goto sigbus;
117334c2f668SLeonid Yegoshin 
117434c2f668SLeonid Yegoshin 	value = regs->regs[reg];
117534c2f668SLeonid Yegoshin 	StoreW(addr, value, res);
117634c2f668SLeonid Yegoshin 	if (res)
117734c2f668SLeonid Yegoshin 		goto fault;
117834c2f668SLeonid Yegoshin 	goto success;
117934c2f668SLeonid Yegoshin 
118034c2f668SLeonid Yegoshin storeDW:
118134c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
118234c2f668SLeonid Yegoshin 	/*
118334c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
118434c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
118534c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
118634c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
118734c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
118834c2f668SLeonid Yegoshin 	 */
118945deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 8))
119034c2f668SLeonid Yegoshin 		goto sigbus;
119134c2f668SLeonid Yegoshin 
119234c2f668SLeonid Yegoshin 	value = regs->regs[reg];
119334c2f668SLeonid Yegoshin 	StoreDW(addr, value, res);
119434c2f668SLeonid Yegoshin 	if (res)
119534c2f668SLeonid Yegoshin 		goto fault;
119634c2f668SLeonid Yegoshin 	goto success;
119734c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
119834c2f668SLeonid Yegoshin 
119934c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
120034c2f668SLeonid Yegoshin 	goto sigill;
120134c2f668SLeonid Yegoshin 
120234c2f668SLeonid Yegoshin success:
120334c2f668SLeonid Yegoshin 	regs->cp0_epc = contpc;	/* advance or branch */
120434c2f668SLeonid Yegoshin 
120534c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
120634c2f668SLeonid Yegoshin 	unaligned_instructions++;
120734c2f668SLeonid Yegoshin #endif
120834c2f668SLeonid Yegoshin 	return;
120934c2f668SLeonid Yegoshin 
121034c2f668SLeonid Yegoshin fault:
121134c2f668SLeonid Yegoshin 	/* roll back jump/branch */
121234c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
121334c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
121434c2f668SLeonid Yegoshin 	/* Did we have an exception handler installed? */
121534c2f668SLeonid Yegoshin 	if (fixup_exception(regs))
121634c2f668SLeonid Yegoshin 		return;
121734c2f668SLeonid Yegoshin 
121834c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
12193cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
122034c2f668SLeonid Yegoshin 
122134c2f668SLeonid Yegoshin 	return;
122234c2f668SLeonid Yegoshin 
122334c2f668SLeonid Yegoshin sigbus:
122434c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
12253cf5d076SEric W. Biederman 	force_sig(SIGBUS);
122634c2f668SLeonid Yegoshin 
122734c2f668SLeonid Yegoshin 	return;
122834c2f668SLeonid Yegoshin 
122934c2f668SLeonid Yegoshin sigill:
123034c2f668SLeonid Yegoshin 	die_if_kernel
123134c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
12323cf5d076SEric W. Biederman 	force_sig(SIGILL);
12331da177e4SLinus Torvalds }
12341da177e4SLinus Torvalds 
emulate_load_store_MIPS16e(struct pt_regs * regs,void __user * addr)1235451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1236451b001bSSteven J. Hill {
1237451b001bSSteven J. Hill 	unsigned long value;
1238451b001bSSteven J. Hill 	unsigned int res;
1239451b001bSSteven J. Hill 	int reg;
1240451b001bSSteven J. Hill 	unsigned long orig31;
1241451b001bSSteven J. Hill 	u16 __user *pc16;
1242451b001bSSteven J. Hill 	unsigned long origpc;
1243451b001bSSteven J. Hill 	union mips16e_instruction mips16inst, oldinst;
1244f3235d32SMaciej W. Rozycki 	unsigned int opcode;
1245f3235d32SMaciej W. Rozycki 	int extended = 0;
124645deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
1247451b001bSSteven J. Hill 
1248451b001bSSteven J. Hill 	origpc = regs->cp0_epc;
1249451b001bSSteven J. Hill 	orig31 = regs->regs[31];
1250451b001bSSteven J. Hill 	pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1251451b001bSSteven J. Hill 	/*
1252451b001bSSteven J. Hill 	 * This load never faults.
1253451b001bSSteven J. Hill 	 */
1254451b001bSSteven J. Hill 	__get_user(mips16inst.full, pc16);
1255451b001bSSteven J. Hill 	oldinst = mips16inst;
1256451b001bSSteven J. Hill 
1257451b001bSSteven J. Hill 	/* skip EXTEND instruction */
1258451b001bSSteven J. Hill 	if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1259f3235d32SMaciej W. Rozycki 		extended = 1;
1260451b001bSSteven J. Hill 		pc16++;
1261451b001bSSteven J. Hill 		__get_user(mips16inst.full, pc16);
1262451b001bSSteven J. Hill 	} else if (delay_slot(regs)) {
1263451b001bSSteven J. Hill 		/*  skip jump instructions */
1264451b001bSSteven J. Hill 		/*  JAL/JALX are 32 bits but have OPCODE in first short int */
1265451b001bSSteven J. Hill 		if (mips16inst.ri.opcode == MIPS16e_jal_op)
1266451b001bSSteven J. Hill 			pc16++;
1267451b001bSSteven J. Hill 		pc16++;
1268451b001bSSteven J. Hill 		if (get_user(mips16inst.full, pc16))
1269451b001bSSteven J. Hill 			goto sigbus;
1270451b001bSSteven J. Hill 	}
1271451b001bSSteven J. Hill 
1272f3235d32SMaciej W. Rozycki 	opcode = mips16inst.ri.opcode;
1273f3235d32SMaciej W. Rozycki 	switch (opcode) {
1274451b001bSSteven J. Hill 	case MIPS16e_i64_op:	/* I64 or RI64 instruction */
1275451b001bSSteven J. Hill 		switch (mips16inst.i64.func) {	/* I64/RI64 func field check */
1276451b001bSSteven J. Hill 		case MIPS16e_ldpc_func:
1277451b001bSSteven J. Hill 		case MIPS16e_ldsp_func:
1278451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1279451b001bSSteven J. Hill 			goto loadDW;
1280451b001bSSteven J. Hill 
1281451b001bSSteven J. Hill 		case MIPS16e_sdsp_func:
1282451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1283451b001bSSteven J. Hill 			goto writeDW;
1284451b001bSSteven J. Hill 
1285451b001bSSteven J. Hill 		case MIPS16e_sdrasp_func:
1286451b001bSSteven J. Hill 			reg = 29;	/* GPRSP */
1287451b001bSSteven J. Hill 			goto writeDW;
1288451b001bSSteven J. Hill 		}
1289451b001bSSteven J. Hill 
1290451b001bSSteven J. Hill 		goto sigbus;
1291451b001bSSteven J. Hill 
1292451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1293f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
1294f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
1295f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
1296f3235d32SMaciej W. Rozycki 			case 0:		/* SWSP */
1297f3235d32SMaciej W. Rozycki 			case 1:		/* SWGP */
1298f3235d32SMaciej W. Rozycki 				break;
1299f3235d32SMaciej W. Rozycki 			case 2:		/* SHGP */
1300f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_sh_op;
1301f3235d32SMaciej W. Rozycki 				break;
1302f3235d32SMaciej W. Rozycki 			default:
1303f3235d32SMaciej W. Rozycki 				goto sigbus;
1304f3235d32SMaciej W. Rozycki 			}
1305f3235d32SMaciej W. Rozycki 		break;
1306f3235d32SMaciej W. Rozycki 
1307451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1308f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
1309f3235d32SMaciej W. Rozycki 		break;
1310f3235d32SMaciej W. Rozycki 
1311451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1312451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.ri.rx];
1313f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
1314f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
1315f3235d32SMaciej W. Rozycki 			case 0:		/* LWSP */
1316f3235d32SMaciej W. Rozycki 			case 1:		/* LWGP */
1317f3235d32SMaciej W. Rozycki 				break;
1318f3235d32SMaciej W. Rozycki 			case 2:		/* LHGP */
1319f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lh_op;
1320f3235d32SMaciej W. Rozycki 				break;
1321f3235d32SMaciej W. Rozycki 			case 4:		/* LHUGP */
1322f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lhu_op;
1323f3235d32SMaciej W. Rozycki 				break;
1324f3235d32SMaciej W. Rozycki 			default:
1325f3235d32SMaciej W. Rozycki 				goto sigbus;
1326f3235d32SMaciej W. Rozycki 			}
1327451b001bSSteven J. Hill 		break;
1328451b001bSSteven J. Hill 
1329451b001bSSteven J. Hill 	case MIPS16e_i8_op:
1330451b001bSSteven J. Hill 		if (mips16inst.i8.func != MIPS16e_swrasp_func)
1331451b001bSSteven J. Hill 			goto sigbus;
1332451b001bSSteven J. Hill 		reg = 29;	/* GPRSP */
1333451b001bSSteven J. Hill 		break;
1334451b001bSSteven J. Hill 
1335451b001bSSteven J. Hill 	default:
1336451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.rri.ry];
1337451b001bSSteven J. Hill 		break;
1338451b001bSSteven J. Hill 	}
1339451b001bSSteven J. Hill 
1340f3235d32SMaciej W. Rozycki 	switch (opcode) {
1341451b001bSSteven J. Hill 
1342451b001bSSteven J. Hill 	case MIPS16e_lb_op:
1343451b001bSSteven J. Hill 	case MIPS16e_lbu_op:
1344451b001bSSteven J. Hill 	case MIPS16e_sb_op:
1345451b001bSSteven J. Hill 		goto sigbus;
1346451b001bSSteven J. Hill 
1347451b001bSSteven J. Hill 	case MIPS16e_lh_op:
134845deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1349451b001bSSteven J. Hill 			goto sigbus;
1350451b001bSSteven J. Hill 
1351451b001bSSteven J. Hill 		LoadHW(addr, value, res);
1352451b001bSSteven J. Hill 		if (res)
1353451b001bSSteven J. Hill 			goto fault;
1354451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1355451b001bSSteven J. Hill 		regs->regs[reg] = value;
1356451b001bSSteven J. Hill 		break;
1357451b001bSSteven J. Hill 
1358451b001bSSteven J. Hill 	case MIPS16e_lhu_op:
135945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1360451b001bSSteven J. Hill 			goto sigbus;
1361451b001bSSteven J. Hill 
1362451b001bSSteven J. Hill 		LoadHWU(addr, value, res);
1363451b001bSSteven J. Hill 		if (res)
1364451b001bSSteven J. Hill 			goto fault;
1365451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1366451b001bSSteven J. Hill 		regs->regs[reg] = value;
1367451b001bSSteven J. Hill 		break;
1368451b001bSSteven J. Hill 
1369451b001bSSteven J. Hill 	case MIPS16e_lw_op:
1370451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1371451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
137245deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1373451b001bSSteven J. Hill 			goto sigbus;
1374451b001bSSteven J. Hill 
1375451b001bSSteven J. Hill 		LoadW(addr, value, res);
1376451b001bSSteven J. Hill 		if (res)
1377451b001bSSteven J. Hill 			goto fault;
1378451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1379451b001bSSteven J. Hill 		regs->regs[reg] = value;
1380451b001bSSteven J. Hill 		break;
1381451b001bSSteven J. Hill 
1382451b001bSSteven J. Hill 	case MIPS16e_lwu_op:
1383451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1384451b001bSSteven J. Hill 		/*
1385451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1386451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1387451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1388451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1389451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1390451b001bSSteven J. Hill 		 */
139145deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1392451b001bSSteven J. Hill 			goto sigbus;
1393451b001bSSteven J. Hill 
1394451b001bSSteven J. Hill 		LoadWU(addr, value, res);
1395451b001bSSteven J. Hill 		if (res)
1396451b001bSSteven J. Hill 			goto fault;
1397451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1398451b001bSSteven J. Hill 		regs->regs[reg] = value;
1399451b001bSSteven J. Hill 		break;
1400451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1401451b001bSSteven J. Hill 
1402451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1403451b001bSSteven J. Hill 		goto sigill;
1404451b001bSSteven J. Hill 
1405451b001bSSteven J. Hill 	case MIPS16e_ld_op:
1406451b001bSSteven J. Hill loadDW:
1407451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1408451b001bSSteven J. Hill 		/*
1409451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1410451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1411451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1412451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1413451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1414451b001bSSteven J. Hill 		 */
141545deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
1416451b001bSSteven J. Hill 			goto sigbus;
1417451b001bSSteven J. Hill 
1418451b001bSSteven J. Hill 		LoadDW(addr, value, res);
1419451b001bSSteven J. Hill 		if (res)
1420451b001bSSteven J. Hill 			goto fault;
1421451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1422451b001bSSteven J. Hill 		regs->regs[reg] = value;
1423451b001bSSteven J. Hill 		break;
1424451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1425451b001bSSteven J. Hill 
1426451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1427451b001bSSteven J. Hill 		goto sigill;
1428451b001bSSteven J. Hill 
1429451b001bSSteven J. Hill 	case MIPS16e_sh_op:
143045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1431451b001bSSteven J. Hill 			goto sigbus;
1432451b001bSSteven J. Hill 
1433451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1434451b001bSSteven J. Hill 		value = regs->regs[reg];
1435451b001bSSteven J. Hill 		StoreHW(addr, value, res);
1436451b001bSSteven J. Hill 		if (res)
1437451b001bSSteven J. Hill 			goto fault;
1438451b001bSSteven J. Hill 		break;
1439451b001bSSteven J. Hill 
1440451b001bSSteven J. Hill 	case MIPS16e_sw_op:
1441451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1442451b001bSSteven J. Hill 	case MIPS16e_i8_op:	/* actually - MIPS16e_swrasp_func */
144345deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1444451b001bSSteven J. Hill 			goto sigbus;
1445451b001bSSteven J. Hill 
1446451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1447451b001bSSteven J. Hill 		value = regs->regs[reg];
1448451b001bSSteven J. Hill 		StoreW(addr, value, res);
1449451b001bSSteven J. Hill 		if (res)
1450451b001bSSteven J. Hill 			goto fault;
1451451b001bSSteven J. Hill 		break;
1452451b001bSSteven J. Hill 
1453451b001bSSteven J. Hill 	case MIPS16e_sd_op:
1454451b001bSSteven J. Hill writeDW:
1455451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1456451b001bSSteven J. Hill 		/*
1457451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1458451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1459451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1460451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1461451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1462451b001bSSteven J. Hill 		 */
146345deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
1464451b001bSSteven J. Hill 			goto sigbus;
1465451b001bSSteven J. Hill 
1466451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1467451b001bSSteven J. Hill 		value = regs->regs[reg];
1468451b001bSSteven J. Hill 		StoreDW(addr, value, res);
1469451b001bSSteven J. Hill 		if (res)
1470451b001bSSteven J. Hill 			goto fault;
1471451b001bSSteven J. Hill 		break;
1472451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1473451b001bSSteven J. Hill 
1474451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1475451b001bSSteven J. Hill 		goto sigill;
1476451b001bSSteven J. Hill 
1477451b001bSSteven J. Hill 	default:
1478451b001bSSteven J. Hill 		/*
1479451b001bSSteven J. Hill 		 * Pheeee...  We encountered an yet unknown instruction or
1480451b001bSSteven J. Hill 		 * cache coherence problem.  Die sucker, die ...
1481451b001bSSteven J. Hill 		 */
1482451b001bSSteven J. Hill 		goto sigill;
1483451b001bSSteven J. Hill 	}
1484451b001bSSteven J. Hill 
1485451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
1486451b001bSSteven J. Hill 	unaligned_instructions++;
1487451b001bSSteven J. Hill #endif
1488451b001bSSteven J. Hill 
1489451b001bSSteven J. Hill 	return;
1490451b001bSSteven J. Hill 
1491451b001bSSteven J. Hill fault:
1492451b001bSSteven J. Hill 	/* roll back jump/branch */
1493451b001bSSteven J. Hill 	regs->cp0_epc = origpc;
1494451b001bSSteven J. Hill 	regs->regs[31] = orig31;
1495451b001bSSteven J. Hill 	/* Did we have an exception handler installed? */
1496451b001bSSteven J. Hill 	if (fixup_exception(regs))
1497451b001bSSteven J. Hill 		return;
1498451b001bSSteven J. Hill 
1499451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
15003cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
1501451b001bSSteven J. Hill 
1502451b001bSSteven J. Hill 	return;
1503451b001bSSteven J. Hill 
1504451b001bSSteven J. Hill sigbus:
1505451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
15063cf5d076SEric W. Biederman 	force_sig(SIGBUS);
1507451b001bSSteven J. Hill 
1508451b001bSSteven J. Hill 	return;
1509451b001bSSteven J. Hill 
1510451b001bSSteven J. Hill sigill:
1511451b001bSSteven J. Hill 	die_if_kernel
1512451b001bSSteven J. Hill 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
15133cf5d076SEric W. Biederman 	force_sig(SIGILL);
1514451b001bSSteven J. Hill }
1515fc192e50STony Wu 
do_ade(struct pt_regs * regs)15161da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
15171da177e4SLinus Torvalds {
1518c3fc5cd5SRalf Baechle 	enum ctx_state prev_state;
15197cba4128SThomas Bogendoerfer 	unsigned int *pc;
15201da177e4SLinus Torvalds 
1521c3fc5cd5SRalf Baechle 	prev_state = exception_enter();
15227f788d2dSDeng-Cheng Zhu 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1523a8b0ca17SPeter Zijlstra 			1, regs, regs->cp0_badvaddr);
1524429124d9SThomas Bogendoerfer 
1525429124d9SThomas Bogendoerfer #ifdef CONFIG_64BIT
1526429124d9SThomas Bogendoerfer 	/*
1527429124d9SThomas Bogendoerfer 	 * check, if we are hitting space between CPU implemented maximum
1528429124d9SThomas Bogendoerfer 	 * virtual user address and 64bit maximum virtual user address
1529429124d9SThomas Bogendoerfer 	 * and do exception handling to get EFAULTs for get_user/put_user
1530429124d9SThomas Bogendoerfer 	 */
1531429124d9SThomas Bogendoerfer 	if ((regs->cp0_badvaddr >= (1UL << cpu_vmbits)) &&
1532429124d9SThomas Bogendoerfer 	    (regs->cp0_badvaddr < XKSSEG)) {
1533429124d9SThomas Bogendoerfer 		if (fixup_exception(regs)) {
1534429124d9SThomas Bogendoerfer 			current->thread.cp0_baduaddr = regs->cp0_badvaddr;
1535429124d9SThomas Bogendoerfer 			return;
1536429124d9SThomas Bogendoerfer 		}
1537429124d9SThomas Bogendoerfer 		goto sigbus;
1538429124d9SThomas Bogendoerfer 	}
1539429124d9SThomas Bogendoerfer #endif
1540429124d9SThomas Bogendoerfer 
15411da177e4SLinus Torvalds 	/*
15421da177e4SLinus Torvalds 	 * Did we catch a fault trying to load an instruction?
15431da177e4SLinus Torvalds 	 */
154434c2f668SLeonid Yegoshin 	if (regs->cp0_badvaddr == regs->cp0_epc)
15451da177e4SLinus Torvalds 		goto sigbus;
15461da177e4SLinus Torvalds 
1547293c5bd1SRalf Baechle 	if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
15481da177e4SLinus Torvalds 		goto sigbus;
15496312e0eeSAtsushi Nemoto 	if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
15506312e0eeSAtsushi Nemoto 		goto sigbus;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 	/*
15531da177e4SLinus Torvalds 	 * Do branch emulation only if we didn't forward the exception.
15541da177e4SLinus Torvalds 	 * This is all so but ugly ...
15551da177e4SLinus Torvalds 	 */
155634c2f668SLeonid Yegoshin 
155734c2f668SLeonid Yegoshin 	/*
155834c2f668SLeonid Yegoshin 	 * Are we running in microMIPS mode?
155934c2f668SLeonid Yegoshin 	 */
156034c2f668SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
156134c2f668SLeonid Yegoshin 		/*
156234c2f668SLeonid Yegoshin 		 * Did we catch a fault trying to load an instruction in
156334c2f668SLeonid Yegoshin 		 * 16-bit mode?
156434c2f668SLeonid Yegoshin 		 */
156534c2f668SLeonid Yegoshin 		if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
156634c2f668SLeonid Yegoshin 			goto sigbus;
156734c2f668SLeonid Yegoshin 		if (unaligned_action == UNALIGNED_ACTION_SHOW)
156834c2f668SLeonid Yegoshin 			show_registers(regs);
156934c2f668SLeonid Yegoshin 
157034c2f668SLeonid Yegoshin 		if (cpu_has_mmips) {
157134c2f668SLeonid Yegoshin 			emulate_load_store_microMIPS(regs,
157234c2f668SLeonid Yegoshin 				(void __user *)regs->cp0_badvaddr);
157334c2f668SLeonid Yegoshin 			return;
157434c2f668SLeonid Yegoshin 		}
157534c2f668SLeonid Yegoshin 
1576451b001bSSteven J. Hill 		if (cpu_has_mips16) {
1577451b001bSSteven J. Hill 			emulate_load_store_MIPS16e(regs,
1578451b001bSSteven J. Hill 				(void __user *)regs->cp0_badvaddr);
1579451b001bSSteven J. Hill 			return;
1580451b001bSSteven J. Hill 		}
1581451b001bSSteven J. Hill 
158234c2f668SLeonid Yegoshin 		goto sigbus;
158334c2f668SLeonid Yegoshin 	}
158434c2f668SLeonid Yegoshin 
158534c2f668SLeonid Yegoshin 	if (unaligned_action == UNALIGNED_ACTION_SHOW)
158634c2f668SLeonid Yegoshin 		show_registers(regs);
15877cba4128SThomas Bogendoerfer 	pc = (unsigned int *)exception_epc(regs);
158834c2f668SLeonid Yegoshin 
15897f18f151SRalf Baechle 	emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
15901da177e4SLinus Torvalds 
15911da177e4SLinus Torvalds 	return;
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds sigbus:
15941da177e4SLinus Torvalds 	die_if_kernel("Kernel unaligned instruction access", regs);
15953cf5d076SEric W. Biederman 	force_sig(SIGBUS);
15961da177e4SLinus Torvalds 
15971da177e4SLinus Torvalds 	/*
15981da177e4SLinus Torvalds 	 * XXX On return from the signal handler we should advance the epc
15991da177e4SLinus Torvalds 	 */
1600c3fc5cd5SRalf Baechle 	exception_exit(prev_state);
16011da177e4SLinus Torvalds }
16026312e0eeSAtsushi Nemoto 
16036312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
debugfs_unaligned(void)16046312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
16056312e0eeSAtsushi Nemoto {
1606d8140426SGreg Kroah-Hartman 	debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir,
1607d8140426SGreg Kroah-Hartman 			   &unaligned_instructions);
1608d8140426SGreg Kroah-Hartman 	debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
16096312e0eeSAtsushi Nemoto 			   mips_debugfs_dir, &unaligned_action);
16106312e0eeSAtsushi Nemoto 	return 0;
16116312e0eeSAtsushi Nemoto }
16128d6b591cSRalf Baechle arch_initcall(debugfs_unaligned);
16136312e0eeSAtsushi Nemoto #endif
1614