xref: /openbmc/linux/arch/mips/kernel/unaligned.c (revision 429124d9)
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 
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 		 */
163c1771216SLeonid Yegoshin 	case spec3_op:
1643f88ec63SMiodrag Dinic 		if (insn.dsp_format.func == lx_op) {
1653f88ec63SMiodrag Dinic 			switch (insn.dsp_format.op) {
1663f88ec63SMiodrag Dinic 			case lwx_op:
16745deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4))
1683f88ec63SMiodrag Dinic 					goto sigbus;
1693f88ec63SMiodrag Dinic 				LoadW(addr, value, res);
1703f88ec63SMiodrag Dinic 				if (res)
1713f88ec63SMiodrag Dinic 					goto fault;
1723f88ec63SMiodrag Dinic 				compute_return_epc(regs);
1733f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
1743f88ec63SMiodrag Dinic 				break;
1753f88ec63SMiodrag Dinic 			case lhx_op:
17645deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 2))
1773f88ec63SMiodrag Dinic 					goto sigbus;
1783f88ec63SMiodrag Dinic 				LoadHW(addr, value, res);
1793f88ec63SMiodrag Dinic 				if (res)
1803f88ec63SMiodrag Dinic 					goto fault;
1813f88ec63SMiodrag Dinic 				compute_return_epc(regs);
1823f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
1833f88ec63SMiodrag Dinic 				break;
1843f88ec63SMiodrag Dinic 			default:
1853f88ec63SMiodrag Dinic 				goto sigill;
1863f88ec63SMiodrag Dinic 			}
1873f88ec63SMiodrag Dinic 		}
1883f88ec63SMiodrag Dinic #ifdef CONFIG_EVA
1893f88ec63SMiodrag Dinic 		else {
190c1771216SLeonid Yegoshin 			/*
1913f88ec63SMiodrag Dinic 			 * we can land here only from kernel accessing user
1923f88ec63SMiodrag Dinic 			 * memory, so we need to "switch" the address limit to
1933f88ec63SMiodrag Dinic 			 * user space, so that address check can work properly.
194c1771216SLeonid Yegoshin 			 */
195c1771216SLeonid Yegoshin 			switch (insn.spec3_format.func) {
196c1771216SLeonid Yegoshin 			case lhe_op:
19745deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
198c1771216SLeonid Yegoshin 					goto sigbus;
199eeb53895SMarkos Chandras 				LoadHWE(addr, value, res);
20045deb5faSThomas Bogendoerfer 				if (res)
201c1771216SLeonid Yegoshin 					goto fault;
202c1771216SLeonid Yegoshin 				compute_return_epc(regs);
203c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
204c1771216SLeonid Yegoshin 				break;
205c1771216SLeonid Yegoshin 			case lwe_op:
20645deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 4))
207c1771216SLeonid Yegoshin 					goto sigbus;
208eeb53895SMarkos Chandras 				LoadWE(addr, value, res);
20945deb5faSThomas Bogendoerfer 				if (res)
210c1771216SLeonid Yegoshin 					goto fault;
211c1771216SLeonid Yegoshin 				compute_return_epc(regs);
212c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
213c1771216SLeonid Yegoshin 				break;
214c1771216SLeonid Yegoshin 			case lhue_op:
21545deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
216c1771216SLeonid Yegoshin 					goto sigbus;
217eeb53895SMarkos Chandras 				LoadHWUE(addr, value, res);
21845deb5faSThomas Bogendoerfer 				if (res)
219c1771216SLeonid Yegoshin 					goto fault;
220c1771216SLeonid Yegoshin 				compute_return_epc(regs);
221c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
222c1771216SLeonid Yegoshin 				break;
223c1771216SLeonid Yegoshin 			case she_op:
22445deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
225c1771216SLeonid Yegoshin 					goto sigbus;
226c1771216SLeonid Yegoshin 				compute_return_epc(regs);
227c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
228eeb53895SMarkos Chandras 				StoreHWE(addr, value, res);
22945deb5faSThomas Bogendoerfer 				if (res)
230c1771216SLeonid Yegoshin 					goto fault;
231c1771216SLeonid Yegoshin 				break;
232c1771216SLeonid Yegoshin 			case swe_op:
23345deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 4))
234c1771216SLeonid Yegoshin 					goto sigbus;
235c1771216SLeonid Yegoshin 				compute_return_epc(regs);
236c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
237eeb53895SMarkos Chandras 				StoreWE(addr, value, res);
23845deb5faSThomas Bogendoerfer 				if (res)
239c1771216SLeonid Yegoshin 					goto fault;
240c1771216SLeonid Yegoshin 				break;
241c1771216SLeonid Yegoshin 			default:
242c1771216SLeonid Yegoshin 				goto sigill;
243c1771216SLeonid Yegoshin 			}
2443f88ec63SMiodrag Dinic 		}
245c1771216SLeonid Yegoshin #endif
2463f88ec63SMiodrag Dinic 		break;
2471da177e4SLinus Torvalds 	case lh_op:
24845deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
2491da177e4SLinus Torvalds 			goto sigbus;
2501da177e4SLinus Torvalds 
25145deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
2526eae3548SMarkos Chandras 			LoadHWE(addr, value, res);
25345deb5faSThomas Bogendoerfer 		else
2546eae3548SMarkos Chandras 			LoadHW(addr, value, res);
2556eae3548SMarkos Chandras 
2561da177e4SLinus Torvalds 		if (res)
2571da177e4SLinus Torvalds 			goto fault;
2587f18f151SRalf Baechle 		compute_return_epc(regs);
2597f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
2601da177e4SLinus Torvalds 		break;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	case lw_op:
26345deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
2641da177e4SLinus Torvalds 			goto sigbus;
2651da177e4SLinus Torvalds 
26645deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
2676eae3548SMarkos Chandras 			LoadWE(addr, value, res);
26845deb5faSThomas Bogendoerfer 		else
2696eae3548SMarkos Chandras 			LoadW(addr, value, res);
2706eae3548SMarkos Chandras 
2711da177e4SLinus Torvalds 		if (res)
2721da177e4SLinus Torvalds 			goto fault;
2737f18f151SRalf Baechle 		compute_return_epc(regs);
2747f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
2751da177e4SLinus Torvalds 		break;
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	case lhu_op:
27845deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
2791da177e4SLinus Torvalds 			goto sigbus;
2801da177e4SLinus Torvalds 
28145deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
2826eae3548SMarkos Chandras 			LoadHWUE(addr, value, res);
28345deb5faSThomas Bogendoerfer 		else
2846eae3548SMarkos Chandras 			LoadHWU(addr, value, res);
2856eae3548SMarkos Chandras 
2861da177e4SLinus Torvalds 		if (res)
2871da177e4SLinus Torvalds 			goto fault;
2887f18f151SRalf Baechle 		compute_return_epc(regs);
2897f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
2901da177e4SLinus Torvalds 		break;
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 	case lwu_op:
293875d43e7SRalf Baechle #ifdef CONFIG_64BIT
2941da177e4SLinus Torvalds 		/*
2951da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
2961da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
2971da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
2981da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
2991da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3001da177e4SLinus Torvalds 		 */
30145deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3021da177e4SLinus Torvalds 			goto sigbus;
3031da177e4SLinus Torvalds 
30434c2f668SLeonid Yegoshin 		LoadWU(addr, value, res);
3051da177e4SLinus Torvalds 		if (res)
3061da177e4SLinus Torvalds 			goto fault;
3077f18f151SRalf Baechle 		compute_return_epc(regs);
3087f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3091da177e4SLinus Torvalds 		break;
310875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3131da177e4SLinus Torvalds 		goto sigill;
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	case ld_op:
316875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3171da177e4SLinus Torvalds 		/*
3181da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
3191da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
3201da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
3211da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
3221da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3231da177e4SLinus Torvalds 		 */
32445deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
3251da177e4SLinus Torvalds 			goto sigbus;
3261da177e4SLinus Torvalds 
32734c2f668SLeonid Yegoshin 		LoadDW(addr, value, res);
3281da177e4SLinus Torvalds 		if (res)
3291da177e4SLinus Torvalds 			goto fault;
3307f18f151SRalf Baechle 		compute_return_epc(regs);
3317f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3321da177e4SLinus Torvalds 		break;
333875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3361da177e4SLinus Torvalds 		goto sigill;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	case sh_op:
33945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
3401da177e4SLinus Torvalds 			goto sigbus;
3411da177e4SLinus Torvalds 
34234c2f668SLeonid Yegoshin 		compute_return_epc(regs);
3431da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
3446eae3548SMarkos Chandras 
34545deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3466eae3548SMarkos Chandras 			StoreHWE(addr, value, res);
34745deb5faSThomas Bogendoerfer 		else
3486eae3548SMarkos Chandras 			StoreHW(addr, value, res);
3496eae3548SMarkos Chandras 
3501da177e4SLinus Torvalds 		if (res)
3511da177e4SLinus Torvalds 			goto fault;
3521da177e4SLinus Torvalds 		break;
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	case sw_op:
35545deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3561da177e4SLinus Torvalds 			goto sigbus;
3571da177e4SLinus Torvalds 
35834c2f668SLeonid Yegoshin 		compute_return_epc(regs);
3591da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
3606eae3548SMarkos Chandras 
36145deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3626eae3548SMarkos Chandras 			StoreWE(addr, value, res);
36345deb5faSThomas Bogendoerfer 		else
3646eae3548SMarkos Chandras 			StoreW(addr, value, res);
3656eae3548SMarkos Chandras 
3661da177e4SLinus Torvalds 		if (res)
3671da177e4SLinus Torvalds 			goto fault;
3681da177e4SLinus Torvalds 		break;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	case sd_op:
371875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3721da177e4SLinus Torvalds 		/*
3731da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
3741da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
3751da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
3761da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
3771da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3781da177e4SLinus Torvalds 		 */
37945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
3801da177e4SLinus Torvalds 			goto sigbus;
3811da177e4SLinus Torvalds 
38234c2f668SLeonid Yegoshin 		compute_return_epc(regs);
3831da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
38434c2f668SLeonid Yegoshin 		StoreDW(addr, value, res);
3851da177e4SLinus Torvalds 		if (res)
3861da177e4SLinus Torvalds 			goto fault;
3871da177e4SLinus Torvalds 		break;
388875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3911da177e4SLinus Torvalds 		goto sigill;
3921da177e4SLinus Torvalds 
39385164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
39485164fd8SPaul Burton 
3951da177e4SLinus Torvalds 	case lwc1_op:
3961da177e4SLinus Torvalds 	case ldc1_op:
3971da177e4SLinus Torvalds 	case swc1_op:
3981da177e4SLinus Torvalds 	case sdc1_op:
39985164fd8SPaul Burton 	case cop1x_op: {
40085164fd8SPaul Burton 		void __user *fault_addr = NULL;
40185164fd8SPaul Burton 
402102cedc3SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
403102cedc3SLeonid Yegoshin 		BUG_ON(!used_math());
404102cedc3SLeonid Yegoshin 
405102cedc3SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
406102cedc3SLeonid Yegoshin 					       &fault_addr);
407102cedc3SLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
408102cedc3SLeonid Yegoshin 
409102cedc3SLeonid Yegoshin 		/* Signal if something went wrong. */
410304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
411102cedc3SLeonid Yegoshin 
412102cedc3SLeonid Yegoshin 		if (res == 0)
413102cedc3SLeonid Yegoshin 			break;
414102cedc3SLeonid Yegoshin 		return;
41585164fd8SPaul Burton 	}
41685164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
4171da177e4SLinus Torvalds 
41885164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
41985164fd8SPaul Burton 
42085164fd8SPaul Burton 	case msa_op: {
42185164fd8SPaul Burton 		unsigned int wd, preempted;
42285164fd8SPaul Burton 		enum msa_2b_fmt df;
42385164fd8SPaul Burton 		union fpureg *fpr;
42485164fd8SPaul Burton 
425e4aa1f15SLeonid Yegoshin 		if (!cpu_has_msa)
426e4aa1f15SLeonid Yegoshin 			goto sigill;
427e4aa1f15SLeonid Yegoshin 
428e4aa1f15SLeonid Yegoshin 		/*
429e4aa1f15SLeonid Yegoshin 		 * If we've reached this point then userland should have taken
430e4aa1f15SLeonid Yegoshin 		 * the MSA disabled exception & initialised vector context at
431e4aa1f15SLeonid Yegoshin 		 * some point in the past.
432e4aa1f15SLeonid Yegoshin 		 */
433e4aa1f15SLeonid Yegoshin 		BUG_ON(!thread_msa_context_live());
434e4aa1f15SLeonid Yegoshin 
435e4aa1f15SLeonid Yegoshin 		df = insn.msa_mi10_format.df;
436e4aa1f15SLeonid Yegoshin 		wd = insn.msa_mi10_format.wd;
437e4aa1f15SLeonid Yegoshin 		fpr = &current->thread.fpu.fpr[wd];
438e4aa1f15SLeonid Yegoshin 
439e4aa1f15SLeonid Yegoshin 		switch (insn.msa_mi10_format.func) {
440e4aa1f15SLeonid Yegoshin 		case msa_ld_op:
44196d4f267SLinus Torvalds 			if (!access_ok(addr, sizeof(*fpr)))
442e4aa1f15SLeonid Yegoshin 				goto sigbus;
443e4aa1f15SLeonid Yegoshin 
444fa8ff601SPaul Burton 			do {
445e4aa1f15SLeonid Yegoshin 				/*
446fa8ff601SPaul Burton 				 * If we have live MSA context keep track of
447fa8ff601SPaul Burton 				 * whether we get preempted in order to avoid
448fa8ff601SPaul Burton 				 * the register context we load being clobbered
449fa8ff601SPaul Burton 				 * by the live context as it's saved during
450fa8ff601SPaul Burton 				 * preemption. If we don't have live context
451fa8ff601SPaul Burton 				 * then it can't be saved to clobber the value
452fa8ff601SPaul Burton 				 * we load.
453e4aa1f15SLeonid Yegoshin 				 */
454fa8ff601SPaul Burton 				preempted = test_thread_flag(TIF_USEDMSA);
455e4aa1f15SLeonid Yegoshin 
456e4aa1f15SLeonid Yegoshin 				res = __copy_from_user_inatomic(fpr, addr,
457e4aa1f15SLeonid Yegoshin 								sizeof(*fpr));
458e4aa1f15SLeonid Yegoshin 				if (res)
459e4aa1f15SLeonid Yegoshin 					goto fault;
460e4aa1f15SLeonid Yegoshin 
461e4aa1f15SLeonid Yegoshin 				/*
462fa8ff601SPaul Burton 				 * Update the hardware register if it is in use
463fa8ff601SPaul Burton 				 * by the task in this quantum, in order to
464fa8ff601SPaul Burton 				 * avoid having to save & restore the whole
465fa8ff601SPaul Burton 				 * vector context.
466e4aa1f15SLeonid Yegoshin 				 */
467fa8ff601SPaul Burton 				preempt_disable();
468fa8ff601SPaul Burton 				if (test_thread_flag(TIF_USEDMSA)) {
469e4aa1f15SLeonid Yegoshin 					write_msa_wr(wd, fpr, df);
470fa8ff601SPaul Burton 					preempted = 0;
471fa8ff601SPaul Burton 				}
472e4aa1f15SLeonid Yegoshin 				preempt_enable();
473fa8ff601SPaul Burton 			} while (preempted);
474e4aa1f15SLeonid Yegoshin 			break;
475e4aa1f15SLeonid Yegoshin 
476e4aa1f15SLeonid Yegoshin 		case msa_st_op:
47796d4f267SLinus Torvalds 			if (!access_ok(addr, sizeof(*fpr)))
478e4aa1f15SLeonid Yegoshin 				goto sigbus;
479e4aa1f15SLeonid Yegoshin 
480e4aa1f15SLeonid Yegoshin 			/*
481e4aa1f15SLeonid Yegoshin 			 * Update from the hardware register if it is in use by
482e4aa1f15SLeonid Yegoshin 			 * the task in this quantum, in order to avoid having to
483e4aa1f15SLeonid Yegoshin 			 * save & restore the whole vector context.
484e4aa1f15SLeonid Yegoshin 			 */
485e4aa1f15SLeonid Yegoshin 			preempt_disable();
486e4aa1f15SLeonid Yegoshin 			if (test_thread_flag(TIF_USEDMSA))
487e4aa1f15SLeonid Yegoshin 				read_msa_wr(wd, fpr, df);
488e4aa1f15SLeonid Yegoshin 			preempt_enable();
489e4aa1f15SLeonid Yegoshin 
490e4aa1f15SLeonid Yegoshin 			res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr));
491e4aa1f15SLeonid Yegoshin 			if (res)
492e4aa1f15SLeonid Yegoshin 				goto fault;
493e4aa1f15SLeonid Yegoshin 			break;
494e4aa1f15SLeonid Yegoshin 
495e4aa1f15SLeonid Yegoshin 		default:
496e4aa1f15SLeonid Yegoshin 			goto sigbus;
497e4aa1f15SLeonid Yegoshin 		}
498e4aa1f15SLeonid Yegoshin 
499e4aa1f15SLeonid Yegoshin 		compute_return_epc(regs);
500e4aa1f15SLeonid Yegoshin 		break;
50185164fd8SPaul Burton 	}
50285164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */
503e4aa1f15SLeonid Yegoshin 
5040593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
5051da177e4SLinus Torvalds 	/*
50669f3a7deSRalf Baechle 	 * COP2 is available to implementor for application specific use.
50769f3a7deSRalf Baechle 	 * It's up to applications to register a notifier chain and do
50869f3a7deSRalf Baechle 	 * whatever they have to do, including possible sending of signals.
5090593a44cSLeonid Yegoshin 	 *
5100593a44cSLeonid Yegoshin 	 * This instruction has been reallocated in Release 6
5111da177e4SLinus Torvalds 	 */
51269f3a7deSRalf Baechle 	case lwc2_op:
51369f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
51469f3a7deSRalf Baechle 		break;
51569f3a7deSRalf Baechle 
51669f3a7deSRalf Baechle 	case ldc2_op:
51769f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
51869f3a7deSRalf Baechle 		break;
51969f3a7deSRalf Baechle 
52069f3a7deSRalf Baechle 	case swc2_op:
52169f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
52269f3a7deSRalf Baechle 		break;
52369f3a7deSRalf Baechle 
52469f3a7deSRalf Baechle 	case sdc2_op:
52569f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
52669f3a7deSRalf Baechle 		break;
5270593a44cSLeonid Yegoshin #endif
5281da177e4SLinus Torvalds 	default:
5291da177e4SLinus Torvalds 		/*
5301da177e4SLinus Torvalds 		 * Pheeee...  We encountered an yet unknown instruction or
5311da177e4SLinus Torvalds 		 * cache coherence problem.  Die sucker, die ...
5321da177e4SLinus Torvalds 		 */
5331da177e4SLinus Torvalds 		goto sigill;
5341da177e4SLinus Torvalds 	}
5351da177e4SLinus Torvalds 
5366312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
5371da177e4SLinus Torvalds 	unaligned_instructions++;
5381da177e4SLinus Torvalds #endif
5391da177e4SLinus Torvalds 
5407f18f151SRalf Baechle 	return;
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds fault:
54334c2f668SLeonid Yegoshin 	/* roll back jump/branch */
54434c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
54534c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
5461da177e4SLinus Torvalds 	/* Did we have an exception handler installed? */
5471da177e4SLinus Torvalds 	if (fixup_exception(regs))
5487f18f151SRalf Baechle 		return;
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
5513cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
5521da177e4SLinus Torvalds 
5537f18f151SRalf Baechle 	return;
5541da177e4SLinus Torvalds 
5551da177e4SLinus Torvalds sigbus:
5561da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
5573cf5d076SEric W. Biederman 	force_sig(SIGBUS);
5581da177e4SLinus Torvalds 
5597f18f151SRalf Baechle 	return;
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds sigill:
56234c2f668SLeonid Yegoshin 	die_if_kernel
56334c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
5643cf5d076SEric W. Biederman 	force_sig(SIGILL);
56534c2f668SLeonid Yegoshin }
56634c2f668SLeonid Yegoshin 
56734c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
56834c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
56934c2f668SLeonid Yegoshin 
57034c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
571b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
57234c2f668SLeonid Yegoshin 
57374338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
57474338805SDavid Daney 					 void __user *addr)
57534c2f668SLeonid Yegoshin {
57634c2f668SLeonid Yegoshin 	unsigned long value;
57734c2f668SLeonid Yegoshin 	unsigned int res;
57834c2f668SLeonid Yegoshin 	int i;
57934c2f668SLeonid Yegoshin 	unsigned int reg = 0, rvar;
58034c2f668SLeonid Yegoshin 	unsigned long orig31;
58134c2f668SLeonid Yegoshin 	u16 __user *pc16;
58234c2f668SLeonid Yegoshin 	u16 halfword;
58334c2f668SLeonid Yegoshin 	unsigned int word;
58434c2f668SLeonid Yegoshin 	unsigned long origpc, contpc;
58534c2f668SLeonid Yegoshin 	union mips_instruction insn;
58634c2f668SLeonid Yegoshin 	struct mm_decoded_insn mminsn;
58745deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
58834c2f668SLeonid Yegoshin 
58934c2f668SLeonid Yegoshin 	origpc = regs->cp0_epc;
59034c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
59134c2f668SLeonid Yegoshin 
59234c2f668SLeonid Yegoshin 	mminsn.micro_mips_mode = 1;
59334c2f668SLeonid Yegoshin 
59434c2f668SLeonid Yegoshin 	/*
59534c2f668SLeonid Yegoshin 	 * This load never faults.
59634c2f668SLeonid Yegoshin 	 */
59734c2f668SLeonid Yegoshin 	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
59834c2f668SLeonid Yegoshin 	__get_user(halfword, pc16);
59934c2f668SLeonid Yegoshin 	pc16++;
60034c2f668SLeonid Yegoshin 	contpc = regs->cp0_epc + 2;
60134c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
60234c2f668SLeonid Yegoshin 	mminsn.pc_inc = 2;
60334c2f668SLeonid Yegoshin 
60434c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
60534c2f668SLeonid Yegoshin 		__get_user(halfword, pc16);
60634c2f668SLeonid Yegoshin 		pc16++;
60734c2f668SLeonid Yegoshin 		contpc = regs->cp0_epc + 4;
60834c2f668SLeonid Yegoshin 		mminsn.pc_inc = 4;
60934c2f668SLeonid Yegoshin 		word |= halfword;
61034c2f668SLeonid Yegoshin 	}
61134c2f668SLeonid Yegoshin 	mminsn.insn = word;
61234c2f668SLeonid Yegoshin 
61334c2f668SLeonid Yegoshin 	if (get_user(halfword, pc16))
61434c2f668SLeonid Yegoshin 		goto fault;
61534c2f668SLeonid Yegoshin 	mminsn.next_pc_inc = 2;
61634c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
61734c2f668SLeonid Yegoshin 
61834c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
61934c2f668SLeonid Yegoshin 		pc16++;
62034c2f668SLeonid Yegoshin 		if (get_user(halfword, pc16))
62134c2f668SLeonid Yegoshin 			goto fault;
62234c2f668SLeonid Yegoshin 		mminsn.next_pc_inc = 4;
62334c2f668SLeonid Yegoshin 		word |= halfword;
62434c2f668SLeonid Yegoshin 	}
62534c2f668SLeonid Yegoshin 	mminsn.next_insn = word;
62634c2f668SLeonid Yegoshin 
62734c2f668SLeonid Yegoshin 	insn = (union mips_instruction)(mminsn.insn);
62834c2f668SLeonid Yegoshin 	if (mm_isBranchInstr(regs, mminsn, &contpc))
62934c2f668SLeonid Yegoshin 		insn = (union mips_instruction)(mminsn.next_insn);
63034c2f668SLeonid Yegoshin 
63134c2f668SLeonid Yegoshin 	/*  Parse instruction to find what to do */
63234c2f668SLeonid Yegoshin 
63334c2f668SLeonid Yegoshin 	switch (insn.mm_i_format.opcode) {
63434c2f668SLeonid Yegoshin 
63534c2f668SLeonid Yegoshin 	case mm_pool32a_op:
63634c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
63734c2f668SLeonid Yegoshin 		case mm_lwxs_op:
63834c2f668SLeonid Yegoshin 			reg = insn.mm_x_format.rd;
63934c2f668SLeonid Yegoshin 			goto loadW;
64034c2f668SLeonid Yegoshin 		}
64134c2f668SLeonid Yegoshin 
64234c2f668SLeonid Yegoshin 		goto sigbus;
64334c2f668SLeonid Yegoshin 
64434c2f668SLeonid Yegoshin 	case mm_pool32b_op:
64534c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
64634c2f668SLeonid Yegoshin 		case mm_lwp_func:
64734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
64834c2f668SLeonid Yegoshin 			if (reg == 31)
64934c2f668SLeonid Yegoshin 				goto sigbus;
65034c2f668SLeonid Yegoshin 
65145deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 8))
65234c2f668SLeonid Yegoshin 				goto sigbus;
65334c2f668SLeonid Yegoshin 
65434c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
65534c2f668SLeonid Yegoshin 			if (res)
65634c2f668SLeonid Yegoshin 				goto fault;
65734c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
65834c2f668SLeonid Yegoshin 			addr += 4;
65934c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
66034c2f668SLeonid Yegoshin 			if (res)
66134c2f668SLeonid Yegoshin 				goto fault;
66234c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
66334c2f668SLeonid Yegoshin 			goto success;
66434c2f668SLeonid Yegoshin 
66534c2f668SLeonid Yegoshin 		case mm_swp_func:
66634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
66734c2f668SLeonid Yegoshin 			if (reg == 31)
66834c2f668SLeonid Yegoshin 				goto sigbus;
66934c2f668SLeonid Yegoshin 
67045deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 8))
67134c2f668SLeonid Yegoshin 				goto sigbus;
67234c2f668SLeonid Yegoshin 
67334c2f668SLeonid Yegoshin 			value = regs->regs[reg];
67434c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
67534c2f668SLeonid Yegoshin 			if (res)
67634c2f668SLeonid Yegoshin 				goto fault;
67734c2f668SLeonid Yegoshin 			addr += 4;
67834c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
67934c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
68034c2f668SLeonid Yegoshin 			if (res)
68134c2f668SLeonid Yegoshin 				goto fault;
68234c2f668SLeonid Yegoshin 			goto success;
68334c2f668SLeonid Yegoshin 
68434c2f668SLeonid Yegoshin 		case mm_ldp_func:
68534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
68634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
68734c2f668SLeonid Yegoshin 			if (reg == 31)
68834c2f668SLeonid Yegoshin 				goto sigbus;
68934c2f668SLeonid Yegoshin 
69045deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 16))
69134c2f668SLeonid Yegoshin 				goto sigbus;
69234c2f668SLeonid Yegoshin 
69334c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
69434c2f668SLeonid Yegoshin 			if (res)
69534c2f668SLeonid Yegoshin 				goto fault;
69634c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
69734c2f668SLeonid Yegoshin 			addr += 8;
69834c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
69934c2f668SLeonid Yegoshin 			if (res)
70034c2f668SLeonid Yegoshin 				goto fault;
70134c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
70234c2f668SLeonid Yegoshin 			goto success;
70334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
70434c2f668SLeonid Yegoshin 
70534c2f668SLeonid Yegoshin 			goto sigill;
70634c2f668SLeonid Yegoshin 
70734c2f668SLeonid Yegoshin 		case mm_sdp_func:
70834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
70934c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
71034c2f668SLeonid Yegoshin 			if (reg == 31)
71134c2f668SLeonid Yegoshin 				goto sigbus;
71234c2f668SLeonid Yegoshin 
71345deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 16))
71434c2f668SLeonid Yegoshin 				goto sigbus;
71534c2f668SLeonid Yegoshin 
71634c2f668SLeonid Yegoshin 			value = regs->regs[reg];
71734c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
71834c2f668SLeonid Yegoshin 			if (res)
71934c2f668SLeonid Yegoshin 				goto fault;
72034c2f668SLeonid Yegoshin 			addr += 8;
72134c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
72234c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
72334c2f668SLeonid Yegoshin 			if (res)
72434c2f668SLeonid Yegoshin 				goto fault;
72534c2f668SLeonid Yegoshin 			goto success;
72634c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
72734c2f668SLeonid Yegoshin 
72834c2f668SLeonid Yegoshin 			goto sigill;
72934c2f668SLeonid Yegoshin 
73034c2f668SLeonid Yegoshin 		case mm_lwm32_func:
73134c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
73234c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
73334c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
73434c2f668SLeonid Yegoshin 				goto sigill;
73534c2f668SLeonid Yegoshin 			if (reg & 0x10) {
73645deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * (rvar + 1)))
73734c2f668SLeonid Yegoshin 					goto sigbus;
73834c2f668SLeonid Yegoshin 			} else {
73945deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * rvar))
74034c2f668SLeonid Yegoshin 					goto sigbus;
74134c2f668SLeonid Yegoshin 			}
74234c2f668SLeonid Yegoshin 			if (rvar == 9)
74334c2f668SLeonid Yegoshin 				rvar = 8;
74434c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
74534c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
74634c2f668SLeonid Yegoshin 				if (res)
74734c2f668SLeonid Yegoshin 					goto fault;
74834c2f668SLeonid Yegoshin 				addr += 4;
74934c2f668SLeonid Yegoshin 				regs->regs[i] = value;
75034c2f668SLeonid Yegoshin 			}
75134c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
75234c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
75334c2f668SLeonid Yegoshin 				if (res)
75434c2f668SLeonid Yegoshin 					goto fault;
75534c2f668SLeonid Yegoshin 				addr += 4;
75634c2f668SLeonid Yegoshin 				regs->regs[30] = value;
75734c2f668SLeonid Yegoshin 			}
75834c2f668SLeonid Yegoshin 			if (reg & 0x10) {
75934c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
76034c2f668SLeonid Yegoshin 				if (res)
76134c2f668SLeonid Yegoshin 					goto fault;
76234c2f668SLeonid Yegoshin 				regs->regs[31] = value;
76334c2f668SLeonid Yegoshin 			}
76434c2f668SLeonid Yegoshin 			goto success;
76534c2f668SLeonid Yegoshin 
76634c2f668SLeonid Yegoshin 		case mm_swm32_func:
76734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
76834c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
76934c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
77034c2f668SLeonid Yegoshin 				goto sigill;
77134c2f668SLeonid Yegoshin 			if (reg & 0x10) {
77245deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * (rvar + 1)))
77334c2f668SLeonid Yegoshin 					goto sigbus;
77434c2f668SLeonid Yegoshin 			} else {
77545deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * rvar))
77634c2f668SLeonid Yegoshin 					goto sigbus;
77734c2f668SLeonid Yegoshin 			}
77834c2f668SLeonid Yegoshin 			if (rvar == 9)
77934c2f668SLeonid Yegoshin 				rvar = 8;
78034c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
78134c2f668SLeonid Yegoshin 				value = regs->regs[i];
78234c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
78334c2f668SLeonid Yegoshin 				if (res)
78434c2f668SLeonid Yegoshin 					goto fault;
78534c2f668SLeonid Yegoshin 				addr += 4;
78634c2f668SLeonid Yegoshin 			}
78734c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
78834c2f668SLeonid Yegoshin 				value = regs->regs[30];
78934c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
79034c2f668SLeonid Yegoshin 				if (res)
79134c2f668SLeonid Yegoshin 					goto fault;
79234c2f668SLeonid Yegoshin 				addr += 4;
79334c2f668SLeonid Yegoshin 			}
79434c2f668SLeonid Yegoshin 			if (reg & 0x10) {
79534c2f668SLeonid Yegoshin 				value = regs->regs[31];
79634c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
79734c2f668SLeonid Yegoshin 				if (res)
79834c2f668SLeonid Yegoshin 					goto fault;
79934c2f668SLeonid Yegoshin 			}
80034c2f668SLeonid Yegoshin 			goto success;
80134c2f668SLeonid Yegoshin 
80234c2f668SLeonid Yegoshin 		case mm_ldm_func:
80334c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
80434c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
80534c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
80634c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
80734c2f668SLeonid Yegoshin 				goto sigill;
80834c2f668SLeonid Yegoshin 			if (reg & 0x10) {
80945deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * (rvar + 1)))
81034c2f668SLeonid Yegoshin 					goto sigbus;
81134c2f668SLeonid Yegoshin 			} else {
81245deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * rvar))
81334c2f668SLeonid Yegoshin 					goto sigbus;
81434c2f668SLeonid Yegoshin 			}
81534c2f668SLeonid Yegoshin 			if (rvar == 9)
81634c2f668SLeonid Yegoshin 				rvar = 8;
81734c2f668SLeonid Yegoshin 
81834c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
81934c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
82034c2f668SLeonid Yegoshin 				if (res)
82134c2f668SLeonid Yegoshin 					goto fault;
82234c2f668SLeonid Yegoshin 				addr += 4;
82334c2f668SLeonid Yegoshin 				regs->regs[i] = value;
82434c2f668SLeonid Yegoshin 			}
82534c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
82634c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
82734c2f668SLeonid Yegoshin 				if (res)
82834c2f668SLeonid Yegoshin 					goto fault;
82934c2f668SLeonid Yegoshin 				addr += 8;
83034c2f668SLeonid Yegoshin 				regs->regs[30] = value;
83134c2f668SLeonid Yegoshin 			}
83234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
83334c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
83434c2f668SLeonid Yegoshin 				if (res)
83534c2f668SLeonid Yegoshin 					goto fault;
83634c2f668SLeonid Yegoshin 				regs->regs[31] = value;
83734c2f668SLeonid Yegoshin 			}
83834c2f668SLeonid Yegoshin 			goto success;
83934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
84034c2f668SLeonid Yegoshin 
84134c2f668SLeonid Yegoshin 			goto sigill;
84234c2f668SLeonid Yegoshin 
84334c2f668SLeonid Yegoshin 		case mm_sdm_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 				value = regs->regs[i];
86134c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
86234c2f668SLeonid Yegoshin 				if (res)
86334c2f668SLeonid Yegoshin 					goto fault;
86434c2f668SLeonid Yegoshin 				addr += 8;
86534c2f668SLeonid Yegoshin 			}
86634c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
86734c2f668SLeonid Yegoshin 				value = regs->regs[30];
86834c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
86934c2f668SLeonid Yegoshin 				if (res)
87034c2f668SLeonid Yegoshin 					goto fault;
87134c2f668SLeonid Yegoshin 				addr += 8;
87234c2f668SLeonid Yegoshin 			}
87334c2f668SLeonid Yegoshin 			if (reg & 0x10) {
87434c2f668SLeonid Yegoshin 				value = regs->regs[31];
87534c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
87634c2f668SLeonid Yegoshin 				if (res)
87734c2f668SLeonid Yegoshin 					goto fault;
87834c2f668SLeonid Yegoshin 			}
87934c2f668SLeonid Yegoshin 			goto success;
88034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
88134c2f668SLeonid Yegoshin 
88234c2f668SLeonid Yegoshin 			goto sigill;
88334c2f668SLeonid Yegoshin 
88434c2f668SLeonid Yegoshin 			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
88534c2f668SLeonid Yegoshin 		}
88634c2f668SLeonid Yegoshin 
88734c2f668SLeonid Yegoshin 		goto sigbus;
88834c2f668SLeonid Yegoshin 
88934c2f668SLeonid Yegoshin 	case mm_pool32c_op:
89034c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
89134c2f668SLeonid Yegoshin 		case mm_lwu_func:
89234c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
89334c2f668SLeonid Yegoshin 			goto loadWU;
89434c2f668SLeonid Yegoshin 		}
89534c2f668SLeonid Yegoshin 
89634c2f668SLeonid Yegoshin 		/*  LL,SC,LLD,SCD are not serviced */
89734c2f668SLeonid Yegoshin 		goto sigbus;
89834c2f668SLeonid Yegoshin 
89985164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
90034c2f668SLeonid Yegoshin 	case mm_pool32f_op:
90134c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
90234c2f668SLeonid Yegoshin 		case mm_lwxc1_func:
90334c2f668SLeonid Yegoshin 		case mm_swxc1_func:
90434c2f668SLeonid Yegoshin 		case mm_ldxc1_func:
90534c2f668SLeonid Yegoshin 		case mm_sdxc1_func:
90634c2f668SLeonid Yegoshin 			goto fpu_emul;
90734c2f668SLeonid Yegoshin 		}
90834c2f668SLeonid Yegoshin 
90934c2f668SLeonid Yegoshin 		goto sigbus;
91034c2f668SLeonid Yegoshin 
91134c2f668SLeonid Yegoshin 	case mm_ldc132_op:
91234c2f668SLeonid Yegoshin 	case mm_sdc132_op:
91334c2f668SLeonid Yegoshin 	case mm_lwc132_op:
91485164fd8SPaul Burton 	case mm_swc132_op: {
91585164fd8SPaul Burton 		void __user *fault_addr = NULL;
91685164fd8SPaul Burton 
91734c2f668SLeonid Yegoshin fpu_emul:
91834c2f668SLeonid Yegoshin 		/* roll back jump/branch */
91934c2f668SLeonid Yegoshin 		regs->cp0_epc = origpc;
92034c2f668SLeonid Yegoshin 		regs->regs[31] = orig31;
92134c2f668SLeonid Yegoshin 
92234c2f668SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
92334c2f668SLeonid Yegoshin 		BUG_ON(!used_math());
92434c2f668SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
92534c2f668SLeonid Yegoshin 
92634c2f668SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
92734c2f668SLeonid Yegoshin 					       &fault_addr);
92834c2f668SLeonid Yegoshin 		own_fpu(1);	/* restore FPU state */
92934c2f668SLeonid Yegoshin 
93034c2f668SLeonid Yegoshin 		/* If something went wrong, signal */
931304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
93234c2f668SLeonid Yegoshin 
93334c2f668SLeonid Yegoshin 		if (res == 0)
93434c2f668SLeonid Yegoshin 			goto success;
93534c2f668SLeonid Yegoshin 		return;
93685164fd8SPaul Burton 	}
93785164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
93834c2f668SLeonid Yegoshin 
93934c2f668SLeonid Yegoshin 	case mm_lh32_op:
94034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
94134c2f668SLeonid Yegoshin 		goto loadHW;
94234c2f668SLeonid Yegoshin 
94334c2f668SLeonid Yegoshin 	case mm_lhu32_op:
94434c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
94534c2f668SLeonid Yegoshin 		goto loadHWU;
94634c2f668SLeonid Yegoshin 
94734c2f668SLeonid Yegoshin 	case mm_lw32_op:
94834c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
94934c2f668SLeonid Yegoshin 		goto loadW;
95034c2f668SLeonid Yegoshin 
95134c2f668SLeonid Yegoshin 	case mm_sh32_op:
95234c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
95334c2f668SLeonid Yegoshin 		goto storeHW;
95434c2f668SLeonid Yegoshin 
95534c2f668SLeonid Yegoshin 	case mm_sw32_op:
95634c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
95734c2f668SLeonid Yegoshin 		goto storeW;
95834c2f668SLeonid Yegoshin 
95934c2f668SLeonid Yegoshin 	case mm_ld32_op:
96034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
96134c2f668SLeonid Yegoshin 		goto loadDW;
96234c2f668SLeonid Yegoshin 
96334c2f668SLeonid Yegoshin 	case mm_sd32_op:
96434c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
96534c2f668SLeonid Yegoshin 		goto storeDW;
96634c2f668SLeonid Yegoshin 
96734c2f668SLeonid Yegoshin 	case mm_pool16c_op:
96834c2f668SLeonid Yegoshin 		switch (insn.mm16_m_format.func) {
96934c2f668SLeonid Yegoshin 		case mm_lwm16_op:
97034c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
97134c2f668SLeonid Yegoshin 			rvar = reg + 1;
97245deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 4 * rvar))
97334c2f668SLeonid Yegoshin 				goto sigbus;
97434c2f668SLeonid Yegoshin 
97534c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
97634c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
97734c2f668SLeonid Yegoshin 				if (res)
97834c2f668SLeonid Yegoshin 					goto fault;
97934c2f668SLeonid Yegoshin 				addr += 4;
98034c2f668SLeonid Yegoshin 				regs->regs[i] = value;
98134c2f668SLeonid Yegoshin 			}
98234c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
98334c2f668SLeonid Yegoshin 			if (res)
98434c2f668SLeonid Yegoshin 				goto fault;
98534c2f668SLeonid Yegoshin 			regs->regs[31] = value;
98634c2f668SLeonid Yegoshin 
98734c2f668SLeonid Yegoshin 			goto success;
98834c2f668SLeonid Yegoshin 
98934c2f668SLeonid Yegoshin 		case mm_swm16_op:
99034c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
99134c2f668SLeonid Yegoshin 			rvar = reg + 1;
99245deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 4 * rvar))
99334c2f668SLeonid Yegoshin 				goto sigbus;
99434c2f668SLeonid Yegoshin 
99534c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
99634c2f668SLeonid Yegoshin 				value = regs->regs[i];
99734c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
99834c2f668SLeonid Yegoshin 				if (res)
99934c2f668SLeonid Yegoshin 					goto fault;
100034c2f668SLeonid Yegoshin 				addr += 4;
100134c2f668SLeonid Yegoshin 			}
100234c2f668SLeonid Yegoshin 			value = regs->regs[31];
100334c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
100434c2f668SLeonid Yegoshin 			if (res)
100534c2f668SLeonid Yegoshin 				goto fault;
100634c2f668SLeonid Yegoshin 
100734c2f668SLeonid Yegoshin 			goto success;
100834c2f668SLeonid Yegoshin 
100934c2f668SLeonid Yegoshin 		}
101034c2f668SLeonid Yegoshin 
101134c2f668SLeonid Yegoshin 		goto sigbus;
101234c2f668SLeonid Yegoshin 
101334c2f668SLeonid Yegoshin 	case mm_lhu16_op:
101434c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
101534c2f668SLeonid Yegoshin 		goto loadHWU;
101634c2f668SLeonid Yegoshin 
101734c2f668SLeonid Yegoshin 	case mm_lw16_op:
101834c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
101934c2f668SLeonid Yegoshin 		goto loadW;
102034c2f668SLeonid Yegoshin 
102134c2f668SLeonid Yegoshin 	case mm_sh16_op:
102234c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
102334c2f668SLeonid Yegoshin 		goto storeHW;
102434c2f668SLeonid Yegoshin 
102534c2f668SLeonid Yegoshin 	case mm_sw16_op:
102634c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
102734c2f668SLeonid Yegoshin 		goto storeW;
102834c2f668SLeonid Yegoshin 
102934c2f668SLeonid Yegoshin 	case mm_lwsp16_op:
103034c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
103134c2f668SLeonid Yegoshin 		goto loadW;
103234c2f668SLeonid Yegoshin 
103334c2f668SLeonid Yegoshin 	case mm_swsp16_op:
103434c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
103534c2f668SLeonid Yegoshin 		goto storeW;
103634c2f668SLeonid Yegoshin 
103734c2f668SLeonid Yegoshin 	case mm_lwgp16_op:
103834c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_r3_format.rt];
103934c2f668SLeonid Yegoshin 		goto loadW;
104034c2f668SLeonid Yegoshin 
104134c2f668SLeonid Yegoshin 	default:
104234c2f668SLeonid Yegoshin 		goto sigill;
104334c2f668SLeonid Yegoshin 	}
104434c2f668SLeonid Yegoshin 
104534c2f668SLeonid Yegoshin loadHW:
104645deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
104734c2f668SLeonid Yegoshin 		goto sigbus;
104834c2f668SLeonid Yegoshin 
104934c2f668SLeonid Yegoshin 	LoadHW(addr, value, res);
105034c2f668SLeonid Yegoshin 	if (res)
105134c2f668SLeonid Yegoshin 		goto fault;
105234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
105334c2f668SLeonid Yegoshin 	goto success;
105434c2f668SLeonid Yegoshin 
105534c2f668SLeonid Yegoshin loadHWU:
105645deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
105734c2f668SLeonid Yegoshin 		goto sigbus;
105834c2f668SLeonid Yegoshin 
105934c2f668SLeonid Yegoshin 	LoadHWU(addr, value, res);
106034c2f668SLeonid Yegoshin 	if (res)
106134c2f668SLeonid Yegoshin 		goto fault;
106234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
106334c2f668SLeonid Yegoshin 	goto success;
106434c2f668SLeonid Yegoshin 
106534c2f668SLeonid Yegoshin loadW:
106645deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
106734c2f668SLeonid Yegoshin 		goto sigbus;
106834c2f668SLeonid Yegoshin 
106934c2f668SLeonid Yegoshin 	LoadW(addr, value, res);
107034c2f668SLeonid Yegoshin 	if (res)
107134c2f668SLeonid Yegoshin 		goto fault;
107234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
107334c2f668SLeonid Yegoshin 	goto success;
107434c2f668SLeonid Yegoshin 
107534c2f668SLeonid Yegoshin loadWU:
107634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
107734c2f668SLeonid Yegoshin 	/*
107834c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
107934c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
108034c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
108134c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
108234c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
108334c2f668SLeonid Yegoshin 	 */
108445deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
108534c2f668SLeonid Yegoshin 		goto sigbus;
108634c2f668SLeonid Yegoshin 
108734c2f668SLeonid Yegoshin 	LoadWU(addr, value, res);
108834c2f668SLeonid Yegoshin 	if (res)
108934c2f668SLeonid Yegoshin 		goto fault;
109034c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
109134c2f668SLeonid Yegoshin 	goto success;
109234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
109334c2f668SLeonid Yegoshin 
109434c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
109534c2f668SLeonid Yegoshin 	goto sigill;
109634c2f668SLeonid Yegoshin 
109734c2f668SLeonid Yegoshin loadDW:
109834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
109934c2f668SLeonid Yegoshin 	/*
110034c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
110134c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
110234c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
110334c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
110434c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
110534c2f668SLeonid Yegoshin 	 */
110645deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 8))
110734c2f668SLeonid Yegoshin 		goto sigbus;
110834c2f668SLeonid Yegoshin 
110934c2f668SLeonid Yegoshin 	LoadDW(addr, value, res);
111034c2f668SLeonid Yegoshin 	if (res)
111134c2f668SLeonid Yegoshin 		goto fault;
111234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
111334c2f668SLeonid Yegoshin 	goto success;
111434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
111534c2f668SLeonid Yegoshin 
111634c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
111734c2f668SLeonid Yegoshin 	goto sigill;
111834c2f668SLeonid Yegoshin 
111934c2f668SLeonid Yegoshin storeHW:
112045deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
112134c2f668SLeonid Yegoshin 		goto sigbus;
112234c2f668SLeonid Yegoshin 
112334c2f668SLeonid Yegoshin 	value = regs->regs[reg];
112434c2f668SLeonid Yegoshin 	StoreHW(addr, value, res);
112534c2f668SLeonid Yegoshin 	if (res)
112634c2f668SLeonid Yegoshin 		goto fault;
112734c2f668SLeonid Yegoshin 	goto success;
112834c2f668SLeonid Yegoshin 
112934c2f668SLeonid Yegoshin storeW:
113045deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
113134c2f668SLeonid Yegoshin 		goto sigbus;
113234c2f668SLeonid Yegoshin 
113334c2f668SLeonid Yegoshin 	value = regs->regs[reg];
113434c2f668SLeonid Yegoshin 	StoreW(addr, value, res);
113534c2f668SLeonid Yegoshin 	if (res)
113634c2f668SLeonid Yegoshin 		goto fault;
113734c2f668SLeonid Yegoshin 	goto success;
113834c2f668SLeonid Yegoshin 
113934c2f668SLeonid Yegoshin storeDW:
114034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
114134c2f668SLeonid Yegoshin 	/*
114234c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
114334c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
114434c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
114534c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
114634c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
114734c2f668SLeonid Yegoshin 	 */
114845deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 8))
114934c2f668SLeonid Yegoshin 		goto sigbus;
115034c2f668SLeonid Yegoshin 
115134c2f668SLeonid Yegoshin 	value = regs->regs[reg];
115234c2f668SLeonid Yegoshin 	StoreDW(addr, value, res);
115334c2f668SLeonid Yegoshin 	if (res)
115434c2f668SLeonid Yegoshin 		goto fault;
115534c2f668SLeonid Yegoshin 	goto success;
115634c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
115734c2f668SLeonid Yegoshin 
115834c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
115934c2f668SLeonid Yegoshin 	goto sigill;
116034c2f668SLeonid Yegoshin 
116134c2f668SLeonid Yegoshin success:
116234c2f668SLeonid Yegoshin 	regs->cp0_epc = contpc;	/* advance or branch */
116334c2f668SLeonid Yegoshin 
116434c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
116534c2f668SLeonid Yegoshin 	unaligned_instructions++;
116634c2f668SLeonid Yegoshin #endif
116734c2f668SLeonid Yegoshin 	return;
116834c2f668SLeonid Yegoshin 
116934c2f668SLeonid Yegoshin fault:
117034c2f668SLeonid Yegoshin 	/* roll back jump/branch */
117134c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
117234c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
117334c2f668SLeonid Yegoshin 	/* Did we have an exception handler installed? */
117434c2f668SLeonid Yegoshin 	if (fixup_exception(regs))
117534c2f668SLeonid Yegoshin 		return;
117634c2f668SLeonid Yegoshin 
117734c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
11783cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
117934c2f668SLeonid Yegoshin 
118034c2f668SLeonid Yegoshin 	return;
118134c2f668SLeonid Yegoshin 
118234c2f668SLeonid Yegoshin sigbus:
118334c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
11843cf5d076SEric W. Biederman 	force_sig(SIGBUS);
118534c2f668SLeonid Yegoshin 
118634c2f668SLeonid Yegoshin 	return;
118734c2f668SLeonid Yegoshin 
118834c2f668SLeonid Yegoshin sigill:
118934c2f668SLeonid Yegoshin 	die_if_kernel
119034c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
11913cf5d076SEric W. Biederman 	force_sig(SIGILL);
11921da177e4SLinus Torvalds }
11931da177e4SLinus Torvalds 
1194451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1195451b001bSSteven J. Hill {
1196451b001bSSteven J. Hill 	unsigned long value;
1197451b001bSSteven J. Hill 	unsigned int res;
1198451b001bSSteven J. Hill 	int reg;
1199451b001bSSteven J. Hill 	unsigned long orig31;
1200451b001bSSteven J. Hill 	u16 __user *pc16;
1201451b001bSSteven J. Hill 	unsigned long origpc;
1202451b001bSSteven J. Hill 	union mips16e_instruction mips16inst, oldinst;
1203f3235d32SMaciej W. Rozycki 	unsigned int opcode;
1204f3235d32SMaciej W. Rozycki 	int extended = 0;
120545deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
1206451b001bSSteven J. Hill 
1207451b001bSSteven J. Hill 	origpc = regs->cp0_epc;
1208451b001bSSteven J. Hill 	orig31 = regs->regs[31];
1209451b001bSSteven J. Hill 	pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1210451b001bSSteven J. Hill 	/*
1211451b001bSSteven J. Hill 	 * This load never faults.
1212451b001bSSteven J. Hill 	 */
1213451b001bSSteven J. Hill 	__get_user(mips16inst.full, pc16);
1214451b001bSSteven J. Hill 	oldinst = mips16inst;
1215451b001bSSteven J. Hill 
1216451b001bSSteven J. Hill 	/* skip EXTEND instruction */
1217451b001bSSteven J. Hill 	if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1218f3235d32SMaciej W. Rozycki 		extended = 1;
1219451b001bSSteven J. Hill 		pc16++;
1220451b001bSSteven J. Hill 		__get_user(mips16inst.full, pc16);
1221451b001bSSteven J. Hill 	} else if (delay_slot(regs)) {
1222451b001bSSteven J. Hill 		/*  skip jump instructions */
1223451b001bSSteven J. Hill 		/*  JAL/JALX are 32 bits but have OPCODE in first short int */
1224451b001bSSteven J. Hill 		if (mips16inst.ri.opcode == MIPS16e_jal_op)
1225451b001bSSteven J. Hill 			pc16++;
1226451b001bSSteven J. Hill 		pc16++;
1227451b001bSSteven J. Hill 		if (get_user(mips16inst.full, pc16))
1228451b001bSSteven J. Hill 			goto sigbus;
1229451b001bSSteven J. Hill 	}
1230451b001bSSteven J. Hill 
1231f3235d32SMaciej W. Rozycki 	opcode = mips16inst.ri.opcode;
1232f3235d32SMaciej W. Rozycki 	switch (opcode) {
1233451b001bSSteven J. Hill 	case MIPS16e_i64_op:	/* I64 or RI64 instruction */
1234451b001bSSteven J. Hill 		switch (mips16inst.i64.func) {	/* I64/RI64 func field check */
1235451b001bSSteven J. Hill 		case MIPS16e_ldpc_func:
1236451b001bSSteven J. Hill 		case MIPS16e_ldsp_func:
1237451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1238451b001bSSteven J. Hill 			goto loadDW;
1239451b001bSSteven J. Hill 
1240451b001bSSteven J. Hill 		case MIPS16e_sdsp_func:
1241451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1242451b001bSSteven J. Hill 			goto writeDW;
1243451b001bSSteven J. Hill 
1244451b001bSSteven J. Hill 		case MIPS16e_sdrasp_func:
1245451b001bSSteven J. Hill 			reg = 29;	/* GPRSP */
1246451b001bSSteven J. Hill 			goto writeDW;
1247451b001bSSteven J. Hill 		}
1248451b001bSSteven J. Hill 
1249451b001bSSteven J. Hill 		goto sigbus;
1250451b001bSSteven J. Hill 
1251451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1252f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
1253f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
1254f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
1255f3235d32SMaciej W. Rozycki 			case 0:		/* SWSP */
1256f3235d32SMaciej W. Rozycki 			case 1:		/* SWGP */
1257f3235d32SMaciej W. Rozycki 				break;
1258f3235d32SMaciej W. Rozycki 			case 2:		/* SHGP */
1259f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_sh_op;
1260f3235d32SMaciej W. Rozycki 				break;
1261f3235d32SMaciej W. Rozycki 			default:
1262f3235d32SMaciej W. Rozycki 				goto sigbus;
1263f3235d32SMaciej W. Rozycki 			}
1264f3235d32SMaciej W. Rozycki 		break;
1265f3235d32SMaciej W. Rozycki 
1266451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1267f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
1268f3235d32SMaciej W. Rozycki 		break;
1269f3235d32SMaciej W. Rozycki 
1270451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1271451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.ri.rx];
1272f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
1273f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
1274f3235d32SMaciej W. Rozycki 			case 0:		/* LWSP */
1275f3235d32SMaciej W. Rozycki 			case 1:		/* LWGP */
1276f3235d32SMaciej W. Rozycki 				break;
1277f3235d32SMaciej W. Rozycki 			case 2:		/* LHGP */
1278f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lh_op;
1279f3235d32SMaciej W. Rozycki 				break;
1280f3235d32SMaciej W. Rozycki 			case 4:		/* LHUGP */
1281f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lhu_op;
1282f3235d32SMaciej W. Rozycki 				break;
1283f3235d32SMaciej W. Rozycki 			default:
1284f3235d32SMaciej W. Rozycki 				goto sigbus;
1285f3235d32SMaciej W. Rozycki 			}
1286451b001bSSteven J. Hill 		break;
1287451b001bSSteven J. Hill 
1288451b001bSSteven J. Hill 	case MIPS16e_i8_op:
1289451b001bSSteven J. Hill 		if (mips16inst.i8.func != MIPS16e_swrasp_func)
1290451b001bSSteven J. Hill 			goto sigbus;
1291451b001bSSteven J. Hill 		reg = 29;	/* GPRSP */
1292451b001bSSteven J. Hill 		break;
1293451b001bSSteven J. Hill 
1294451b001bSSteven J. Hill 	default:
1295451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.rri.ry];
1296451b001bSSteven J. Hill 		break;
1297451b001bSSteven J. Hill 	}
1298451b001bSSteven J. Hill 
1299f3235d32SMaciej W. Rozycki 	switch (opcode) {
1300451b001bSSteven J. Hill 
1301451b001bSSteven J. Hill 	case MIPS16e_lb_op:
1302451b001bSSteven J. Hill 	case MIPS16e_lbu_op:
1303451b001bSSteven J. Hill 	case MIPS16e_sb_op:
1304451b001bSSteven J. Hill 		goto sigbus;
1305451b001bSSteven J. Hill 
1306451b001bSSteven J. Hill 	case MIPS16e_lh_op:
130745deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1308451b001bSSteven J. Hill 			goto sigbus;
1309451b001bSSteven J. Hill 
1310451b001bSSteven J. Hill 		LoadHW(addr, value, res);
1311451b001bSSteven J. Hill 		if (res)
1312451b001bSSteven J. Hill 			goto fault;
1313451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1314451b001bSSteven J. Hill 		regs->regs[reg] = value;
1315451b001bSSteven J. Hill 		break;
1316451b001bSSteven J. Hill 
1317451b001bSSteven J. Hill 	case MIPS16e_lhu_op:
131845deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1319451b001bSSteven J. Hill 			goto sigbus;
1320451b001bSSteven J. Hill 
1321451b001bSSteven J. Hill 		LoadHWU(addr, value, res);
1322451b001bSSteven J. Hill 		if (res)
1323451b001bSSteven J. Hill 			goto fault;
1324451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1325451b001bSSteven J. Hill 		regs->regs[reg] = value;
1326451b001bSSteven J. Hill 		break;
1327451b001bSSteven J. Hill 
1328451b001bSSteven J. Hill 	case MIPS16e_lw_op:
1329451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1330451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
133145deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1332451b001bSSteven J. Hill 			goto sigbus;
1333451b001bSSteven J. Hill 
1334451b001bSSteven J. Hill 		LoadW(addr, value, res);
1335451b001bSSteven J. Hill 		if (res)
1336451b001bSSteven J. Hill 			goto fault;
1337451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1338451b001bSSteven J. Hill 		regs->regs[reg] = value;
1339451b001bSSteven J. Hill 		break;
1340451b001bSSteven J. Hill 
1341451b001bSSteven J. Hill 	case MIPS16e_lwu_op:
1342451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1343451b001bSSteven J. Hill 		/*
1344451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1345451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1346451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1347451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1348451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1349451b001bSSteven J. Hill 		 */
135045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1351451b001bSSteven J. Hill 			goto sigbus;
1352451b001bSSteven J. Hill 
1353451b001bSSteven J. Hill 		LoadWU(addr, value, res);
1354451b001bSSteven J. Hill 		if (res)
1355451b001bSSteven J. Hill 			goto fault;
1356451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1357451b001bSSteven J. Hill 		regs->regs[reg] = value;
1358451b001bSSteven J. Hill 		break;
1359451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1360451b001bSSteven J. Hill 
1361451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1362451b001bSSteven J. Hill 		goto sigill;
1363451b001bSSteven J. Hill 
1364451b001bSSteven J. Hill 	case MIPS16e_ld_op:
1365451b001bSSteven J. Hill loadDW:
1366451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1367451b001bSSteven J. Hill 		/*
1368451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1369451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1370451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1371451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1372451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1373451b001bSSteven J. Hill 		 */
137445deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
1375451b001bSSteven J. Hill 			goto sigbus;
1376451b001bSSteven J. Hill 
1377451b001bSSteven J. Hill 		LoadDW(addr, value, res);
1378451b001bSSteven J. Hill 		if (res)
1379451b001bSSteven J. Hill 			goto fault;
1380451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1381451b001bSSteven J. Hill 		regs->regs[reg] = value;
1382451b001bSSteven J. Hill 		break;
1383451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1384451b001bSSteven J. Hill 
1385451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1386451b001bSSteven J. Hill 		goto sigill;
1387451b001bSSteven J. Hill 
1388451b001bSSteven J. Hill 	case MIPS16e_sh_op:
138945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1390451b001bSSteven J. Hill 			goto sigbus;
1391451b001bSSteven J. Hill 
1392451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1393451b001bSSteven J. Hill 		value = regs->regs[reg];
1394451b001bSSteven J. Hill 		StoreHW(addr, value, res);
1395451b001bSSteven J. Hill 		if (res)
1396451b001bSSteven J. Hill 			goto fault;
1397451b001bSSteven J. Hill 		break;
1398451b001bSSteven J. Hill 
1399451b001bSSteven J. Hill 	case MIPS16e_sw_op:
1400451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1401451b001bSSteven J. Hill 	case MIPS16e_i8_op:	/* actually - MIPS16e_swrasp_func */
140245deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1403451b001bSSteven J. Hill 			goto sigbus;
1404451b001bSSteven J. Hill 
1405451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1406451b001bSSteven J. Hill 		value = regs->regs[reg];
1407451b001bSSteven J. Hill 		StoreW(addr, value, res);
1408451b001bSSteven J. Hill 		if (res)
1409451b001bSSteven J. Hill 			goto fault;
1410451b001bSSteven J. Hill 		break;
1411451b001bSSteven J. Hill 
1412451b001bSSteven J. Hill 	case MIPS16e_sd_op:
1413451b001bSSteven J. Hill writeDW:
1414451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1415451b001bSSteven J. Hill 		/*
1416451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1417451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1418451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1419451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1420451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1421451b001bSSteven J. Hill 		 */
142245deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
1423451b001bSSteven J. Hill 			goto sigbus;
1424451b001bSSteven J. Hill 
1425451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1426451b001bSSteven J. Hill 		value = regs->regs[reg];
1427451b001bSSteven J. Hill 		StoreDW(addr, value, res);
1428451b001bSSteven J. Hill 		if (res)
1429451b001bSSteven J. Hill 			goto fault;
1430451b001bSSteven J. Hill 		break;
1431451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1432451b001bSSteven J. Hill 
1433451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1434451b001bSSteven J. Hill 		goto sigill;
1435451b001bSSteven J. Hill 
1436451b001bSSteven J. Hill 	default:
1437451b001bSSteven J. Hill 		/*
1438451b001bSSteven J. Hill 		 * Pheeee...  We encountered an yet unknown instruction or
1439451b001bSSteven J. Hill 		 * cache coherence problem.  Die sucker, die ...
1440451b001bSSteven J. Hill 		 */
1441451b001bSSteven J. Hill 		goto sigill;
1442451b001bSSteven J. Hill 	}
1443451b001bSSteven J. Hill 
1444451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
1445451b001bSSteven J. Hill 	unaligned_instructions++;
1446451b001bSSteven J. Hill #endif
1447451b001bSSteven J. Hill 
1448451b001bSSteven J. Hill 	return;
1449451b001bSSteven J. Hill 
1450451b001bSSteven J. Hill fault:
1451451b001bSSteven J. Hill 	/* roll back jump/branch */
1452451b001bSSteven J. Hill 	regs->cp0_epc = origpc;
1453451b001bSSteven J. Hill 	regs->regs[31] = orig31;
1454451b001bSSteven J. Hill 	/* Did we have an exception handler installed? */
1455451b001bSSteven J. Hill 	if (fixup_exception(regs))
1456451b001bSSteven J. Hill 		return;
1457451b001bSSteven J. Hill 
1458451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
14593cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
1460451b001bSSteven J. Hill 
1461451b001bSSteven J. Hill 	return;
1462451b001bSSteven J. Hill 
1463451b001bSSteven J. Hill sigbus:
1464451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
14653cf5d076SEric W. Biederman 	force_sig(SIGBUS);
1466451b001bSSteven J. Hill 
1467451b001bSSteven J. Hill 	return;
1468451b001bSSteven J. Hill 
1469451b001bSSteven J. Hill sigill:
1470451b001bSSteven J. Hill 	die_if_kernel
1471451b001bSSteven J. Hill 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
14723cf5d076SEric W. Biederman 	force_sig(SIGILL);
1473451b001bSSteven J. Hill }
1474fc192e50STony Wu 
14751da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
14761da177e4SLinus Torvalds {
1477c3fc5cd5SRalf Baechle 	enum ctx_state prev_state;
14787cba4128SThomas Bogendoerfer 	unsigned int *pc;
14791da177e4SLinus Torvalds 
1480c3fc5cd5SRalf Baechle 	prev_state = exception_enter();
14817f788d2dSDeng-Cheng Zhu 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1482a8b0ca17SPeter Zijlstra 			1, regs, regs->cp0_badvaddr);
1483*429124d9SThomas Bogendoerfer 
1484*429124d9SThomas Bogendoerfer #ifdef CONFIG_64BIT
1485*429124d9SThomas Bogendoerfer 	/*
1486*429124d9SThomas Bogendoerfer 	 * check, if we are hitting space between CPU implemented maximum
1487*429124d9SThomas Bogendoerfer 	 * virtual user address and 64bit maximum virtual user address
1488*429124d9SThomas Bogendoerfer 	 * and do exception handling to get EFAULTs for get_user/put_user
1489*429124d9SThomas Bogendoerfer 	 */
1490*429124d9SThomas Bogendoerfer 	if ((regs->cp0_badvaddr >= (1UL << cpu_vmbits)) &&
1491*429124d9SThomas Bogendoerfer 	    (regs->cp0_badvaddr < XKSSEG)) {
1492*429124d9SThomas Bogendoerfer 		if (fixup_exception(regs)) {
1493*429124d9SThomas Bogendoerfer 			current->thread.cp0_baduaddr = regs->cp0_badvaddr;
1494*429124d9SThomas Bogendoerfer 			return;
1495*429124d9SThomas Bogendoerfer 		}
1496*429124d9SThomas Bogendoerfer 		goto sigbus;
1497*429124d9SThomas Bogendoerfer 	}
1498*429124d9SThomas Bogendoerfer #endif
1499*429124d9SThomas Bogendoerfer 
15001da177e4SLinus Torvalds 	/*
15011da177e4SLinus Torvalds 	 * Did we catch a fault trying to load an instruction?
15021da177e4SLinus Torvalds 	 */
150334c2f668SLeonid Yegoshin 	if (regs->cp0_badvaddr == regs->cp0_epc)
15041da177e4SLinus Torvalds 		goto sigbus;
15051da177e4SLinus Torvalds 
1506293c5bd1SRalf Baechle 	if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
15071da177e4SLinus Torvalds 		goto sigbus;
15086312e0eeSAtsushi Nemoto 	if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
15096312e0eeSAtsushi Nemoto 		goto sigbus;
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 	/*
15121da177e4SLinus Torvalds 	 * Do branch emulation only if we didn't forward the exception.
15131da177e4SLinus Torvalds 	 * This is all so but ugly ...
15141da177e4SLinus Torvalds 	 */
151534c2f668SLeonid Yegoshin 
151634c2f668SLeonid Yegoshin 	/*
151734c2f668SLeonid Yegoshin 	 * Are we running in microMIPS mode?
151834c2f668SLeonid Yegoshin 	 */
151934c2f668SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
152034c2f668SLeonid Yegoshin 		/*
152134c2f668SLeonid Yegoshin 		 * Did we catch a fault trying to load an instruction in
152234c2f668SLeonid Yegoshin 		 * 16-bit mode?
152334c2f668SLeonid Yegoshin 		 */
152434c2f668SLeonid Yegoshin 		if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
152534c2f668SLeonid Yegoshin 			goto sigbus;
152634c2f668SLeonid Yegoshin 		if (unaligned_action == UNALIGNED_ACTION_SHOW)
152734c2f668SLeonid Yegoshin 			show_registers(regs);
152834c2f668SLeonid Yegoshin 
152934c2f668SLeonid Yegoshin 		if (cpu_has_mmips) {
153034c2f668SLeonid Yegoshin 			emulate_load_store_microMIPS(regs,
153134c2f668SLeonid Yegoshin 				(void __user *)regs->cp0_badvaddr);
153234c2f668SLeonid Yegoshin 			return;
153334c2f668SLeonid Yegoshin 		}
153434c2f668SLeonid Yegoshin 
1535451b001bSSteven J. Hill 		if (cpu_has_mips16) {
1536451b001bSSteven J. Hill 			emulate_load_store_MIPS16e(regs,
1537451b001bSSteven J. Hill 				(void __user *)regs->cp0_badvaddr);
1538451b001bSSteven J. Hill 			return;
1539451b001bSSteven J. Hill 		}
1540451b001bSSteven J. Hill 
154134c2f668SLeonid Yegoshin 		goto sigbus;
154234c2f668SLeonid Yegoshin 	}
154334c2f668SLeonid Yegoshin 
154434c2f668SLeonid Yegoshin 	if (unaligned_action == UNALIGNED_ACTION_SHOW)
154534c2f668SLeonid Yegoshin 		show_registers(regs);
15467cba4128SThomas Bogendoerfer 	pc = (unsigned int *)exception_epc(regs);
154734c2f668SLeonid Yegoshin 
15487f18f151SRalf Baechle 	emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
15491da177e4SLinus Torvalds 
15501da177e4SLinus Torvalds 	return;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds sigbus:
15531da177e4SLinus Torvalds 	die_if_kernel("Kernel unaligned instruction access", regs);
15543cf5d076SEric W. Biederman 	force_sig(SIGBUS);
15551da177e4SLinus Torvalds 
15561da177e4SLinus Torvalds 	/*
15571da177e4SLinus Torvalds 	 * XXX On return from the signal handler we should advance the epc
15581da177e4SLinus Torvalds 	 */
1559c3fc5cd5SRalf Baechle 	exception_exit(prev_state);
15601da177e4SLinus Torvalds }
15616312e0eeSAtsushi Nemoto 
15626312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
15636312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
15646312e0eeSAtsushi Nemoto {
1565d8140426SGreg Kroah-Hartman 	debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir,
1566d8140426SGreg Kroah-Hartman 			   &unaligned_instructions);
1567d8140426SGreg Kroah-Hartman 	debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
15686312e0eeSAtsushi Nemoto 			   mips_debugfs_dir, &unaligned_action);
15696312e0eeSAtsushi Nemoto 	return 0;
15706312e0eeSAtsushi Nemoto }
15718d6b591cSRalf Baechle arch_initcall(debugfs_unaligned);
15726312e0eeSAtsushi Nemoto #endif
1573