xref: /linux/arch/mips/kernel/unaligned.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
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>
94*09fc778eSArnd Bergmann #include <asm/traps.h>
957c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
961da177e4SLinus Torvalds 
9745deb5faSThomas Bogendoerfer #include "access-helper.h"
9845deb5faSThomas Bogendoerfer 
996312e0eeSAtsushi Nemoto enum {
1006312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_QUIET,
1016312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SIGNAL,
1026312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SHOW,
1036312e0eeSAtsushi Nemoto };
1046312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
1056312e0eeSAtsushi Nemoto static u32 unaligned_instructions;
1066312e0eeSAtsushi Nemoto static u32 unaligned_action;
1076312e0eeSAtsushi Nemoto #else
1086312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET
1091da177e4SLinus Torvalds #endif
1106312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs);
1111da177e4SLinus Torvalds 
emulate_load_store_insn(struct pt_regs * regs,void __user * addr,unsigned int * pc)1127f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs,
1137cba4128SThomas Bogendoerfer 	void __user *addr, unsigned int *pc)
1141da177e4SLinus Torvalds {
11585164fd8SPaul Burton 	unsigned long origpc, orig31, value;
1161da177e4SLinus Torvalds 	union mips_instruction insn;
11785164fd8SPaul Burton 	unsigned int res;
11845deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
11945deb5faSThomas Bogendoerfer 
12034c2f668SLeonid Yegoshin 	origpc = (unsigned long)pc;
12134c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
12234c2f668SLeonid Yegoshin 
123a8b0ca17SPeter Zijlstra 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
1247f788d2dSDeng-Cheng Zhu 
1251da177e4SLinus Torvalds 	/*
1261da177e4SLinus Torvalds 	 * This load never faults.
1271da177e4SLinus Torvalds 	 */
12845deb5faSThomas Bogendoerfer 	__get_inst32(&insn.word, pc, user);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	switch (insn.i_format.opcode) {
1311da177e4SLinus Torvalds 		/*
1321da177e4SLinus Torvalds 		 * These are instructions that a compiler doesn't generate.  We
1331da177e4SLinus Torvalds 		 * can assume therefore that the code is MIPS-aware and
1341da177e4SLinus Torvalds 		 * really buggy.  Emulating these instructions would break the
1351da177e4SLinus Torvalds 		 * semantics anyway.
1361da177e4SLinus Torvalds 		 */
1371da177e4SLinus Torvalds 	case ll_op:
1381da177e4SLinus Torvalds 	case lld_op:
1391da177e4SLinus Torvalds 	case sc_op:
1401da177e4SLinus Torvalds 	case scd_op:
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 		/*
1431da177e4SLinus Torvalds 		 * For these instructions the only way to create an address
1441da177e4SLinus Torvalds 		 * error is an attempted access to kernel/supervisor address
1451da177e4SLinus Torvalds 		 * space.
1461da177e4SLinus Torvalds 		 */
1471da177e4SLinus Torvalds 	case ldl_op:
1481da177e4SLinus Torvalds 	case ldr_op:
1491da177e4SLinus Torvalds 	case lwl_op:
1501da177e4SLinus Torvalds 	case lwr_op:
1511da177e4SLinus Torvalds 	case sdl_op:
1521da177e4SLinus Torvalds 	case sdr_op:
1531da177e4SLinus Torvalds 	case swl_op:
1541da177e4SLinus Torvalds 	case swr_op:
1551da177e4SLinus Torvalds 	case lb_op:
1561da177e4SLinus Torvalds 	case lbu_op:
1571da177e4SLinus Torvalds 	case sb_op:
1581da177e4SLinus Torvalds 		goto sigbus;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 		/*
16134c2f668SLeonid Yegoshin 		 * The remaining opcodes are the ones that are really of
16234c2f668SLeonid Yegoshin 		 * interest.
1631da177e4SLinus Torvalds 		 */
1646673c276SSiarhei Volkau #ifdef CONFIG_MACH_INGENIC
1656673c276SSiarhei Volkau 	case spec2_op:
1666673c276SSiarhei Volkau 		if (insn.mxu_lx_format.func != mxu_lx_op)
1676673c276SSiarhei Volkau 			goto sigbus; /* other MXU instructions we don't care */
1686673c276SSiarhei Volkau 
1696673c276SSiarhei Volkau 		switch (insn.mxu_lx_format.op) {
1706673c276SSiarhei Volkau 		case mxu_lxw_op:
1716673c276SSiarhei Volkau 			if (user && !access_ok(addr, 4))
1726673c276SSiarhei Volkau 				goto sigbus;
1736673c276SSiarhei Volkau 			LoadW(addr, value, res);
1746673c276SSiarhei Volkau 			if (res)
1756673c276SSiarhei Volkau 				goto fault;
1766673c276SSiarhei Volkau 			compute_return_epc(regs);
1776673c276SSiarhei Volkau 			regs->regs[insn.mxu_lx_format.rd] = value;
1786673c276SSiarhei Volkau 			break;
1796673c276SSiarhei Volkau 		case mxu_lxh_op:
1806673c276SSiarhei Volkau 			if (user && !access_ok(addr, 2))
1816673c276SSiarhei Volkau 				goto sigbus;
1826673c276SSiarhei Volkau 			LoadHW(addr, value, res);
1836673c276SSiarhei Volkau 			if (res)
1846673c276SSiarhei Volkau 				goto fault;
1856673c276SSiarhei Volkau 			compute_return_epc(regs);
1866673c276SSiarhei Volkau 			regs->regs[insn.dsp_format.rd] = value;
1876673c276SSiarhei Volkau 			break;
1886673c276SSiarhei Volkau 		case mxu_lxhu_op:
1896673c276SSiarhei Volkau 			if (user && !access_ok(addr, 2))
1906673c276SSiarhei Volkau 				goto sigbus;
1916673c276SSiarhei Volkau 			LoadHWU(addr, value, res);
1926673c276SSiarhei Volkau 			if (res)
1936673c276SSiarhei Volkau 				goto fault;
1946673c276SSiarhei Volkau 			compute_return_epc(regs);
1956673c276SSiarhei Volkau 			regs->regs[insn.dsp_format.rd] = value;
1966673c276SSiarhei Volkau 			break;
1976673c276SSiarhei Volkau 		case mxu_lxb_op:
1986673c276SSiarhei Volkau 		case mxu_lxbu_op:
1996673c276SSiarhei Volkau 			goto sigbus;
2006673c276SSiarhei Volkau 		default:
2016673c276SSiarhei Volkau 			goto sigill;
2026673c276SSiarhei Volkau 		}
2036673c276SSiarhei Volkau 		break;
2046673c276SSiarhei Volkau #endif
205c1771216SLeonid Yegoshin 	case spec3_op:
2063f88ec63SMiodrag Dinic 		if (insn.dsp_format.func == lx_op) {
2073f88ec63SMiodrag Dinic 			switch (insn.dsp_format.op) {
2083f88ec63SMiodrag Dinic 			case lwx_op:
20945deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4))
2103f88ec63SMiodrag Dinic 					goto sigbus;
2113f88ec63SMiodrag Dinic 				LoadW(addr, value, res);
2123f88ec63SMiodrag Dinic 				if (res)
2133f88ec63SMiodrag Dinic 					goto fault;
2143f88ec63SMiodrag Dinic 				compute_return_epc(regs);
2153f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
2163f88ec63SMiodrag Dinic 				break;
2173f88ec63SMiodrag Dinic 			case lhx_op:
21845deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 2))
2193f88ec63SMiodrag Dinic 					goto sigbus;
2203f88ec63SMiodrag Dinic 				LoadHW(addr, value, res);
2213f88ec63SMiodrag Dinic 				if (res)
2223f88ec63SMiodrag Dinic 					goto fault;
2233f88ec63SMiodrag Dinic 				compute_return_epc(regs);
2243f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
2253f88ec63SMiodrag Dinic 				break;
2263f88ec63SMiodrag Dinic 			default:
2273f88ec63SMiodrag Dinic 				goto sigill;
2283f88ec63SMiodrag Dinic 			}
2293f88ec63SMiodrag Dinic 		}
2303f88ec63SMiodrag Dinic #ifdef CONFIG_EVA
2313f88ec63SMiodrag Dinic 		else {
232c1771216SLeonid Yegoshin 			/*
2333f88ec63SMiodrag Dinic 			 * we can land here only from kernel accessing user
2343f88ec63SMiodrag Dinic 			 * memory, so we need to "switch" the address limit to
2353f88ec63SMiodrag Dinic 			 * user space, so that address check can work properly.
236c1771216SLeonid Yegoshin 			 */
237c1771216SLeonid Yegoshin 			switch (insn.spec3_format.func) {
238c1771216SLeonid Yegoshin 			case lhe_op:
23945deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
240c1771216SLeonid Yegoshin 					goto sigbus;
241eeb53895SMarkos Chandras 				LoadHWE(addr, value, res);
24245deb5faSThomas Bogendoerfer 				if (res)
243c1771216SLeonid Yegoshin 					goto fault;
244c1771216SLeonid Yegoshin 				compute_return_epc(regs);
245c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
246c1771216SLeonid Yegoshin 				break;
247c1771216SLeonid Yegoshin 			case lwe_op:
24845deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 4))
249c1771216SLeonid Yegoshin 					goto sigbus;
250eeb53895SMarkos Chandras 				LoadWE(addr, value, res);
25145deb5faSThomas Bogendoerfer 				if (res)
252c1771216SLeonid Yegoshin 					goto fault;
253c1771216SLeonid Yegoshin 				compute_return_epc(regs);
254c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
255c1771216SLeonid Yegoshin 				break;
256c1771216SLeonid Yegoshin 			case lhue_op:
25745deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
258c1771216SLeonid Yegoshin 					goto sigbus;
259eeb53895SMarkos Chandras 				LoadHWUE(addr, value, res);
26045deb5faSThomas Bogendoerfer 				if (res)
261c1771216SLeonid Yegoshin 					goto fault;
262c1771216SLeonid Yegoshin 				compute_return_epc(regs);
263c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
264c1771216SLeonid Yegoshin 				break;
265c1771216SLeonid Yegoshin 			case she_op:
26645deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 2))
267c1771216SLeonid Yegoshin 					goto sigbus;
268c1771216SLeonid Yegoshin 				compute_return_epc(regs);
269c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
270eeb53895SMarkos Chandras 				StoreHWE(addr, value, res);
27145deb5faSThomas Bogendoerfer 				if (res)
272c1771216SLeonid Yegoshin 					goto fault;
273c1771216SLeonid Yegoshin 				break;
274c1771216SLeonid Yegoshin 			case swe_op:
27545deb5faSThomas Bogendoerfer 				if (!access_ok(addr, 4))
276c1771216SLeonid Yegoshin 					goto sigbus;
277c1771216SLeonid Yegoshin 				compute_return_epc(regs);
278c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
279eeb53895SMarkos Chandras 				StoreWE(addr, value, res);
28045deb5faSThomas Bogendoerfer 				if (res)
281c1771216SLeonid Yegoshin 					goto fault;
282c1771216SLeonid Yegoshin 				break;
283c1771216SLeonid Yegoshin 			default:
284c1771216SLeonid Yegoshin 				goto sigill;
285c1771216SLeonid Yegoshin 			}
2863f88ec63SMiodrag Dinic 		}
287c1771216SLeonid Yegoshin #endif
2883f88ec63SMiodrag Dinic 		break;
2891da177e4SLinus Torvalds 	case lh_op:
29045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
2911da177e4SLinus Torvalds 			goto sigbus;
2921da177e4SLinus Torvalds 
29345deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
2946eae3548SMarkos Chandras 			LoadHWE(addr, value, res);
29545deb5faSThomas Bogendoerfer 		else
2966eae3548SMarkos Chandras 			LoadHW(addr, value, res);
2976eae3548SMarkos Chandras 
2981da177e4SLinus Torvalds 		if (res)
2991da177e4SLinus Torvalds 			goto fault;
3007f18f151SRalf Baechle 		compute_return_epc(regs);
3017f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3021da177e4SLinus Torvalds 		break;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	case lw_op:
30545deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3061da177e4SLinus Torvalds 			goto sigbus;
3071da177e4SLinus Torvalds 
30845deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3096eae3548SMarkos Chandras 			LoadWE(addr, value, res);
31045deb5faSThomas Bogendoerfer 		else
3116eae3548SMarkos Chandras 			LoadW(addr, value, res);
3126eae3548SMarkos Chandras 
3131da177e4SLinus Torvalds 		if (res)
3141da177e4SLinus Torvalds 			goto fault;
3157f18f151SRalf Baechle 		compute_return_epc(regs);
3167f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3171da177e4SLinus Torvalds 		break;
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	case lhu_op:
32045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
3211da177e4SLinus Torvalds 			goto sigbus;
3221da177e4SLinus Torvalds 
32345deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3246eae3548SMarkos Chandras 			LoadHWUE(addr, value, res);
32545deb5faSThomas Bogendoerfer 		else
3266eae3548SMarkos Chandras 			LoadHWU(addr, value, res);
3276eae3548SMarkos Chandras 
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;
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	case lwu_op:
335875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3361da177e4SLinus Torvalds 		/*
3371da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
3381da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
3391da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
3401da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
3411da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3421da177e4SLinus Torvalds 		 */
34345deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3441da177e4SLinus Torvalds 			goto sigbus;
3451da177e4SLinus Torvalds 
34634c2f668SLeonid Yegoshin 		LoadWU(addr, value, res);
3471da177e4SLinus Torvalds 		if (res)
3481da177e4SLinus Torvalds 			goto fault;
3497f18f151SRalf Baechle 		compute_return_epc(regs);
3507f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3511da177e4SLinus Torvalds 		break;
352875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3551da177e4SLinus Torvalds 		goto sigill;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	case ld_op:
358875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3591da177e4SLinus Torvalds 		/*
3601da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
3611da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
3621da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
3631da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
3641da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
3651da177e4SLinus Torvalds 		 */
36645deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
3671da177e4SLinus Torvalds 			goto sigbus;
3681da177e4SLinus Torvalds 
36934c2f668SLeonid Yegoshin 		LoadDW(addr, value, res);
3701da177e4SLinus Torvalds 		if (res)
3711da177e4SLinus Torvalds 			goto fault;
3727f18f151SRalf Baechle 		compute_return_epc(regs);
3737f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
3741da177e4SLinus Torvalds 		break;
375875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
3781da177e4SLinus Torvalds 		goto sigill;
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	case sh_op:
38145deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
3821da177e4SLinus Torvalds 			goto sigbus;
3831da177e4SLinus Torvalds 
38434c2f668SLeonid Yegoshin 		compute_return_epc(regs);
3851da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
3866eae3548SMarkos Chandras 
38745deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
3886eae3548SMarkos Chandras 			StoreHWE(addr, value, res);
38945deb5faSThomas Bogendoerfer 		else
3906eae3548SMarkos Chandras 			StoreHW(addr, value, res);
3916eae3548SMarkos Chandras 
3921da177e4SLinus Torvalds 		if (res)
3931da177e4SLinus Torvalds 			goto fault;
3941da177e4SLinus Torvalds 		break;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	case sw_op:
39745deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
3981da177e4SLinus Torvalds 			goto sigbus;
3991da177e4SLinus Torvalds 
40034c2f668SLeonid Yegoshin 		compute_return_epc(regs);
4011da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
4026eae3548SMarkos Chandras 
40345deb5faSThomas Bogendoerfer 		if (IS_ENABLED(CONFIG_EVA) && user)
4046eae3548SMarkos Chandras 			StoreWE(addr, value, res);
40545deb5faSThomas Bogendoerfer 		else
4066eae3548SMarkos Chandras 			StoreW(addr, value, res);
4076eae3548SMarkos Chandras 
4081da177e4SLinus Torvalds 		if (res)
4091da177e4SLinus Torvalds 			goto fault;
4101da177e4SLinus Torvalds 		break;
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 	case sd_op:
413875d43e7SRalf Baechle #ifdef CONFIG_64BIT
4141da177e4SLinus Torvalds 		/*
4151da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
4161da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
4171da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
4181da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
4191da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
4201da177e4SLinus Torvalds 		 */
42145deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
4221da177e4SLinus Torvalds 			goto sigbus;
4231da177e4SLinus Torvalds 
42434c2f668SLeonid Yegoshin 		compute_return_epc(regs);
4251da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
42634c2f668SLeonid Yegoshin 		StoreDW(addr, value, res);
4271da177e4SLinus Torvalds 		if (res)
4281da177e4SLinus Torvalds 			goto fault;
4291da177e4SLinus Torvalds 		break;
430875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
4331da177e4SLinus Torvalds 		goto sigill;
4341da177e4SLinus Torvalds 
43585164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
43685164fd8SPaul Burton 
4371da177e4SLinus Torvalds 	case lwc1_op:
4381da177e4SLinus Torvalds 	case ldc1_op:
4391da177e4SLinus Torvalds 	case swc1_op:
4401da177e4SLinus Torvalds 	case sdc1_op:
44185164fd8SPaul Burton 	case cop1x_op: {
44285164fd8SPaul Burton 		void __user *fault_addr = NULL;
44385164fd8SPaul Burton 
444102cedc3SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
445102cedc3SLeonid Yegoshin 		BUG_ON(!used_math());
446102cedc3SLeonid Yegoshin 
447102cedc3SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
448102cedc3SLeonid Yegoshin 					       &fault_addr);
449102cedc3SLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
450102cedc3SLeonid Yegoshin 
451102cedc3SLeonid Yegoshin 		/* Signal if something went wrong. */
452304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
453102cedc3SLeonid Yegoshin 
454102cedc3SLeonid Yegoshin 		if (res == 0)
455102cedc3SLeonid Yegoshin 			break;
456102cedc3SLeonid Yegoshin 		return;
45785164fd8SPaul Burton 	}
45885164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
4591da177e4SLinus Torvalds 
46085164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
46185164fd8SPaul Burton 
46285164fd8SPaul Burton 	case msa_op: {
46385164fd8SPaul Burton 		unsigned int wd, preempted;
46485164fd8SPaul Burton 		enum msa_2b_fmt df;
46585164fd8SPaul Burton 		union fpureg *fpr;
46685164fd8SPaul Burton 
467e4aa1f15SLeonid Yegoshin 		if (!cpu_has_msa)
468e4aa1f15SLeonid Yegoshin 			goto sigill;
469e4aa1f15SLeonid Yegoshin 
470e4aa1f15SLeonid Yegoshin 		/*
471e4aa1f15SLeonid Yegoshin 		 * If we've reached this point then userland should have taken
472e4aa1f15SLeonid Yegoshin 		 * the MSA disabled exception & initialised vector context at
473e4aa1f15SLeonid Yegoshin 		 * some point in the past.
474e4aa1f15SLeonid Yegoshin 		 */
475e4aa1f15SLeonid Yegoshin 		BUG_ON(!thread_msa_context_live());
476e4aa1f15SLeonid Yegoshin 
477e4aa1f15SLeonid Yegoshin 		df = insn.msa_mi10_format.df;
478e4aa1f15SLeonid Yegoshin 		wd = insn.msa_mi10_format.wd;
479e4aa1f15SLeonid Yegoshin 		fpr = &current->thread.fpu.fpr[wd];
480e4aa1f15SLeonid Yegoshin 
481e4aa1f15SLeonid Yegoshin 		switch (insn.msa_mi10_format.func) {
482e4aa1f15SLeonid Yegoshin 		case msa_ld_op:
48396d4f267SLinus Torvalds 			if (!access_ok(addr, sizeof(*fpr)))
484e4aa1f15SLeonid Yegoshin 				goto sigbus;
485e4aa1f15SLeonid Yegoshin 
486fa8ff601SPaul Burton 			do {
487e4aa1f15SLeonid Yegoshin 				/*
488fa8ff601SPaul Burton 				 * If we have live MSA context keep track of
489fa8ff601SPaul Burton 				 * whether we get preempted in order to avoid
490fa8ff601SPaul Burton 				 * the register context we load being clobbered
491fa8ff601SPaul Burton 				 * by the live context as it's saved during
492fa8ff601SPaul Burton 				 * preemption. If we don't have live context
493fa8ff601SPaul Burton 				 * then it can't be saved to clobber the value
494fa8ff601SPaul Burton 				 * we load.
495e4aa1f15SLeonid Yegoshin 				 */
496fa8ff601SPaul Burton 				preempted = test_thread_flag(TIF_USEDMSA);
497e4aa1f15SLeonid Yegoshin 
498e4aa1f15SLeonid Yegoshin 				res = __copy_from_user_inatomic(fpr, addr,
499e4aa1f15SLeonid Yegoshin 								sizeof(*fpr));
500e4aa1f15SLeonid Yegoshin 				if (res)
501e4aa1f15SLeonid Yegoshin 					goto fault;
502e4aa1f15SLeonid Yegoshin 
503e4aa1f15SLeonid Yegoshin 				/*
504fa8ff601SPaul Burton 				 * Update the hardware register if it is in use
505fa8ff601SPaul Burton 				 * by the task in this quantum, in order to
506fa8ff601SPaul Burton 				 * avoid having to save & restore the whole
507fa8ff601SPaul Burton 				 * vector context.
508e4aa1f15SLeonid Yegoshin 				 */
509fa8ff601SPaul Burton 				preempt_disable();
510fa8ff601SPaul Burton 				if (test_thread_flag(TIF_USEDMSA)) {
511e4aa1f15SLeonid Yegoshin 					write_msa_wr(wd, fpr, df);
512fa8ff601SPaul Burton 					preempted = 0;
513fa8ff601SPaul Burton 				}
514e4aa1f15SLeonid Yegoshin 				preempt_enable();
515fa8ff601SPaul Burton 			} while (preempted);
516e4aa1f15SLeonid Yegoshin 			break;
517e4aa1f15SLeonid Yegoshin 
518e4aa1f15SLeonid Yegoshin 		case msa_st_op:
51996d4f267SLinus Torvalds 			if (!access_ok(addr, sizeof(*fpr)))
520e4aa1f15SLeonid Yegoshin 				goto sigbus;
521e4aa1f15SLeonid Yegoshin 
522e4aa1f15SLeonid Yegoshin 			/*
523e4aa1f15SLeonid Yegoshin 			 * Update from the hardware register if it is in use by
524e4aa1f15SLeonid Yegoshin 			 * the task in this quantum, in order to avoid having to
525e4aa1f15SLeonid Yegoshin 			 * save & restore the whole vector context.
526e4aa1f15SLeonid Yegoshin 			 */
527e4aa1f15SLeonid Yegoshin 			preempt_disable();
528e4aa1f15SLeonid Yegoshin 			if (test_thread_flag(TIF_USEDMSA))
529e4aa1f15SLeonid Yegoshin 				read_msa_wr(wd, fpr, df);
530e4aa1f15SLeonid Yegoshin 			preempt_enable();
531e4aa1f15SLeonid Yegoshin 
532e4aa1f15SLeonid Yegoshin 			res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr));
533e4aa1f15SLeonid Yegoshin 			if (res)
534e4aa1f15SLeonid Yegoshin 				goto fault;
535e4aa1f15SLeonid Yegoshin 			break;
536e4aa1f15SLeonid Yegoshin 
537e4aa1f15SLeonid Yegoshin 		default:
538e4aa1f15SLeonid Yegoshin 			goto sigbus;
539e4aa1f15SLeonid Yegoshin 		}
540e4aa1f15SLeonid Yegoshin 
541e4aa1f15SLeonid Yegoshin 		compute_return_epc(regs);
542e4aa1f15SLeonid Yegoshin 		break;
54385164fd8SPaul Burton 	}
54485164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */
545e4aa1f15SLeonid Yegoshin 
5460593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
5471da177e4SLinus Torvalds 	/*
54869f3a7deSRalf Baechle 	 * COP2 is available to implementor for application specific use.
54969f3a7deSRalf Baechle 	 * It's up to applications to register a notifier chain and do
55069f3a7deSRalf Baechle 	 * whatever they have to do, including possible sending of signals.
5510593a44cSLeonid Yegoshin 	 *
5520593a44cSLeonid Yegoshin 	 * This instruction has been reallocated in Release 6
5531da177e4SLinus Torvalds 	 */
55469f3a7deSRalf Baechle 	case lwc2_op:
55569f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
55669f3a7deSRalf Baechle 		break;
55769f3a7deSRalf Baechle 
55869f3a7deSRalf Baechle 	case ldc2_op:
55969f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
56069f3a7deSRalf Baechle 		break;
56169f3a7deSRalf Baechle 
56269f3a7deSRalf Baechle 	case swc2_op:
56369f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
56469f3a7deSRalf Baechle 		break;
56569f3a7deSRalf Baechle 
56669f3a7deSRalf Baechle 	case sdc2_op:
56769f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
56869f3a7deSRalf Baechle 		break;
5690593a44cSLeonid Yegoshin #endif
5701da177e4SLinus Torvalds 	default:
5711da177e4SLinus Torvalds 		/*
5721da177e4SLinus Torvalds 		 * Pheeee...  We encountered an yet unknown instruction or
5731da177e4SLinus Torvalds 		 * cache coherence problem.  Die sucker, die ...
5741da177e4SLinus Torvalds 		 */
5751da177e4SLinus Torvalds 		goto sigill;
5761da177e4SLinus Torvalds 	}
5771da177e4SLinus Torvalds 
5786312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
5791da177e4SLinus Torvalds 	unaligned_instructions++;
5801da177e4SLinus Torvalds #endif
5811da177e4SLinus Torvalds 
5827f18f151SRalf Baechle 	return;
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds fault:
58534c2f668SLeonid Yegoshin 	/* roll back jump/branch */
58634c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
58734c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
5881da177e4SLinus Torvalds 	/* Did we have an exception handler installed? */
5891da177e4SLinus Torvalds 	if (fixup_exception(regs))
5907f18f151SRalf Baechle 		return;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
5933cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
5941da177e4SLinus Torvalds 
5957f18f151SRalf Baechle 	return;
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds sigbus:
5981da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
5993cf5d076SEric W. Biederman 	force_sig(SIGBUS);
6001da177e4SLinus Torvalds 
6017f18f151SRalf Baechle 	return;
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds sigill:
60434c2f668SLeonid Yegoshin 	die_if_kernel
60534c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
6063cf5d076SEric W. Biederman 	force_sig(SIGILL);
60734c2f668SLeonid Yegoshin }
60834c2f668SLeonid Yegoshin 
60934c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
61034c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
61134c2f668SLeonid Yegoshin 
61234c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
613b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
61434c2f668SLeonid Yegoshin 
emulate_load_store_microMIPS(struct pt_regs * regs,void __user * addr)61574338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
61674338805SDavid Daney 					 void __user *addr)
61734c2f668SLeonid Yegoshin {
61834c2f668SLeonid Yegoshin 	unsigned long value;
61934c2f668SLeonid Yegoshin 	unsigned int res;
62034c2f668SLeonid Yegoshin 	int i;
62134c2f668SLeonid Yegoshin 	unsigned int reg = 0, rvar;
62234c2f668SLeonid Yegoshin 	unsigned long orig31;
62334c2f668SLeonid Yegoshin 	u16 __user *pc16;
62434c2f668SLeonid Yegoshin 	u16 halfword;
62534c2f668SLeonid Yegoshin 	unsigned int word;
62634c2f668SLeonid Yegoshin 	unsigned long origpc, contpc;
62734c2f668SLeonid Yegoshin 	union mips_instruction insn;
62834c2f668SLeonid Yegoshin 	struct mm_decoded_insn mminsn;
62945deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
63034c2f668SLeonid Yegoshin 
63134c2f668SLeonid Yegoshin 	origpc = regs->cp0_epc;
63234c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
63334c2f668SLeonid Yegoshin 
63434c2f668SLeonid Yegoshin 	mminsn.micro_mips_mode = 1;
63534c2f668SLeonid Yegoshin 
63634c2f668SLeonid Yegoshin 	/*
63734c2f668SLeonid Yegoshin 	 * This load never faults.
63834c2f668SLeonid Yegoshin 	 */
63934c2f668SLeonid Yegoshin 	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
64034c2f668SLeonid Yegoshin 	__get_user(halfword, pc16);
64134c2f668SLeonid Yegoshin 	pc16++;
64234c2f668SLeonid Yegoshin 	contpc = regs->cp0_epc + 2;
64334c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
64434c2f668SLeonid Yegoshin 	mminsn.pc_inc = 2;
64534c2f668SLeonid Yegoshin 
64634c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
64734c2f668SLeonid Yegoshin 		__get_user(halfword, pc16);
64834c2f668SLeonid Yegoshin 		pc16++;
64934c2f668SLeonid Yegoshin 		contpc = regs->cp0_epc + 4;
65034c2f668SLeonid Yegoshin 		mminsn.pc_inc = 4;
65134c2f668SLeonid Yegoshin 		word |= halfword;
65234c2f668SLeonid Yegoshin 	}
65334c2f668SLeonid Yegoshin 	mminsn.insn = word;
65434c2f668SLeonid Yegoshin 
65534c2f668SLeonid Yegoshin 	if (get_user(halfword, pc16))
65634c2f668SLeonid Yegoshin 		goto fault;
65734c2f668SLeonid Yegoshin 	mminsn.next_pc_inc = 2;
65834c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
65934c2f668SLeonid Yegoshin 
66034c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
66134c2f668SLeonid Yegoshin 		pc16++;
66234c2f668SLeonid Yegoshin 		if (get_user(halfword, pc16))
66334c2f668SLeonid Yegoshin 			goto fault;
66434c2f668SLeonid Yegoshin 		mminsn.next_pc_inc = 4;
66534c2f668SLeonid Yegoshin 		word |= halfword;
66634c2f668SLeonid Yegoshin 	}
66734c2f668SLeonid Yegoshin 	mminsn.next_insn = word;
66834c2f668SLeonid Yegoshin 
66934c2f668SLeonid Yegoshin 	insn = (union mips_instruction)(mminsn.insn);
67034c2f668SLeonid Yegoshin 	if (mm_isBranchInstr(regs, mminsn, &contpc))
67134c2f668SLeonid Yegoshin 		insn = (union mips_instruction)(mminsn.next_insn);
67234c2f668SLeonid Yegoshin 
67334c2f668SLeonid Yegoshin 	/*  Parse instruction to find what to do */
67434c2f668SLeonid Yegoshin 
67534c2f668SLeonid Yegoshin 	switch (insn.mm_i_format.opcode) {
67634c2f668SLeonid Yegoshin 
67734c2f668SLeonid Yegoshin 	case mm_pool32a_op:
67834c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
67934c2f668SLeonid Yegoshin 		case mm_lwxs_op:
68034c2f668SLeonid Yegoshin 			reg = insn.mm_x_format.rd;
68134c2f668SLeonid Yegoshin 			goto loadW;
68234c2f668SLeonid Yegoshin 		}
68334c2f668SLeonid Yegoshin 
68434c2f668SLeonid Yegoshin 		goto sigbus;
68534c2f668SLeonid Yegoshin 
68634c2f668SLeonid Yegoshin 	case mm_pool32b_op:
68734c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
68834c2f668SLeonid Yegoshin 		case mm_lwp_func:
68934c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
69034c2f668SLeonid Yegoshin 			if (reg == 31)
69134c2f668SLeonid Yegoshin 				goto sigbus;
69234c2f668SLeonid Yegoshin 
69345deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 8))
69434c2f668SLeonid Yegoshin 				goto sigbus;
69534c2f668SLeonid Yegoshin 
69634c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
69734c2f668SLeonid Yegoshin 			if (res)
69834c2f668SLeonid Yegoshin 				goto fault;
69934c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
70034c2f668SLeonid Yegoshin 			addr += 4;
70134c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
70234c2f668SLeonid Yegoshin 			if (res)
70334c2f668SLeonid Yegoshin 				goto fault;
70434c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
70534c2f668SLeonid Yegoshin 			goto success;
70634c2f668SLeonid Yegoshin 
70734c2f668SLeonid Yegoshin 		case mm_swp_func:
70834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
70934c2f668SLeonid Yegoshin 			if (reg == 31)
71034c2f668SLeonid Yegoshin 				goto sigbus;
71134c2f668SLeonid Yegoshin 
71245deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 8))
71334c2f668SLeonid Yegoshin 				goto sigbus;
71434c2f668SLeonid Yegoshin 
71534c2f668SLeonid Yegoshin 			value = regs->regs[reg];
71634c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
71734c2f668SLeonid Yegoshin 			if (res)
71834c2f668SLeonid Yegoshin 				goto fault;
71934c2f668SLeonid Yegoshin 			addr += 4;
72034c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
72134c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
72234c2f668SLeonid Yegoshin 			if (res)
72334c2f668SLeonid Yegoshin 				goto fault;
72434c2f668SLeonid Yegoshin 			goto success;
72534c2f668SLeonid Yegoshin 
72634c2f668SLeonid Yegoshin 		case mm_ldp_func:
72734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
72834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
72934c2f668SLeonid Yegoshin 			if (reg == 31)
73034c2f668SLeonid Yegoshin 				goto sigbus;
73134c2f668SLeonid Yegoshin 
73245deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 16))
73334c2f668SLeonid Yegoshin 				goto sigbus;
73434c2f668SLeonid Yegoshin 
73534c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
73634c2f668SLeonid Yegoshin 			if (res)
73734c2f668SLeonid Yegoshin 				goto fault;
73834c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
73934c2f668SLeonid Yegoshin 			addr += 8;
74034c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
74134c2f668SLeonid Yegoshin 			if (res)
74234c2f668SLeonid Yegoshin 				goto fault;
74334c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
74434c2f668SLeonid Yegoshin 			goto success;
74534c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
74634c2f668SLeonid Yegoshin 
74734c2f668SLeonid Yegoshin 			goto sigill;
74834c2f668SLeonid Yegoshin 
74934c2f668SLeonid Yegoshin 		case mm_sdp_func:
75034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
75134c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
75234c2f668SLeonid Yegoshin 			if (reg == 31)
75334c2f668SLeonid Yegoshin 				goto sigbus;
75434c2f668SLeonid Yegoshin 
75545deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 16))
75634c2f668SLeonid Yegoshin 				goto sigbus;
75734c2f668SLeonid Yegoshin 
75834c2f668SLeonid Yegoshin 			value = regs->regs[reg];
75934c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
76034c2f668SLeonid Yegoshin 			if (res)
76134c2f668SLeonid Yegoshin 				goto fault;
76234c2f668SLeonid Yegoshin 			addr += 8;
76334c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
76434c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
76534c2f668SLeonid Yegoshin 			if (res)
76634c2f668SLeonid Yegoshin 				goto fault;
76734c2f668SLeonid Yegoshin 			goto success;
76834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
76934c2f668SLeonid Yegoshin 
77034c2f668SLeonid Yegoshin 			goto sigill;
77134c2f668SLeonid Yegoshin 
77234c2f668SLeonid Yegoshin 		case mm_lwm32_func:
77334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
77434c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
77534c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
77634c2f668SLeonid Yegoshin 				goto sigill;
77734c2f668SLeonid Yegoshin 			if (reg & 0x10) {
77845deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * (rvar + 1)))
77934c2f668SLeonid Yegoshin 					goto sigbus;
78034c2f668SLeonid Yegoshin 			} else {
78145deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * rvar))
78234c2f668SLeonid Yegoshin 					goto sigbus;
78334c2f668SLeonid Yegoshin 			}
78434c2f668SLeonid Yegoshin 			if (rvar == 9)
78534c2f668SLeonid Yegoshin 				rvar = 8;
78634c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
78734c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
78834c2f668SLeonid Yegoshin 				if (res)
78934c2f668SLeonid Yegoshin 					goto fault;
79034c2f668SLeonid Yegoshin 				addr += 4;
79134c2f668SLeonid Yegoshin 				regs->regs[i] = value;
79234c2f668SLeonid Yegoshin 			}
79334c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
79434c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
79534c2f668SLeonid Yegoshin 				if (res)
79634c2f668SLeonid Yegoshin 					goto fault;
79734c2f668SLeonid Yegoshin 				addr += 4;
79834c2f668SLeonid Yegoshin 				regs->regs[30] = value;
79934c2f668SLeonid Yegoshin 			}
80034c2f668SLeonid Yegoshin 			if (reg & 0x10) {
80134c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
80234c2f668SLeonid Yegoshin 				if (res)
80334c2f668SLeonid Yegoshin 					goto fault;
80434c2f668SLeonid Yegoshin 				regs->regs[31] = value;
80534c2f668SLeonid Yegoshin 			}
80634c2f668SLeonid Yegoshin 			goto success;
80734c2f668SLeonid Yegoshin 
80834c2f668SLeonid Yegoshin 		case mm_swm32_func:
80934c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
81034c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
81134c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
81234c2f668SLeonid Yegoshin 				goto sigill;
81334c2f668SLeonid Yegoshin 			if (reg & 0x10) {
81445deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * (rvar + 1)))
81534c2f668SLeonid Yegoshin 					goto sigbus;
81634c2f668SLeonid Yegoshin 			} else {
81745deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 4 * rvar))
81834c2f668SLeonid Yegoshin 					goto sigbus;
81934c2f668SLeonid Yegoshin 			}
82034c2f668SLeonid Yegoshin 			if (rvar == 9)
82134c2f668SLeonid Yegoshin 				rvar = 8;
82234c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
82334c2f668SLeonid Yegoshin 				value = regs->regs[i];
82434c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
82534c2f668SLeonid Yegoshin 				if (res)
82634c2f668SLeonid Yegoshin 					goto fault;
82734c2f668SLeonid Yegoshin 				addr += 4;
82834c2f668SLeonid Yegoshin 			}
82934c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
83034c2f668SLeonid Yegoshin 				value = regs->regs[30];
83134c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
83234c2f668SLeonid Yegoshin 				if (res)
83334c2f668SLeonid Yegoshin 					goto fault;
83434c2f668SLeonid Yegoshin 				addr += 4;
83534c2f668SLeonid Yegoshin 			}
83634c2f668SLeonid Yegoshin 			if (reg & 0x10) {
83734c2f668SLeonid Yegoshin 				value = regs->regs[31];
83834c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
83934c2f668SLeonid Yegoshin 				if (res)
84034c2f668SLeonid Yegoshin 					goto fault;
84134c2f668SLeonid Yegoshin 			}
84234c2f668SLeonid Yegoshin 			goto success;
84334c2f668SLeonid Yegoshin 
84434c2f668SLeonid Yegoshin 		case mm_ldm_func:
84534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
84634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
84734c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
84834c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
84934c2f668SLeonid Yegoshin 				goto sigill;
85034c2f668SLeonid Yegoshin 			if (reg & 0x10) {
85145deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * (rvar + 1)))
85234c2f668SLeonid Yegoshin 					goto sigbus;
85334c2f668SLeonid Yegoshin 			} else {
85445deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * rvar))
85534c2f668SLeonid Yegoshin 					goto sigbus;
85634c2f668SLeonid Yegoshin 			}
85734c2f668SLeonid Yegoshin 			if (rvar == 9)
85834c2f668SLeonid Yegoshin 				rvar = 8;
85934c2f668SLeonid Yegoshin 
86034c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
86134c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
86234c2f668SLeonid Yegoshin 				if (res)
86334c2f668SLeonid Yegoshin 					goto fault;
86434c2f668SLeonid Yegoshin 				addr += 4;
86534c2f668SLeonid Yegoshin 				regs->regs[i] = value;
86634c2f668SLeonid Yegoshin 			}
86734c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
86834c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
86934c2f668SLeonid Yegoshin 				if (res)
87034c2f668SLeonid Yegoshin 					goto fault;
87134c2f668SLeonid Yegoshin 				addr += 8;
87234c2f668SLeonid Yegoshin 				regs->regs[30] = value;
87334c2f668SLeonid Yegoshin 			}
87434c2f668SLeonid Yegoshin 			if (reg & 0x10) {
87534c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
87634c2f668SLeonid Yegoshin 				if (res)
87734c2f668SLeonid Yegoshin 					goto fault;
87834c2f668SLeonid Yegoshin 				regs->regs[31] = value;
87934c2f668SLeonid Yegoshin 			}
88034c2f668SLeonid Yegoshin 			goto success;
88134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
88234c2f668SLeonid Yegoshin 
88334c2f668SLeonid Yegoshin 			goto sigill;
88434c2f668SLeonid Yegoshin 
88534c2f668SLeonid Yegoshin 		case mm_sdm_func:
88634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
88734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
88834c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
88934c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
89034c2f668SLeonid Yegoshin 				goto sigill;
89134c2f668SLeonid Yegoshin 			if (reg & 0x10) {
89245deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * (rvar + 1)))
89334c2f668SLeonid Yegoshin 					goto sigbus;
89434c2f668SLeonid Yegoshin 			} else {
89545deb5faSThomas Bogendoerfer 				if (user && !access_ok(addr, 8 * rvar))
89634c2f668SLeonid Yegoshin 					goto sigbus;
89734c2f668SLeonid Yegoshin 			}
89834c2f668SLeonid Yegoshin 			if (rvar == 9)
89934c2f668SLeonid Yegoshin 				rvar = 8;
90034c2f668SLeonid Yegoshin 
90134c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
90234c2f668SLeonid Yegoshin 				value = regs->regs[i];
90334c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
90434c2f668SLeonid Yegoshin 				if (res)
90534c2f668SLeonid Yegoshin 					goto fault;
90634c2f668SLeonid Yegoshin 				addr += 8;
90734c2f668SLeonid Yegoshin 			}
90834c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
90934c2f668SLeonid Yegoshin 				value = regs->regs[30];
91034c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
91134c2f668SLeonid Yegoshin 				if (res)
91234c2f668SLeonid Yegoshin 					goto fault;
91334c2f668SLeonid Yegoshin 				addr += 8;
91434c2f668SLeonid Yegoshin 			}
91534c2f668SLeonid Yegoshin 			if (reg & 0x10) {
91634c2f668SLeonid Yegoshin 				value = regs->regs[31];
91734c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
91834c2f668SLeonid Yegoshin 				if (res)
91934c2f668SLeonid Yegoshin 					goto fault;
92034c2f668SLeonid Yegoshin 			}
92134c2f668SLeonid Yegoshin 			goto success;
92234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
92334c2f668SLeonid Yegoshin 
92434c2f668SLeonid Yegoshin 			goto sigill;
92534c2f668SLeonid Yegoshin 
92634c2f668SLeonid Yegoshin 			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
92734c2f668SLeonid Yegoshin 		}
92834c2f668SLeonid Yegoshin 
92934c2f668SLeonid Yegoshin 		goto sigbus;
93034c2f668SLeonid Yegoshin 
93134c2f668SLeonid Yegoshin 	case mm_pool32c_op:
93234c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
93334c2f668SLeonid Yegoshin 		case mm_lwu_func:
93434c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
93534c2f668SLeonid Yegoshin 			goto loadWU;
93634c2f668SLeonid Yegoshin 		}
93734c2f668SLeonid Yegoshin 
93834c2f668SLeonid Yegoshin 		/*  LL,SC,LLD,SCD are not serviced */
93934c2f668SLeonid Yegoshin 		goto sigbus;
94034c2f668SLeonid Yegoshin 
94185164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
94234c2f668SLeonid Yegoshin 	case mm_pool32f_op:
94334c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
94434c2f668SLeonid Yegoshin 		case mm_lwxc1_func:
94534c2f668SLeonid Yegoshin 		case mm_swxc1_func:
94634c2f668SLeonid Yegoshin 		case mm_ldxc1_func:
94734c2f668SLeonid Yegoshin 		case mm_sdxc1_func:
94834c2f668SLeonid Yegoshin 			goto fpu_emul;
94934c2f668SLeonid Yegoshin 		}
95034c2f668SLeonid Yegoshin 
95134c2f668SLeonid Yegoshin 		goto sigbus;
95234c2f668SLeonid Yegoshin 
95334c2f668SLeonid Yegoshin 	case mm_ldc132_op:
95434c2f668SLeonid Yegoshin 	case mm_sdc132_op:
95534c2f668SLeonid Yegoshin 	case mm_lwc132_op:
95685164fd8SPaul Burton 	case mm_swc132_op: {
95785164fd8SPaul Burton 		void __user *fault_addr = NULL;
95885164fd8SPaul Burton 
95934c2f668SLeonid Yegoshin fpu_emul:
96034c2f668SLeonid Yegoshin 		/* roll back jump/branch */
96134c2f668SLeonid Yegoshin 		regs->cp0_epc = origpc;
96234c2f668SLeonid Yegoshin 		regs->regs[31] = orig31;
96334c2f668SLeonid Yegoshin 
96434c2f668SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
96534c2f668SLeonid Yegoshin 		BUG_ON(!used_math());
96634c2f668SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
96734c2f668SLeonid Yegoshin 
96834c2f668SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
96934c2f668SLeonid Yegoshin 					       &fault_addr);
97034c2f668SLeonid Yegoshin 		own_fpu(1);	/* restore FPU state */
97134c2f668SLeonid Yegoshin 
97234c2f668SLeonid Yegoshin 		/* If something went wrong, signal */
973304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
97434c2f668SLeonid Yegoshin 
97534c2f668SLeonid Yegoshin 		if (res == 0)
97634c2f668SLeonid Yegoshin 			goto success;
97734c2f668SLeonid Yegoshin 		return;
97885164fd8SPaul Burton 	}
97985164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
98034c2f668SLeonid Yegoshin 
98134c2f668SLeonid Yegoshin 	case mm_lh32_op:
98234c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
98334c2f668SLeonid Yegoshin 		goto loadHW;
98434c2f668SLeonid Yegoshin 
98534c2f668SLeonid Yegoshin 	case mm_lhu32_op:
98634c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
98734c2f668SLeonid Yegoshin 		goto loadHWU;
98834c2f668SLeonid Yegoshin 
98934c2f668SLeonid Yegoshin 	case mm_lw32_op:
99034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
99134c2f668SLeonid Yegoshin 		goto loadW;
99234c2f668SLeonid Yegoshin 
99334c2f668SLeonid Yegoshin 	case mm_sh32_op:
99434c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
99534c2f668SLeonid Yegoshin 		goto storeHW;
99634c2f668SLeonid Yegoshin 
99734c2f668SLeonid Yegoshin 	case mm_sw32_op:
99834c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
99934c2f668SLeonid Yegoshin 		goto storeW;
100034c2f668SLeonid Yegoshin 
100134c2f668SLeonid Yegoshin 	case mm_ld32_op:
100234c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
100334c2f668SLeonid Yegoshin 		goto loadDW;
100434c2f668SLeonid Yegoshin 
100534c2f668SLeonid Yegoshin 	case mm_sd32_op:
100634c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
100734c2f668SLeonid Yegoshin 		goto storeDW;
100834c2f668SLeonid Yegoshin 
100934c2f668SLeonid Yegoshin 	case mm_pool16c_op:
101034c2f668SLeonid Yegoshin 		switch (insn.mm16_m_format.func) {
101134c2f668SLeonid Yegoshin 		case mm_lwm16_op:
101234c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
101334c2f668SLeonid Yegoshin 			rvar = reg + 1;
101445deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 4 * rvar))
101534c2f668SLeonid Yegoshin 				goto sigbus;
101634c2f668SLeonid Yegoshin 
101734c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
101834c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
101934c2f668SLeonid Yegoshin 				if (res)
102034c2f668SLeonid Yegoshin 					goto fault;
102134c2f668SLeonid Yegoshin 				addr += 4;
102234c2f668SLeonid Yegoshin 				regs->regs[i] = value;
102334c2f668SLeonid Yegoshin 			}
102434c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
102534c2f668SLeonid Yegoshin 			if (res)
102634c2f668SLeonid Yegoshin 				goto fault;
102734c2f668SLeonid Yegoshin 			regs->regs[31] = value;
102834c2f668SLeonid Yegoshin 
102934c2f668SLeonid Yegoshin 			goto success;
103034c2f668SLeonid Yegoshin 
103134c2f668SLeonid Yegoshin 		case mm_swm16_op:
103234c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
103334c2f668SLeonid Yegoshin 			rvar = reg + 1;
103445deb5faSThomas Bogendoerfer 			if (user && !access_ok(addr, 4 * rvar))
103534c2f668SLeonid Yegoshin 				goto sigbus;
103634c2f668SLeonid Yegoshin 
103734c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
103834c2f668SLeonid Yegoshin 				value = regs->regs[i];
103934c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
104034c2f668SLeonid Yegoshin 				if (res)
104134c2f668SLeonid Yegoshin 					goto fault;
104234c2f668SLeonid Yegoshin 				addr += 4;
104334c2f668SLeonid Yegoshin 			}
104434c2f668SLeonid Yegoshin 			value = regs->regs[31];
104534c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
104634c2f668SLeonid Yegoshin 			if (res)
104734c2f668SLeonid Yegoshin 				goto fault;
104834c2f668SLeonid Yegoshin 
104934c2f668SLeonid Yegoshin 			goto success;
105034c2f668SLeonid Yegoshin 
105134c2f668SLeonid Yegoshin 		}
105234c2f668SLeonid Yegoshin 
105334c2f668SLeonid Yegoshin 		goto sigbus;
105434c2f668SLeonid Yegoshin 
105534c2f668SLeonid Yegoshin 	case mm_lhu16_op:
105634c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
105734c2f668SLeonid Yegoshin 		goto loadHWU;
105834c2f668SLeonid Yegoshin 
105934c2f668SLeonid Yegoshin 	case mm_lw16_op:
106034c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
106134c2f668SLeonid Yegoshin 		goto loadW;
106234c2f668SLeonid Yegoshin 
106334c2f668SLeonid Yegoshin 	case mm_sh16_op:
106434c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
106534c2f668SLeonid Yegoshin 		goto storeHW;
106634c2f668SLeonid Yegoshin 
106734c2f668SLeonid Yegoshin 	case mm_sw16_op:
106834c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
106934c2f668SLeonid Yegoshin 		goto storeW;
107034c2f668SLeonid Yegoshin 
107134c2f668SLeonid Yegoshin 	case mm_lwsp16_op:
107234c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
107334c2f668SLeonid Yegoshin 		goto loadW;
107434c2f668SLeonid Yegoshin 
107534c2f668SLeonid Yegoshin 	case mm_swsp16_op:
107634c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
107734c2f668SLeonid Yegoshin 		goto storeW;
107834c2f668SLeonid Yegoshin 
107934c2f668SLeonid Yegoshin 	case mm_lwgp16_op:
108034c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_r3_format.rt];
108134c2f668SLeonid Yegoshin 		goto loadW;
108234c2f668SLeonid Yegoshin 
108334c2f668SLeonid Yegoshin 	default:
108434c2f668SLeonid Yegoshin 		goto sigill;
108534c2f668SLeonid Yegoshin 	}
108634c2f668SLeonid Yegoshin 
108734c2f668SLeonid Yegoshin loadHW:
108845deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
108934c2f668SLeonid Yegoshin 		goto sigbus;
109034c2f668SLeonid Yegoshin 
109134c2f668SLeonid Yegoshin 	LoadHW(addr, value, res);
109234c2f668SLeonid Yegoshin 	if (res)
109334c2f668SLeonid Yegoshin 		goto fault;
109434c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
109534c2f668SLeonid Yegoshin 	goto success;
109634c2f668SLeonid Yegoshin 
109734c2f668SLeonid Yegoshin loadHWU:
109845deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
109934c2f668SLeonid Yegoshin 		goto sigbus;
110034c2f668SLeonid Yegoshin 
110134c2f668SLeonid Yegoshin 	LoadHWU(addr, value, res);
110234c2f668SLeonid Yegoshin 	if (res)
110334c2f668SLeonid Yegoshin 		goto fault;
110434c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
110534c2f668SLeonid Yegoshin 	goto success;
110634c2f668SLeonid Yegoshin 
110734c2f668SLeonid Yegoshin loadW:
110845deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
110934c2f668SLeonid Yegoshin 		goto sigbus;
111034c2f668SLeonid Yegoshin 
111134c2f668SLeonid Yegoshin 	LoadW(addr, value, res);
111234c2f668SLeonid Yegoshin 	if (res)
111334c2f668SLeonid Yegoshin 		goto fault;
111434c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
111534c2f668SLeonid Yegoshin 	goto success;
111634c2f668SLeonid Yegoshin 
111734c2f668SLeonid Yegoshin loadWU:
111834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
111934c2f668SLeonid Yegoshin 	/*
112034c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
112134c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
112234c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
112334c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
112434c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
112534c2f668SLeonid Yegoshin 	 */
112645deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
112734c2f668SLeonid Yegoshin 		goto sigbus;
112834c2f668SLeonid Yegoshin 
112934c2f668SLeonid Yegoshin 	LoadWU(addr, value, res);
113034c2f668SLeonid Yegoshin 	if (res)
113134c2f668SLeonid Yegoshin 		goto fault;
113234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
113334c2f668SLeonid Yegoshin 	goto success;
113434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
113534c2f668SLeonid Yegoshin 
113634c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
113734c2f668SLeonid Yegoshin 	goto sigill;
113834c2f668SLeonid Yegoshin 
113934c2f668SLeonid Yegoshin loadDW:
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 	LoadDW(addr, value, res);
115234c2f668SLeonid Yegoshin 	if (res)
115334c2f668SLeonid Yegoshin 		goto fault;
115434c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
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 storeHW:
116245deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 2))
116334c2f668SLeonid Yegoshin 		goto sigbus;
116434c2f668SLeonid Yegoshin 
116534c2f668SLeonid Yegoshin 	value = regs->regs[reg];
116634c2f668SLeonid Yegoshin 	StoreHW(addr, value, res);
116734c2f668SLeonid Yegoshin 	if (res)
116834c2f668SLeonid Yegoshin 		goto fault;
116934c2f668SLeonid Yegoshin 	goto success;
117034c2f668SLeonid Yegoshin 
117134c2f668SLeonid Yegoshin storeW:
117245deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 4))
117334c2f668SLeonid Yegoshin 		goto sigbus;
117434c2f668SLeonid Yegoshin 
117534c2f668SLeonid Yegoshin 	value = regs->regs[reg];
117634c2f668SLeonid Yegoshin 	StoreW(addr, value, res);
117734c2f668SLeonid Yegoshin 	if (res)
117834c2f668SLeonid Yegoshin 		goto fault;
117934c2f668SLeonid Yegoshin 	goto success;
118034c2f668SLeonid Yegoshin 
118134c2f668SLeonid Yegoshin storeDW:
118234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
118334c2f668SLeonid Yegoshin 	/*
118434c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
118534c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
118634c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
118734c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
118834c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
118934c2f668SLeonid Yegoshin 	 */
119045deb5faSThomas Bogendoerfer 	if (user && !access_ok(addr, 8))
119134c2f668SLeonid Yegoshin 		goto sigbus;
119234c2f668SLeonid Yegoshin 
119334c2f668SLeonid Yegoshin 	value = regs->regs[reg];
119434c2f668SLeonid Yegoshin 	StoreDW(addr, value, res);
119534c2f668SLeonid Yegoshin 	if (res)
119634c2f668SLeonid Yegoshin 		goto fault;
119734c2f668SLeonid Yegoshin 	goto success;
119834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
119934c2f668SLeonid Yegoshin 
120034c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
120134c2f668SLeonid Yegoshin 	goto sigill;
120234c2f668SLeonid Yegoshin 
120334c2f668SLeonid Yegoshin success:
120434c2f668SLeonid Yegoshin 	regs->cp0_epc = contpc;	/* advance or branch */
120534c2f668SLeonid Yegoshin 
120634c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
120734c2f668SLeonid Yegoshin 	unaligned_instructions++;
120834c2f668SLeonid Yegoshin #endif
120934c2f668SLeonid Yegoshin 	return;
121034c2f668SLeonid Yegoshin 
121134c2f668SLeonid Yegoshin fault:
121234c2f668SLeonid Yegoshin 	/* roll back jump/branch */
121334c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
121434c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
121534c2f668SLeonid Yegoshin 	/* Did we have an exception handler installed? */
121634c2f668SLeonid Yegoshin 	if (fixup_exception(regs))
121734c2f668SLeonid Yegoshin 		return;
121834c2f668SLeonid Yegoshin 
121934c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
12203cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
122134c2f668SLeonid Yegoshin 
122234c2f668SLeonid Yegoshin 	return;
122334c2f668SLeonid Yegoshin 
122434c2f668SLeonid Yegoshin sigbus:
122534c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
12263cf5d076SEric W. Biederman 	force_sig(SIGBUS);
122734c2f668SLeonid Yegoshin 
122834c2f668SLeonid Yegoshin 	return;
122934c2f668SLeonid Yegoshin 
123034c2f668SLeonid Yegoshin sigill:
123134c2f668SLeonid Yegoshin 	die_if_kernel
123234c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
12333cf5d076SEric W. Biederman 	force_sig(SIGILL);
12341da177e4SLinus Torvalds }
12351da177e4SLinus Torvalds 
emulate_load_store_MIPS16e(struct pt_regs * regs,void __user * addr)1236451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1237451b001bSSteven J. Hill {
1238451b001bSSteven J. Hill 	unsigned long value;
1239451b001bSSteven J. Hill 	unsigned int res;
1240451b001bSSteven J. Hill 	int reg;
1241451b001bSSteven J. Hill 	unsigned long orig31;
1242451b001bSSteven J. Hill 	u16 __user *pc16;
1243451b001bSSteven J. Hill 	unsigned long origpc;
1244451b001bSSteven J. Hill 	union mips16e_instruction mips16inst, oldinst;
1245f3235d32SMaciej W. Rozycki 	unsigned int opcode;
1246f3235d32SMaciej W. Rozycki 	int extended = 0;
124745deb5faSThomas Bogendoerfer 	bool user = user_mode(regs);
1248451b001bSSteven J. Hill 
1249451b001bSSteven J. Hill 	origpc = regs->cp0_epc;
1250451b001bSSteven J. Hill 	orig31 = regs->regs[31];
1251451b001bSSteven J. Hill 	pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1252451b001bSSteven J. Hill 	/*
1253451b001bSSteven J. Hill 	 * This load never faults.
1254451b001bSSteven J. Hill 	 */
1255451b001bSSteven J. Hill 	__get_user(mips16inst.full, pc16);
1256451b001bSSteven J. Hill 	oldinst = mips16inst;
1257451b001bSSteven J. Hill 
1258451b001bSSteven J. Hill 	/* skip EXTEND instruction */
1259451b001bSSteven J. Hill 	if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1260f3235d32SMaciej W. Rozycki 		extended = 1;
1261451b001bSSteven J. Hill 		pc16++;
1262451b001bSSteven J. Hill 		__get_user(mips16inst.full, pc16);
1263451b001bSSteven J. Hill 	} else if (delay_slot(regs)) {
1264451b001bSSteven J. Hill 		/*  skip jump instructions */
1265451b001bSSteven J. Hill 		/*  JAL/JALX are 32 bits but have OPCODE in first short int */
1266451b001bSSteven J. Hill 		if (mips16inst.ri.opcode == MIPS16e_jal_op)
1267451b001bSSteven J. Hill 			pc16++;
1268451b001bSSteven J. Hill 		pc16++;
1269451b001bSSteven J. Hill 		if (get_user(mips16inst.full, pc16))
1270451b001bSSteven J. Hill 			goto sigbus;
1271451b001bSSteven J. Hill 	}
1272451b001bSSteven J. Hill 
1273f3235d32SMaciej W. Rozycki 	opcode = mips16inst.ri.opcode;
1274f3235d32SMaciej W. Rozycki 	switch (opcode) {
1275451b001bSSteven J. Hill 	case MIPS16e_i64_op:	/* I64 or RI64 instruction */
1276451b001bSSteven J. Hill 		switch (mips16inst.i64.func) {	/* I64/RI64 func field check */
1277451b001bSSteven J. Hill 		case MIPS16e_ldpc_func:
1278451b001bSSteven J. Hill 		case MIPS16e_ldsp_func:
1279451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1280451b001bSSteven J. Hill 			goto loadDW;
1281451b001bSSteven J. Hill 
1282451b001bSSteven J. Hill 		case MIPS16e_sdsp_func:
1283451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1284451b001bSSteven J. Hill 			goto writeDW;
1285451b001bSSteven J. Hill 
1286451b001bSSteven J. Hill 		case MIPS16e_sdrasp_func:
1287451b001bSSteven J. Hill 			reg = 29;	/* GPRSP */
1288451b001bSSteven J. Hill 			goto writeDW;
1289451b001bSSteven J. Hill 		}
1290451b001bSSteven J. Hill 
1291451b001bSSteven J. Hill 		goto sigbus;
1292451b001bSSteven J. Hill 
1293451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1294f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
1295f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
1296f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
1297f3235d32SMaciej W. Rozycki 			case 0:		/* SWSP */
1298f3235d32SMaciej W. Rozycki 			case 1:		/* SWGP */
1299f3235d32SMaciej W. Rozycki 				break;
1300f3235d32SMaciej W. Rozycki 			case 2:		/* SHGP */
1301f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_sh_op;
1302f3235d32SMaciej W. Rozycki 				break;
1303f3235d32SMaciej W. Rozycki 			default:
1304f3235d32SMaciej W. Rozycki 				goto sigbus;
1305f3235d32SMaciej W. Rozycki 			}
1306f3235d32SMaciej W. Rozycki 		break;
1307f3235d32SMaciej W. Rozycki 
1308451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1309f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
1310f3235d32SMaciej W. Rozycki 		break;
1311f3235d32SMaciej W. Rozycki 
1312451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1313451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.ri.rx];
1314f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
1315f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
1316f3235d32SMaciej W. Rozycki 			case 0:		/* LWSP */
1317f3235d32SMaciej W. Rozycki 			case 1:		/* LWGP */
1318f3235d32SMaciej W. Rozycki 				break;
1319f3235d32SMaciej W. Rozycki 			case 2:		/* LHGP */
1320f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lh_op;
1321f3235d32SMaciej W. Rozycki 				break;
1322f3235d32SMaciej W. Rozycki 			case 4:		/* LHUGP */
1323f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lhu_op;
1324f3235d32SMaciej W. Rozycki 				break;
1325f3235d32SMaciej W. Rozycki 			default:
1326f3235d32SMaciej W. Rozycki 				goto sigbus;
1327f3235d32SMaciej W. Rozycki 			}
1328451b001bSSteven J. Hill 		break;
1329451b001bSSteven J. Hill 
1330451b001bSSteven J. Hill 	case MIPS16e_i8_op:
1331451b001bSSteven J. Hill 		if (mips16inst.i8.func != MIPS16e_swrasp_func)
1332451b001bSSteven J. Hill 			goto sigbus;
1333451b001bSSteven J. Hill 		reg = 29;	/* GPRSP */
1334451b001bSSteven J. Hill 		break;
1335451b001bSSteven J. Hill 
1336451b001bSSteven J. Hill 	default:
1337451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.rri.ry];
1338451b001bSSteven J. Hill 		break;
1339451b001bSSteven J. Hill 	}
1340451b001bSSteven J. Hill 
1341f3235d32SMaciej W. Rozycki 	switch (opcode) {
1342451b001bSSteven J. Hill 
1343451b001bSSteven J. Hill 	case MIPS16e_lb_op:
1344451b001bSSteven J. Hill 	case MIPS16e_lbu_op:
1345451b001bSSteven J. Hill 	case MIPS16e_sb_op:
1346451b001bSSteven J. Hill 		goto sigbus;
1347451b001bSSteven J. Hill 
1348451b001bSSteven J. Hill 	case MIPS16e_lh_op:
134945deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1350451b001bSSteven J. Hill 			goto sigbus;
1351451b001bSSteven J. Hill 
1352451b001bSSteven J. Hill 		LoadHW(addr, value, res);
1353451b001bSSteven J. Hill 		if (res)
1354451b001bSSteven J. Hill 			goto fault;
1355451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1356451b001bSSteven J. Hill 		regs->regs[reg] = value;
1357451b001bSSteven J. Hill 		break;
1358451b001bSSteven J. Hill 
1359451b001bSSteven J. Hill 	case MIPS16e_lhu_op:
136045deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1361451b001bSSteven J. Hill 			goto sigbus;
1362451b001bSSteven J. Hill 
1363451b001bSSteven J. Hill 		LoadHWU(addr, value, res);
1364451b001bSSteven J. Hill 		if (res)
1365451b001bSSteven J. Hill 			goto fault;
1366451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1367451b001bSSteven J. Hill 		regs->regs[reg] = value;
1368451b001bSSteven J. Hill 		break;
1369451b001bSSteven J. Hill 
1370451b001bSSteven J. Hill 	case MIPS16e_lw_op:
1371451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1372451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
137345deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1374451b001bSSteven J. Hill 			goto sigbus;
1375451b001bSSteven J. Hill 
1376451b001bSSteven J. Hill 		LoadW(addr, value, res);
1377451b001bSSteven J. Hill 		if (res)
1378451b001bSSteven J. Hill 			goto fault;
1379451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1380451b001bSSteven J. Hill 		regs->regs[reg] = value;
1381451b001bSSteven J. Hill 		break;
1382451b001bSSteven J. Hill 
1383451b001bSSteven J. Hill 	case MIPS16e_lwu_op:
1384451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1385451b001bSSteven J. Hill 		/*
1386451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1387451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1388451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1389451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1390451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1391451b001bSSteven J. Hill 		 */
139245deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1393451b001bSSteven J. Hill 			goto sigbus;
1394451b001bSSteven J. Hill 
1395451b001bSSteven J. Hill 		LoadWU(addr, value, res);
1396451b001bSSteven J. Hill 		if (res)
1397451b001bSSteven J. Hill 			goto fault;
1398451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1399451b001bSSteven J. Hill 		regs->regs[reg] = value;
1400451b001bSSteven J. Hill 		break;
1401451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1402451b001bSSteven J. Hill 
1403451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1404451b001bSSteven J. Hill 		goto sigill;
1405451b001bSSteven J. Hill 
1406451b001bSSteven J. Hill 	case MIPS16e_ld_op:
1407451b001bSSteven J. Hill loadDW:
1408451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1409451b001bSSteven J. Hill 		/*
1410451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1411451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1412451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1413451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1414451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1415451b001bSSteven J. Hill 		 */
141645deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
1417451b001bSSteven J. Hill 			goto sigbus;
1418451b001bSSteven J. Hill 
1419451b001bSSteven J. Hill 		LoadDW(addr, value, res);
1420451b001bSSteven J. Hill 		if (res)
1421451b001bSSteven J. Hill 			goto fault;
1422451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1423451b001bSSteven J. Hill 		regs->regs[reg] = value;
1424451b001bSSteven J. Hill 		break;
1425451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1426451b001bSSteven J. Hill 
1427451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1428451b001bSSteven J. Hill 		goto sigill;
1429451b001bSSteven J. Hill 
1430451b001bSSteven J. Hill 	case MIPS16e_sh_op:
143145deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 2))
1432451b001bSSteven J. Hill 			goto sigbus;
1433451b001bSSteven J. Hill 
1434451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1435451b001bSSteven J. Hill 		value = regs->regs[reg];
1436451b001bSSteven J. Hill 		StoreHW(addr, value, res);
1437451b001bSSteven J. Hill 		if (res)
1438451b001bSSteven J. Hill 			goto fault;
1439451b001bSSteven J. Hill 		break;
1440451b001bSSteven J. Hill 
1441451b001bSSteven J. Hill 	case MIPS16e_sw_op:
1442451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1443451b001bSSteven J. Hill 	case MIPS16e_i8_op:	/* actually - MIPS16e_swrasp_func */
144445deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 4))
1445451b001bSSteven J. Hill 			goto sigbus;
1446451b001bSSteven J. Hill 
1447451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1448451b001bSSteven J. Hill 		value = regs->regs[reg];
1449451b001bSSteven J. Hill 		StoreW(addr, value, res);
1450451b001bSSteven J. Hill 		if (res)
1451451b001bSSteven J. Hill 			goto fault;
1452451b001bSSteven J. Hill 		break;
1453451b001bSSteven J. Hill 
1454451b001bSSteven J. Hill 	case MIPS16e_sd_op:
1455451b001bSSteven J. Hill writeDW:
1456451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1457451b001bSSteven J. Hill 		/*
1458451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1459451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1460451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1461451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1462451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1463451b001bSSteven J. Hill 		 */
146445deb5faSThomas Bogendoerfer 		if (user && !access_ok(addr, 8))
1465451b001bSSteven J. Hill 			goto sigbus;
1466451b001bSSteven J. Hill 
1467451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1468451b001bSSteven J. Hill 		value = regs->regs[reg];
1469451b001bSSteven J. Hill 		StoreDW(addr, value, res);
1470451b001bSSteven J. Hill 		if (res)
1471451b001bSSteven J. Hill 			goto fault;
1472451b001bSSteven J. Hill 		break;
1473451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1474451b001bSSteven J. Hill 
1475451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1476451b001bSSteven J. Hill 		goto sigill;
1477451b001bSSteven J. Hill 
1478451b001bSSteven J. Hill 	default:
1479451b001bSSteven J. Hill 		/*
1480451b001bSSteven J. Hill 		 * Pheeee...  We encountered an yet unknown instruction or
1481451b001bSSteven J. Hill 		 * cache coherence problem.  Die sucker, die ...
1482451b001bSSteven J. Hill 		 */
1483451b001bSSteven J. Hill 		goto sigill;
1484451b001bSSteven J. Hill 	}
1485451b001bSSteven J. Hill 
1486451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
1487451b001bSSteven J. Hill 	unaligned_instructions++;
1488451b001bSSteven J. Hill #endif
1489451b001bSSteven J. Hill 
1490451b001bSSteven J. Hill 	return;
1491451b001bSSteven J. Hill 
1492451b001bSSteven J. Hill fault:
1493451b001bSSteven J. Hill 	/* roll back jump/branch */
1494451b001bSSteven J. Hill 	regs->cp0_epc = origpc;
1495451b001bSSteven J. Hill 	regs->regs[31] = orig31;
1496451b001bSSteven J. Hill 	/* Did we have an exception handler installed? */
1497451b001bSSteven J. Hill 	if (fixup_exception(regs))
1498451b001bSSteven J. Hill 		return;
1499451b001bSSteven J. Hill 
1500451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
15013cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
1502451b001bSSteven J. Hill 
1503451b001bSSteven J. Hill 	return;
1504451b001bSSteven J. Hill 
1505451b001bSSteven J. Hill sigbus:
1506451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
15073cf5d076SEric W. Biederman 	force_sig(SIGBUS);
1508451b001bSSteven J. Hill 
1509451b001bSSteven J. Hill 	return;
1510451b001bSSteven J. Hill 
1511451b001bSSteven J. Hill sigill:
1512451b001bSSteven J. Hill 	die_if_kernel
1513451b001bSSteven J. Hill 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
15143cf5d076SEric W. Biederman 	force_sig(SIGILL);
1515451b001bSSteven J. Hill }
1516fc192e50STony Wu 
do_ade(struct pt_regs * regs)15171da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
15181da177e4SLinus Torvalds {
1519c3fc5cd5SRalf Baechle 	enum ctx_state prev_state;
15207cba4128SThomas Bogendoerfer 	unsigned int *pc;
15211da177e4SLinus Torvalds 
1522c3fc5cd5SRalf Baechle 	prev_state = exception_enter();
15237f788d2dSDeng-Cheng Zhu 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1524a8b0ca17SPeter Zijlstra 			1, regs, regs->cp0_badvaddr);
1525429124d9SThomas Bogendoerfer 
1526429124d9SThomas Bogendoerfer #ifdef CONFIG_64BIT
1527429124d9SThomas Bogendoerfer 	/*
1528429124d9SThomas Bogendoerfer 	 * check, if we are hitting space between CPU implemented maximum
1529429124d9SThomas Bogendoerfer 	 * virtual user address and 64bit maximum virtual user address
1530429124d9SThomas Bogendoerfer 	 * and do exception handling to get EFAULTs for get_user/put_user
1531429124d9SThomas Bogendoerfer 	 */
1532429124d9SThomas Bogendoerfer 	if ((regs->cp0_badvaddr >= (1UL << cpu_vmbits)) &&
1533429124d9SThomas Bogendoerfer 	    (regs->cp0_badvaddr < XKSSEG)) {
1534429124d9SThomas Bogendoerfer 		if (fixup_exception(regs)) {
1535429124d9SThomas Bogendoerfer 			current->thread.cp0_baduaddr = regs->cp0_badvaddr;
1536429124d9SThomas Bogendoerfer 			return;
1537429124d9SThomas Bogendoerfer 		}
1538429124d9SThomas Bogendoerfer 		goto sigbus;
1539429124d9SThomas Bogendoerfer 	}
1540429124d9SThomas Bogendoerfer #endif
1541429124d9SThomas Bogendoerfer 
15421da177e4SLinus Torvalds 	/*
15431da177e4SLinus Torvalds 	 * Did we catch a fault trying to load an instruction?
15441da177e4SLinus Torvalds 	 */
154534c2f668SLeonid Yegoshin 	if (regs->cp0_badvaddr == regs->cp0_epc)
15461da177e4SLinus Torvalds 		goto sigbus;
15471da177e4SLinus Torvalds 
1548293c5bd1SRalf Baechle 	if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
15491da177e4SLinus Torvalds 		goto sigbus;
15506312e0eeSAtsushi Nemoto 	if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
15516312e0eeSAtsushi Nemoto 		goto sigbus;
15521da177e4SLinus Torvalds 
15531da177e4SLinus Torvalds 	/*
15541da177e4SLinus Torvalds 	 * Do branch emulation only if we didn't forward the exception.
15551da177e4SLinus Torvalds 	 * This is all so but ugly ...
15561da177e4SLinus Torvalds 	 */
155734c2f668SLeonid Yegoshin 
155834c2f668SLeonid Yegoshin 	/*
155934c2f668SLeonid Yegoshin 	 * Are we running in microMIPS mode?
156034c2f668SLeonid Yegoshin 	 */
156134c2f668SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
156234c2f668SLeonid Yegoshin 		/*
156334c2f668SLeonid Yegoshin 		 * Did we catch a fault trying to load an instruction in
156434c2f668SLeonid Yegoshin 		 * 16-bit mode?
156534c2f668SLeonid Yegoshin 		 */
156634c2f668SLeonid Yegoshin 		if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
156734c2f668SLeonid Yegoshin 			goto sigbus;
156834c2f668SLeonid Yegoshin 		if (unaligned_action == UNALIGNED_ACTION_SHOW)
156934c2f668SLeonid Yegoshin 			show_registers(regs);
157034c2f668SLeonid Yegoshin 
157134c2f668SLeonid Yegoshin 		if (cpu_has_mmips) {
157234c2f668SLeonid Yegoshin 			emulate_load_store_microMIPS(regs,
157334c2f668SLeonid Yegoshin 				(void __user *)regs->cp0_badvaddr);
157434c2f668SLeonid Yegoshin 			return;
157534c2f668SLeonid Yegoshin 		}
157634c2f668SLeonid Yegoshin 
1577451b001bSSteven J. Hill 		if (cpu_has_mips16) {
1578451b001bSSteven J. Hill 			emulate_load_store_MIPS16e(regs,
1579451b001bSSteven J. Hill 				(void __user *)regs->cp0_badvaddr);
1580451b001bSSteven J. Hill 			return;
1581451b001bSSteven J. Hill 		}
1582451b001bSSteven J. Hill 
158334c2f668SLeonid Yegoshin 		goto sigbus;
158434c2f668SLeonid Yegoshin 	}
158534c2f668SLeonid Yegoshin 
158634c2f668SLeonid Yegoshin 	if (unaligned_action == UNALIGNED_ACTION_SHOW)
158734c2f668SLeonid Yegoshin 		show_registers(regs);
15887cba4128SThomas Bogendoerfer 	pc = (unsigned int *)exception_epc(regs);
158934c2f668SLeonid Yegoshin 
15907f18f151SRalf Baechle 	emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds 	return;
15931da177e4SLinus Torvalds 
15941da177e4SLinus Torvalds sigbus:
15951da177e4SLinus Torvalds 	die_if_kernel("Kernel unaligned instruction access", regs);
15963cf5d076SEric W. Biederman 	force_sig(SIGBUS);
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds 	/*
15991da177e4SLinus Torvalds 	 * XXX On return from the signal handler we should advance the epc
16001da177e4SLinus Torvalds 	 */
1601c3fc5cd5SRalf Baechle 	exception_exit(prev_state);
16021da177e4SLinus Torvalds }
16036312e0eeSAtsushi Nemoto 
16046312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
debugfs_unaligned(void)16056312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
16066312e0eeSAtsushi Nemoto {
1607d8140426SGreg Kroah-Hartman 	debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir,
1608d8140426SGreg Kroah-Hartman 			   &unaligned_instructions);
1609d8140426SGreg Kroah-Hartman 	debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
16106312e0eeSAtsushi Nemoto 			   mips_debugfs_dir, &unaligned_action);
16116312e0eeSAtsushi Nemoto 	return 0;
16126312e0eeSAtsushi Nemoto }
16138d6b591cSRalf Baechle arch_initcall(debugfs_unaligned);
16146312e0eeSAtsushi Nemoto #endif
1615