xref: /linux/arch/mips/kernel/unaligned.c (revision eeb538950367e3966cbf0237ab1a1dc30e059818)
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>
88102cedc3SLeonid Yegoshin #include <asm/fpu.h>
89102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h>
901da177e4SLinus Torvalds #include <asm/inst.h>
911da177e4SLinus Torvalds #include <asm/uaccess.h>
9234c2f668SLeonid Yegoshin #include <asm/fpu.h>
9334c2f668SLeonid Yegoshin #include <asm/fpu_emulator.h>
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds #define STR(x)	__STR(x)
961da177e4SLinus Torvalds #define __STR(x)  #x
971da177e4SLinus Torvalds 
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 
11134c2f668SLeonid Yegoshin #ifdef __BIG_ENDIAN
112*eeb53895SMarkos Chandras #define     _LoadHW(addr, value, res, type)  \
11334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (".set\tnoat\n"        \
114*eeb53895SMarkos Chandras 			"1:\t"type##_lb("%0", "0(%2)")"\n"  \
115*eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
11634c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
11734c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
11834c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
11934c2f668SLeonid Yegoshin 			"3:\t.set\tat\n\t"                  \
12034c2f668SLeonid Yegoshin 			".insn\n\t"                         \
12134c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
12234c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
12334c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
12434c2f668SLeonid Yegoshin 			".previous\n\t"                     \
12534c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
12634c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
12734c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
12834c2f668SLeonid Yegoshin 			".previous"                         \
12934c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
13034c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
13134c2f668SLeonid Yegoshin 
1320593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
133*eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type)   \
13434c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
135*eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "(%2)")"\n"   \
136*eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
13734c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
13834c2f668SLeonid Yegoshin 			"3:\n\t"                            \
13934c2f668SLeonid Yegoshin 			".insn\n\t"                         \
14034c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
14134c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
14234c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
14334c2f668SLeonid Yegoshin 			".previous\n\t"                     \
14434c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
14534c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
14634c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
14734c2f668SLeonid Yegoshin 			".previous"                         \
14834c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
14934c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
1500593a44cSLeonid Yegoshin #else
1510593a44cSLeonid Yegoshin /* MIPSR6 has no lwl instruction */
152*eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type) \
1530593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
1540593a44cSLeonid Yegoshin 			".set\tpush\n"			    \
1550593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
156*eeb53895SMarkos Chandras 			"1:"type##_lb("%0", "0(%2)")"\n\t"  \
157*eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "1(%2)")"\n\t" \
1580593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
1590593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
160*eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "2(%2)")"\n\t" \
1610593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
1620593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
163*eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "3(%2)")"\n\t" \
1640593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
1650593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
1660593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
1670593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
1680593a44cSLeonid Yegoshin 			"10:\n\t"			    \
1690593a44cSLeonid Yegoshin 			".insn\n\t"			    \
1700593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
1710593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
1720593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
1730593a44cSLeonid Yegoshin 			".previous\n\t"			    \
1740593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
1750593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
1760593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
1770593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
1780593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
1790593a44cSLeonid Yegoshin 			".previous"			    \
1800593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
1810593a44cSLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
1820593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
18334c2f668SLeonid Yegoshin 
184*eeb53895SMarkos Chandras #define     _LoadHWU(addr, value, res, type) \
18534c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
18634c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
187*eeb53895SMarkos Chandras 			"1:\t"type##_lbu("%0", "0(%2)")"\n" \
188*eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
18934c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
19034c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
19134c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
19234c2f668SLeonid Yegoshin 			"3:\n\t"                            \
19334c2f668SLeonid Yegoshin 			".insn\n\t"                         \
19434c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
19534c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
19634c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
19734c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
19834c2f668SLeonid Yegoshin 			".previous\n\t"                     \
19934c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
20034c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
20134c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
20234c2f668SLeonid Yegoshin 			".previous"                         \
20334c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
20434c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
20534c2f668SLeonid Yegoshin 
2060593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
207*eeb53895SMarkos Chandras #define     _LoadWU(addr, value, res, type)  \
20834c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
209*eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "(%2)")"\n"  \
210*eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
21134c2f668SLeonid Yegoshin 			"dsll\t%0, %0, 32\n\t"              \
21234c2f668SLeonid Yegoshin 			"dsrl\t%0, %0, 32\n\t"              \
21334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
21434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
21534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
21634c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
21734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
21834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
21934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
22034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
22134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
22234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
22334c2f668SLeonid Yegoshin 			".previous"                         \
22434c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
22534c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
22634c2f668SLeonid Yegoshin 
227*eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
22834c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
22934c2f668SLeonid Yegoshin 			"1:\tldl\t%0, (%2)\n"               \
23034c2f668SLeonid Yegoshin 			"2:\tldr\t%0, 7(%2)\n\t"            \
23134c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
23234c2f668SLeonid Yegoshin 			"3:\n\t"                            \
23334c2f668SLeonid Yegoshin 			".insn\n\t"                         \
23434c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
23534c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
23634c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
23734c2f668SLeonid Yegoshin 			".previous\n\t"                     \
23834c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
23934c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
24034c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
24134c2f668SLeonid Yegoshin 			".previous"                         \
24234c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
24334c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
2440593a44cSLeonid Yegoshin #else
2450593a44cSLeonid Yegoshin /* MIPSR6 has not lwl and ldl instructions */
246*eeb53895SMarkos Chandras #define	    _LoadWU(addr, value, res, type) \
2470593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
2480593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
2490593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
250*eeb53895SMarkos Chandras 			"1:"type##_lbu("%0", "0(%2)")"\n\t" \
251*eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "1(%2)")"\n\t" \
2520593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
2530593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
254*eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "2(%2)")"\n\t" \
2550593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
2560593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
257*eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "3(%2)")"\n\t" \
2580593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
2590593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2600593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
2610593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
2620593a44cSLeonid Yegoshin 			"10:\n\t"			    \
2630593a44cSLeonid Yegoshin 			".insn\n\t"			    \
2640593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
2650593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
2660593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
2670593a44cSLeonid Yegoshin 			".previous\n\t"			    \
2680593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
2690593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
2700593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
2710593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
2720593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
2730593a44cSLeonid Yegoshin 			".previous"			    \
2740593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
2750593a44cSLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
2760593a44cSLeonid Yegoshin 
277*eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
2780593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
2790593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
2800593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
2810593a44cSLeonid Yegoshin 			"1:lb\t%0, 0(%2)\n\t"    	    \
2820593a44cSLeonid Yegoshin 			"2:lbu\t $1, 1(%2)\n\t"   	    \
2830593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
2840593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2850593a44cSLeonid Yegoshin 			"3:lbu\t$1, 2(%2)\n\t"   	    \
2860593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
2870593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2880593a44cSLeonid Yegoshin 			"4:lbu\t$1, 3(%2)\n\t"   	    \
2890593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
2900593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2910593a44cSLeonid Yegoshin 			"5:lbu\t$1, 4(%2)\n\t"   	    \
2920593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
2930593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2940593a44cSLeonid Yegoshin 			"6:lbu\t$1, 5(%2)\n\t"   	    \
2950593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
2960593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2970593a44cSLeonid Yegoshin 			"7:lbu\t$1, 6(%2)\n\t"   	    \
2980593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
2990593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3000593a44cSLeonid Yegoshin 			"8:lbu\t$1, 7(%2)\n\t"   	    \
3010593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3020593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3030593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
3040593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
3050593a44cSLeonid Yegoshin 			"10:\n\t"			    \
3060593a44cSLeonid Yegoshin 			".insn\n\t"			    \
3070593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
3080593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
3090593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
3100593a44cSLeonid Yegoshin 			".previous\n\t"			    \
3110593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
3120593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
3130593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
3140593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
3150593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
3160593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
3170593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
3180593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
3190593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
3200593a44cSLeonid Yegoshin 			".previous"			    \
3210593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
3220593a44cSLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
3230593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
3240593a44cSLeonid Yegoshin 
32534c2f668SLeonid Yegoshin 
326*eeb53895SMarkos Chandras #define     _StoreHW(addr, value, res, type) \
32734c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
32834c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
329*eeb53895SMarkos Chandras 			"1:\t"type##_sb("%1", "1(%2)")"\n"  \
33034c2f668SLeonid Yegoshin 			"srl\t$1, %1, 0x8\n"                \
331*eeb53895SMarkos Chandras 			"2:\t"type##_sb("$1", "0(%2)")"\n"  \
33234c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
33334c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
33434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
33534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
33634c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
33734c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
33834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
33934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
34034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
34134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
34234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
34334c2f668SLeonid Yegoshin 			".previous"                         \
34434c2f668SLeonid Yegoshin 			: "=r" (res)                        \
34534c2f668SLeonid Yegoshin 			: "r" (value), "r" (addr), "i" (-EFAULT));
34634c2f668SLeonid Yegoshin 
3470593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
348*eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
34934c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
350*eeb53895SMarkos Chandras 			"1:\t"type##_swl("%1", "(%2)")"\n"  \
351*eeb53895SMarkos Chandras 			"2:\t"type##_swr("%1", "3(%2)")"\n\t"\
35234c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
35334c2f668SLeonid Yegoshin 			"3:\n\t"                            \
35434c2f668SLeonid Yegoshin 			".insn\n\t"                         \
35534c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
35634c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
35734c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
35834c2f668SLeonid Yegoshin 			".previous\n\t"                     \
35934c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
36034c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
36134c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
36234c2f668SLeonid Yegoshin 			".previous"                         \
36334c2f668SLeonid Yegoshin 		: "=r" (res)                                \
36434c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
36534c2f668SLeonid Yegoshin 
366*eeb53895SMarkos Chandras #define     _StoreDW(addr, value, res) \
36734c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
36834c2f668SLeonid Yegoshin 			"1:\tsdl\t%1,(%2)\n"                \
36934c2f668SLeonid Yegoshin 			"2:\tsdr\t%1, 7(%2)\n\t"            \
37034c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
37134c2f668SLeonid Yegoshin 			"3:\n\t"                            \
37234c2f668SLeonid Yegoshin 			".insn\n\t"                         \
37334c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
37434c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
37534c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
37634c2f668SLeonid Yegoshin 			".previous\n\t"                     \
37734c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
37834c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
37934c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
38034c2f668SLeonid Yegoshin 			".previous"                         \
38134c2f668SLeonid Yegoshin 		: "=r" (res)                                \
38234c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
3830593a44cSLeonid Yegoshin #else
3840593a44cSLeonid Yegoshin /* MIPSR6 has no swl and sdl instructions */
385*eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
3860593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
3870593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
3880593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
389*eeb53895SMarkos Chandras 			"1:"type##_sb("%1", "3(%2)")"\n\t"  \
3900593a44cSLeonid Yegoshin 			"srl\t$1, %1, 0x8\n\t"		    \
391*eeb53895SMarkos Chandras 			"2:"type##_sb("$1", "2(%2)")"\n\t"  \
3920593a44cSLeonid Yegoshin 			"srl\t$1, $1,  0x8\n\t"		    \
393*eeb53895SMarkos Chandras 			"3:"type##_sb("$1", "1(%2)")"\n\t"  \
3940593a44cSLeonid Yegoshin 			"srl\t$1, $1, 0x8\n\t"		    \
395*eeb53895SMarkos Chandras 			"4:"type##_sb("$1", "0(%2)")"\n\t"  \
3960593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
3970593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
3980593a44cSLeonid Yegoshin 			"10:\n\t"			    \
3990593a44cSLeonid Yegoshin 			".insn\n\t"			    \
4000593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
4010593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
4020593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
4030593a44cSLeonid Yegoshin 			".previous\n\t"			    \
4040593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
4050593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
4060593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
4070593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
4080593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
4090593a44cSLeonid Yegoshin 			".previous"			    \
4100593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
4110593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
4120593a44cSLeonid Yegoshin 		: "memory");
41334c2f668SLeonid Yegoshin 
4140593a44cSLeonid Yegoshin #define     StoreDW(addr, value, res) \
4150593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
4160593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
4170593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
4180593a44cSLeonid Yegoshin 			"1:sb\t%1, 7(%2)\n\t"    	    \
4190593a44cSLeonid Yegoshin 			"dsrl\t$1, %1, 0x8\n\t"		    \
4200593a44cSLeonid Yegoshin 			"2:sb\t$1, 6(%2)\n\t"    	    \
4210593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4220593a44cSLeonid Yegoshin 			"3:sb\t$1, 5(%2)\n\t"    	    \
4230593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4240593a44cSLeonid Yegoshin 			"4:sb\t$1, 4(%2)\n\t"    	    \
4250593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4260593a44cSLeonid Yegoshin 			"5:sb\t$1, 3(%2)\n\t"    	    \
4270593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4280593a44cSLeonid Yegoshin 			"6:sb\t$1, 2(%2)\n\t"    	    \
4290593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4300593a44cSLeonid Yegoshin 			"7:sb\t$1, 1(%2)\n\t"    	    \
4310593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4320593a44cSLeonid Yegoshin 			"8:sb\t$1, 0(%2)\n\t"    	    \
4330593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4340593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
4350593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
4360593a44cSLeonid Yegoshin 			"10:\n\t"			    \
4370593a44cSLeonid Yegoshin 			".insn\n\t"			    \
4380593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
4390593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
4400593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
4410593a44cSLeonid Yegoshin 			".previous\n\t"			    \
4420593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
4430593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
4440593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
4450593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
4460593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
4470593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
4480593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
4490593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
4500593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
4510593a44cSLeonid Yegoshin 			".previous"			    \
4520593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
4530593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
4540593a44cSLeonid Yegoshin 		: "memory");
4550593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
4560593a44cSLeonid Yegoshin 
4570593a44cSLeonid Yegoshin #else /* __BIG_ENDIAN */
4580593a44cSLeonid Yegoshin 
459*eeb53895SMarkos Chandras #define     _LoadHW(addr, value, res, type)  \
46034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (".set\tnoat\n"        \
461*eeb53895SMarkos Chandras 			"1:\t"type##_lb("%0", "1(%2)")"\n"  \
462*eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
46334c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
46434c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
46534c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
46634c2f668SLeonid Yegoshin 			"3:\t.set\tat\n\t"                  \
46734c2f668SLeonid Yegoshin 			".insn\n\t"                         \
46834c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
46934c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
47034c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
47134c2f668SLeonid Yegoshin 			".previous\n\t"                     \
47234c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
47334c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
47434c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
47534c2f668SLeonid Yegoshin 			".previous"                         \
47634c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
47734c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
47834c2f668SLeonid Yegoshin 
4790593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
480*eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type)   \
48134c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
482*eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "3(%2)")"\n" \
483*eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
48434c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
48534c2f668SLeonid Yegoshin 			"3:\n\t"                            \
48634c2f668SLeonid Yegoshin 			".insn\n\t"                         \
48734c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
48834c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
48934c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
49034c2f668SLeonid Yegoshin 			".previous\n\t"                     \
49134c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
49234c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
49334c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
49434c2f668SLeonid Yegoshin 			".previous"                         \
49534c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
49634c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
4970593a44cSLeonid Yegoshin #else
4980593a44cSLeonid Yegoshin /* MIPSR6 has no lwl instruction */
499*eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type) \
5000593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
5010593a44cSLeonid Yegoshin 			".set\tpush\n"			    \
5020593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
503*eeb53895SMarkos Chandras 			"1:"type##_lb("%0", "3(%2)")"\n\t"  \
504*eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "2(%2)")"\n\t" \
5050593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
5060593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
507*eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "1(%2)")"\n\t" \
5080593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
5090593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
510*eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "0(%2)")"\n\t" \
5110593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
5120593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
5130593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
5140593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
5150593a44cSLeonid Yegoshin 			"10:\n\t"			    \
5160593a44cSLeonid Yegoshin 			".insn\n\t"			    \
5170593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
5180593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
5190593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
5200593a44cSLeonid Yegoshin 			".previous\n\t"			    \
5210593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
5220593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
5230593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
5240593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
5250593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
5260593a44cSLeonid Yegoshin 			".previous"			    \
5270593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
5280593a44cSLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
5290593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
5300593a44cSLeonid Yegoshin 
53134c2f668SLeonid Yegoshin 
532*eeb53895SMarkos Chandras #define     _LoadHWU(addr, value, res, type) \
53334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
53434c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
535*eeb53895SMarkos Chandras 			"1:\t"type##_lbu("%0", "1(%2)")"\n" \
536*eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
53734c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
53834c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
53934c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
54034c2f668SLeonid Yegoshin 			"3:\n\t"                            \
54134c2f668SLeonid Yegoshin 			".insn\n\t"                         \
54234c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
54334c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
54434c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
54534c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
54634c2f668SLeonid Yegoshin 			".previous\n\t"                     \
54734c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
54834c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
54934c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
55034c2f668SLeonid Yegoshin 			".previous"                         \
55134c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
55234c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
55334c2f668SLeonid Yegoshin 
5540593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
555*eeb53895SMarkos Chandras #define     _LoadWU(addr, value, res, type)  \
55634c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
557*eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "3(%2)")"\n" \
558*eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
55934c2f668SLeonid Yegoshin 			"dsll\t%0, %0, 32\n\t"              \
56034c2f668SLeonid Yegoshin 			"dsrl\t%0, %0, 32\n\t"              \
56134c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
56234c2f668SLeonid Yegoshin 			"3:\n\t"                            \
56334c2f668SLeonid Yegoshin 			".insn\n\t"                         \
56434c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
56534c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
56634c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
56734c2f668SLeonid Yegoshin 			".previous\n\t"                     \
56834c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
56934c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
57034c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
57134c2f668SLeonid Yegoshin 			".previous"                         \
57234c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
57334c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
57434c2f668SLeonid Yegoshin 
575*eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
57634c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
57734c2f668SLeonid Yegoshin 			"1:\tldl\t%0, 7(%2)\n"              \
57834c2f668SLeonid Yegoshin 			"2:\tldr\t%0, (%2)\n\t"             \
57934c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
58034c2f668SLeonid Yegoshin 			"3:\n\t"                            \
58134c2f668SLeonid Yegoshin 			".insn\n\t"                         \
58234c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
58334c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
58434c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
58534c2f668SLeonid Yegoshin 			".previous\n\t"                     \
58634c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
58734c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
58834c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
58934c2f668SLeonid Yegoshin 			".previous"                         \
59034c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
59134c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
5920593a44cSLeonid Yegoshin #else
5930593a44cSLeonid Yegoshin /* MIPSR6 has not lwl and ldl instructions */
594*eeb53895SMarkos Chandras #define	    _LoadWU(addr, value, res, type) \
5950593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
5960593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
5970593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
598*eeb53895SMarkos Chandras 			"1:"type##_lbu("%0", "3(%2)")"\n\t" \
599*eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "2(%2)")"\n\t" \
6000593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
6010593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
602*eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "1(%2)")"\n\t" \
6030593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
6040593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
605*eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "0(%2)")"\n\t" \
6060593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
6070593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6080593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
6090593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
6100593a44cSLeonid Yegoshin 			"10:\n\t"			    \
6110593a44cSLeonid Yegoshin 			".insn\n\t"			    \
6120593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
6130593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
6140593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
6150593a44cSLeonid Yegoshin 			".previous\n\t"			    \
6160593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
6170593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
6180593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
6190593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
6200593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
6210593a44cSLeonid Yegoshin 			".previous"			    \
6220593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
6230593a44cSLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
6240593a44cSLeonid Yegoshin 
625*eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
6260593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
6270593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
6280593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
6290593a44cSLeonid Yegoshin 			"1:lb\t%0, 7(%2)\n\t"    	    \
6300593a44cSLeonid Yegoshin 			"2:lbu\t$1, 6(%2)\n\t"   	    \
6310593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6320593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6330593a44cSLeonid Yegoshin 			"3:lbu\t$1, 5(%2)\n\t"   	    \
6340593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6350593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6360593a44cSLeonid Yegoshin 			"4:lbu\t$1, 4(%2)\n\t"   	    \
6370593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6380593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6390593a44cSLeonid Yegoshin 			"5:lbu\t$1, 3(%2)\n\t"   	    \
6400593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6410593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6420593a44cSLeonid Yegoshin 			"6:lbu\t$1, 2(%2)\n\t"   	    \
6430593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6440593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6450593a44cSLeonid Yegoshin 			"7:lbu\t$1, 1(%2)\n\t"   	    \
6460593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6470593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6480593a44cSLeonid Yegoshin 			"8:lbu\t$1, 0(%2)\n\t"   	    \
6490593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6500593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6510593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
6520593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
6530593a44cSLeonid Yegoshin 			"10:\n\t"			    \
6540593a44cSLeonid Yegoshin 			".insn\n\t"			    \
6550593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
6560593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
6570593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
6580593a44cSLeonid Yegoshin 			".previous\n\t"			    \
6590593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
6600593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
6610593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
6620593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
6630593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
6640593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
6650593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
6660593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
6670593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
6680593a44cSLeonid Yegoshin 			".previous"			    \
6690593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
6700593a44cSLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
6710593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
67234c2f668SLeonid Yegoshin 
673*eeb53895SMarkos Chandras #define     _StoreHW(addr, value, res, type) \
67434c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
67534c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
676*eeb53895SMarkos Chandras 			"1:\t"type##_sb("%1", "0(%2)")"\n"  \
67734c2f668SLeonid Yegoshin 			"srl\t$1,%1, 0x8\n"                 \
678*eeb53895SMarkos Chandras 			"2:\t"type##_sb("$1", "1(%2)")"\n"  \
67934c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
68034c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
68134c2f668SLeonid Yegoshin 			"3:\n\t"                            \
68234c2f668SLeonid Yegoshin 			".insn\n\t"                         \
68334c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
68434c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
68534c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
68634c2f668SLeonid Yegoshin 			".previous\n\t"                     \
68734c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
68834c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
68934c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
69034c2f668SLeonid Yegoshin 			".previous"                         \
69134c2f668SLeonid Yegoshin 			: "=r" (res)                        \
69234c2f668SLeonid Yegoshin 			: "r" (value), "r" (addr), "i" (-EFAULT));
6930593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
694*eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
69534c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
696*eeb53895SMarkos Chandras 			"1:\t"type##_swl("%1", "3(%2)")"\n" \
697*eeb53895SMarkos Chandras 			"2:\t"type##_swr("%1", "(%2)")"\n\t"\
69834c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
69934c2f668SLeonid Yegoshin 			"3:\n\t"                            \
70034c2f668SLeonid Yegoshin 			".insn\n\t"                         \
70134c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
70234c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
70334c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
70434c2f668SLeonid Yegoshin 			".previous\n\t"                     \
70534c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
70634c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
70734c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
70834c2f668SLeonid Yegoshin 			".previous"                         \
70934c2f668SLeonid Yegoshin 		: "=r" (res)                                \
71034c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
71134c2f668SLeonid Yegoshin 
712*eeb53895SMarkos Chandras #define     _StoreDW(addr, value, res) \
71334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
71434c2f668SLeonid Yegoshin 			"1:\tsdl\t%1, 7(%2)\n"              \
71534c2f668SLeonid Yegoshin 			"2:\tsdr\t%1, (%2)\n\t"             \
71634c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
71734c2f668SLeonid Yegoshin 			"3:\n\t"                            \
71834c2f668SLeonid Yegoshin 			".insn\n\t"                         \
71934c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
72034c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
72134c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
72234c2f668SLeonid Yegoshin 			".previous\n\t"                     \
72334c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
72434c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
72534c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
72634c2f668SLeonid Yegoshin 			".previous"                         \
72734c2f668SLeonid Yegoshin 		: "=r" (res)                                \
72834c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
7290593a44cSLeonid Yegoshin #else
7300593a44cSLeonid Yegoshin /* MIPSR6 has no swl and sdl instructions */
731*eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
7320593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
7330593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
7340593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
735*eeb53895SMarkos Chandras 			"1:"type##_sb("%1", "0(%2)")"\n\t"  \
7360593a44cSLeonid Yegoshin 			"srl\t$1, %1, 0x8\n\t"		    \
737*eeb53895SMarkos Chandras 			"2:"type##_sb("$1", "1(%2)")"\n\t"  \
7380593a44cSLeonid Yegoshin 			"srl\t$1, $1,  0x8\n\t"		    \
739*eeb53895SMarkos Chandras 			"3:"type##_sb("$1", "2(%2)")"\n\t"  \
7400593a44cSLeonid Yegoshin 			"srl\t$1, $1, 0x8\n\t"		    \
741*eeb53895SMarkos Chandras 			"4:"type##_sb("$1", "3(%2)")"\n\t"  \
7420593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
7430593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
7440593a44cSLeonid Yegoshin 			"10:\n\t"			    \
7450593a44cSLeonid Yegoshin 			".insn\n\t"			    \
7460593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
7470593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
7480593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
7490593a44cSLeonid Yegoshin 			".previous\n\t"			    \
7500593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
7510593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
7520593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
7530593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
7540593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
7550593a44cSLeonid Yegoshin 			".previous"			    \
7560593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
7570593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
7580593a44cSLeonid Yegoshin 		: "memory");
7590593a44cSLeonid Yegoshin 
760*eeb53895SMarkos Chandras #define     _StoreDW(addr, value, res) \
7610593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
7620593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
7630593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
7640593a44cSLeonid Yegoshin 			"1:sb\t%1, 0(%2)\n\t"    	    \
7650593a44cSLeonid Yegoshin 			"dsrl\t$1, %1, 0x8\n\t"		    \
7660593a44cSLeonid Yegoshin 			"2:sb\t$1, 1(%2)\n\t"    	    \
7670593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7680593a44cSLeonid Yegoshin 			"3:sb\t$1, 2(%2)\n\t"    	    \
7690593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7700593a44cSLeonid Yegoshin 			"4:sb\t$1, 3(%2)\n\t"    	    \
7710593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7720593a44cSLeonid Yegoshin 			"5:sb\t$1, 4(%2)\n\t"    	    \
7730593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7740593a44cSLeonid Yegoshin 			"6:sb\t$1, 5(%2)\n\t"    	    \
7750593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7760593a44cSLeonid Yegoshin 			"7:sb\t$1, 6(%2)\n\t"    	    \
7770593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7780593a44cSLeonid Yegoshin 			"8:sb\t$1, 7(%2)\n\t"    	    \
7790593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
7800593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
7810593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
7820593a44cSLeonid Yegoshin 			"10:\n\t"			    \
7830593a44cSLeonid Yegoshin 			".insn\n\t"			    \
7840593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
7850593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
7860593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
7870593a44cSLeonid Yegoshin 			".previous\n\t"			    \
7880593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
7890593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
7900593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
7910593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
7920593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
7930593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
7940593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
7950593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
7960593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
7970593a44cSLeonid Yegoshin 			".previous"			    \
7980593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
7990593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
8000593a44cSLeonid Yegoshin 		: "memory");
8010593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
80234c2f668SLeonid Yegoshin #endif
80334c2f668SLeonid Yegoshin 
804*eeb53895SMarkos Chandras #define LoadHWU(addr, value, res)	_LoadHWU(addr, value, res, kernel)
805*eeb53895SMarkos Chandras #define LoadHWUE(addr, value, res)	_LoadHWU(addr, value, res, user)
806*eeb53895SMarkos Chandras #define LoadWU(addr, value, res)	_LoadWU(addr, value, res, kernel)
807*eeb53895SMarkos Chandras #define LoadWUE(addr, value, res)	_LoadWU(addr, value, res, user)
808*eeb53895SMarkos Chandras #define LoadHW(addr, value, res)	_LoadHW(addr, value, res, kernel)
809*eeb53895SMarkos Chandras #define LoadHWE(addr, value, res)	_LoadHW(addr, value, res, user)
810*eeb53895SMarkos Chandras #define LoadW(addr, value, res)		_LoadW(addr, value, res, kernel)
811*eeb53895SMarkos Chandras #define LoadWE(addr, value, res)	_LoadW(addr, value, res, user)
812*eeb53895SMarkos Chandras #define LoadDW(addr, value, res)	_LoadDW(addr, value, res)
813*eeb53895SMarkos Chandras 
814*eeb53895SMarkos Chandras #define StoreHW(addr, value, res)	_StoreHW(addr, value, res, kernel)
815*eeb53895SMarkos Chandras #define StoreHWE(addr, value, res)	_StoreHW(addr, value, res, user)
816*eeb53895SMarkos Chandras #define StoreW(addr, value, res)	_StoreW(addr, value, res, kernel)
817*eeb53895SMarkos Chandras #define StoreWE(addr, value, res)	_StoreW(addr, value, res, user)
818*eeb53895SMarkos Chandras #define StoreDW(addr, value, res)	_StoreDW(addr, value, res)
819*eeb53895SMarkos Chandras 
8207f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs,
8217f18f151SRalf Baechle 	void __user *addr, unsigned int __user *pc)
8221da177e4SLinus Torvalds {
8231da177e4SLinus Torvalds 	union mips_instruction insn;
8241da177e4SLinus Torvalds 	unsigned long value;
8251da177e4SLinus Torvalds 	unsigned int res;
82634c2f668SLeonid Yegoshin 	unsigned long origpc;
82734c2f668SLeonid Yegoshin 	unsigned long orig31;
828102cedc3SLeonid Yegoshin 	void __user *fault_addr = NULL;
829c1771216SLeonid Yegoshin #ifdef	CONFIG_EVA
830c1771216SLeonid Yegoshin 	mm_segment_t seg;
831c1771216SLeonid Yegoshin #endif
83234c2f668SLeonid Yegoshin 	origpc = (unsigned long)pc;
83334c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
83434c2f668SLeonid Yegoshin 
835a8b0ca17SPeter Zijlstra 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
8367f788d2dSDeng-Cheng Zhu 
8371da177e4SLinus Torvalds 	/*
8381da177e4SLinus Torvalds 	 * This load never faults.
8391da177e4SLinus Torvalds 	 */
840fe00f943SRalf Baechle 	__get_user(insn.word, pc);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	switch (insn.i_format.opcode) {
8431da177e4SLinus Torvalds 		/*
8441da177e4SLinus Torvalds 		 * These are instructions that a compiler doesn't generate.  We
8451da177e4SLinus Torvalds 		 * can assume therefore that the code is MIPS-aware and
8461da177e4SLinus Torvalds 		 * really buggy.  Emulating these instructions would break the
8471da177e4SLinus Torvalds 		 * semantics anyway.
8481da177e4SLinus Torvalds 		 */
8491da177e4SLinus Torvalds 	case ll_op:
8501da177e4SLinus Torvalds 	case lld_op:
8511da177e4SLinus Torvalds 	case sc_op:
8521da177e4SLinus Torvalds 	case scd_op:
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds 		/*
8551da177e4SLinus Torvalds 		 * For these instructions the only way to create an address
8561da177e4SLinus Torvalds 		 * error is an attempted access to kernel/supervisor address
8571da177e4SLinus Torvalds 		 * space.
8581da177e4SLinus Torvalds 		 */
8591da177e4SLinus Torvalds 	case ldl_op:
8601da177e4SLinus Torvalds 	case ldr_op:
8611da177e4SLinus Torvalds 	case lwl_op:
8621da177e4SLinus Torvalds 	case lwr_op:
8631da177e4SLinus Torvalds 	case sdl_op:
8641da177e4SLinus Torvalds 	case sdr_op:
8651da177e4SLinus Torvalds 	case swl_op:
8661da177e4SLinus Torvalds 	case swr_op:
8671da177e4SLinus Torvalds 	case lb_op:
8681da177e4SLinus Torvalds 	case lbu_op:
8691da177e4SLinus Torvalds 	case sb_op:
8701da177e4SLinus Torvalds 		goto sigbus;
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 		/*
87334c2f668SLeonid Yegoshin 		 * The remaining opcodes are the ones that are really of
87434c2f668SLeonid Yegoshin 		 * interest.
8751da177e4SLinus Torvalds 		 */
876c1771216SLeonid Yegoshin #ifdef CONFIG_EVA
877c1771216SLeonid Yegoshin 	case spec3_op:
878c1771216SLeonid Yegoshin 		/*
879c1771216SLeonid Yegoshin 		 * we can land here only from kernel accessing user memory,
880c1771216SLeonid Yegoshin 		 * so we need to "switch" the address limit to user space, so
881c1771216SLeonid Yegoshin 		 * address check can work properly.
882c1771216SLeonid Yegoshin 		 */
883c1771216SLeonid Yegoshin 		seg = get_fs();
884c1771216SLeonid Yegoshin 		set_fs(USER_DS);
885c1771216SLeonid Yegoshin 		switch (insn.spec3_format.func) {
886c1771216SLeonid Yegoshin 		case lhe_op:
887c1771216SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 2)) {
888c1771216SLeonid Yegoshin 				set_fs(seg);
889c1771216SLeonid Yegoshin 				goto sigbus;
890c1771216SLeonid Yegoshin 			}
891*eeb53895SMarkos Chandras 			LoadHWE(addr, value, res);
892c1771216SLeonid Yegoshin 			if (res) {
893c1771216SLeonid Yegoshin 				set_fs(seg);
894c1771216SLeonid Yegoshin 				goto fault;
895c1771216SLeonid Yegoshin 			}
896c1771216SLeonid Yegoshin 			compute_return_epc(regs);
897c1771216SLeonid Yegoshin 			regs->regs[insn.spec3_format.rt] = value;
898c1771216SLeonid Yegoshin 			break;
899c1771216SLeonid Yegoshin 		case lwe_op:
900c1771216SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 4)) {
901c1771216SLeonid Yegoshin 				set_fs(seg);
902c1771216SLeonid Yegoshin 				goto sigbus;
903c1771216SLeonid Yegoshin 			}
904*eeb53895SMarkos Chandras 				LoadWE(addr, value, res);
905c1771216SLeonid Yegoshin 			if (res) {
906c1771216SLeonid Yegoshin 				set_fs(seg);
907c1771216SLeonid Yegoshin 				goto fault;
908c1771216SLeonid Yegoshin 			}
909c1771216SLeonid Yegoshin 			compute_return_epc(regs);
910c1771216SLeonid Yegoshin 			regs->regs[insn.spec3_format.rt] = value;
911c1771216SLeonid Yegoshin 			break;
912c1771216SLeonid Yegoshin 		case lhue_op:
913c1771216SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 2)) {
914c1771216SLeonid Yegoshin 				set_fs(seg);
915c1771216SLeonid Yegoshin 				goto sigbus;
916c1771216SLeonid Yegoshin 			}
917*eeb53895SMarkos Chandras 			LoadHWUE(addr, value, res);
918c1771216SLeonid Yegoshin 			if (res) {
919c1771216SLeonid Yegoshin 				set_fs(seg);
920c1771216SLeonid Yegoshin 				goto fault;
921c1771216SLeonid Yegoshin 			}
922c1771216SLeonid Yegoshin 			compute_return_epc(regs);
923c1771216SLeonid Yegoshin 			regs->regs[insn.spec3_format.rt] = value;
924c1771216SLeonid Yegoshin 			break;
925c1771216SLeonid Yegoshin 		case she_op:
926c1771216SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 2)) {
927c1771216SLeonid Yegoshin 				set_fs(seg);
928c1771216SLeonid Yegoshin 				goto sigbus;
929c1771216SLeonid Yegoshin 			}
930c1771216SLeonid Yegoshin 			compute_return_epc(regs);
931c1771216SLeonid Yegoshin 			value = regs->regs[insn.spec3_format.rt];
932*eeb53895SMarkos Chandras 			StoreHWE(addr, value, res);
933c1771216SLeonid Yegoshin 			if (res) {
934c1771216SLeonid Yegoshin 				set_fs(seg);
935c1771216SLeonid Yegoshin 				goto fault;
936c1771216SLeonid Yegoshin 			}
937c1771216SLeonid Yegoshin 			break;
938c1771216SLeonid Yegoshin 		case swe_op:
939c1771216SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 4)) {
940c1771216SLeonid Yegoshin 				set_fs(seg);
941c1771216SLeonid Yegoshin 				goto sigbus;
942c1771216SLeonid Yegoshin 			}
943c1771216SLeonid Yegoshin 			compute_return_epc(regs);
944c1771216SLeonid Yegoshin 			value = regs->regs[insn.spec3_format.rt];
945*eeb53895SMarkos Chandras 			StoreWE(addr, value, res);
946c1771216SLeonid Yegoshin 			if (res) {
947c1771216SLeonid Yegoshin 				set_fs(seg);
948c1771216SLeonid Yegoshin 				goto fault;
949c1771216SLeonid Yegoshin 			}
950c1771216SLeonid Yegoshin 			break;
951c1771216SLeonid Yegoshin 		default:
952c1771216SLeonid Yegoshin 			set_fs(seg);
953c1771216SLeonid Yegoshin 			goto sigill;
954c1771216SLeonid Yegoshin 		}
955c1771216SLeonid Yegoshin 		set_fs(seg);
956c1771216SLeonid Yegoshin 		break;
957c1771216SLeonid Yegoshin #endif
9581da177e4SLinus Torvalds 	case lh_op:
9591da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 2))
9601da177e4SLinus Torvalds 			goto sigbus;
9611da177e4SLinus Torvalds 
96234c2f668SLeonid Yegoshin 		LoadHW(addr, value, res);
9631da177e4SLinus Torvalds 		if (res)
9641da177e4SLinus Torvalds 			goto fault;
9657f18f151SRalf Baechle 		compute_return_epc(regs);
9667f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
9671da177e4SLinus Torvalds 		break;
9681da177e4SLinus Torvalds 
9691da177e4SLinus Torvalds 	case lw_op:
9701da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 4))
9711da177e4SLinus Torvalds 			goto sigbus;
9721da177e4SLinus Torvalds 
97334c2f668SLeonid Yegoshin 		LoadW(addr, value, res);
9741da177e4SLinus Torvalds 		if (res)
9751da177e4SLinus Torvalds 			goto fault;
9767f18f151SRalf Baechle 		compute_return_epc(regs);
9777f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
9781da177e4SLinus Torvalds 		break;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 	case lhu_op:
9811da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 2))
9821da177e4SLinus Torvalds 			goto sigbus;
9831da177e4SLinus Torvalds 
98434c2f668SLeonid Yegoshin 		LoadHWU(addr, value, res);
9851da177e4SLinus Torvalds 		if (res)
9861da177e4SLinus Torvalds 			goto fault;
9877f18f151SRalf Baechle 		compute_return_epc(regs);
9887f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
9891da177e4SLinus Torvalds 		break;
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds 	case lwu_op:
992875d43e7SRalf Baechle #ifdef CONFIG_64BIT
9931da177e4SLinus Torvalds 		/*
9941da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
9951da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
9961da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
9971da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
9981da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
9991da177e4SLinus Torvalds 		 */
10001da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 4))
10011da177e4SLinus Torvalds 			goto sigbus;
10021da177e4SLinus Torvalds 
100334c2f668SLeonid Yegoshin 		LoadWU(addr, value, res);
10041da177e4SLinus Torvalds 		if (res)
10051da177e4SLinus Torvalds 			goto fault;
10067f18f151SRalf Baechle 		compute_return_epc(regs);
10077f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
10081da177e4SLinus Torvalds 		break;
1009875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
10121da177e4SLinus Torvalds 		goto sigill;
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	case ld_op:
1015875d43e7SRalf Baechle #ifdef CONFIG_64BIT
10161da177e4SLinus Torvalds 		/*
10171da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
10181da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
10191da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
10201da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
10211da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
10221da177e4SLinus Torvalds 		 */
10231da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 8))
10241da177e4SLinus Torvalds 			goto sigbus;
10251da177e4SLinus Torvalds 
102634c2f668SLeonid Yegoshin 		LoadDW(addr, value, res);
10271da177e4SLinus Torvalds 		if (res)
10281da177e4SLinus Torvalds 			goto fault;
10297f18f151SRalf Baechle 		compute_return_epc(regs);
10307f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
10311da177e4SLinus Torvalds 		break;
1032875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
10351da177e4SLinus Torvalds 		goto sigill;
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 	case sh_op:
10381da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 2))
10391da177e4SLinus Torvalds 			goto sigbus;
10401da177e4SLinus Torvalds 
104134c2f668SLeonid Yegoshin 		compute_return_epc(regs);
10421da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
104334c2f668SLeonid Yegoshin 		StoreHW(addr, value, res);
10441da177e4SLinus Torvalds 		if (res)
10451da177e4SLinus Torvalds 			goto fault;
10461da177e4SLinus Torvalds 		break;
10471da177e4SLinus Torvalds 
10481da177e4SLinus Torvalds 	case sw_op:
10491da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 4))
10501da177e4SLinus Torvalds 			goto sigbus;
10511da177e4SLinus Torvalds 
105234c2f668SLeonid Yegoshin 		compute_return_epc(regs);
10531da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
105434c2f668SLeonid Yegoshin 		StoreW(addr, value, res);
10551da177e4SLinus Torvalds 		if (res)
10561da177e4SLinus Torvalds 			goto fault;
10571da177e4SLinus Torvalds 		break;
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	case sd_op:
1060875d43e7SRalf Baechle #ifdef CONFIG_64BIT
10611da177e4SLinus Torvalds 		/*
10621da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
10631da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
10641da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
10651da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
10661da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
10671da177e4SLinus Torvalds 		 */
10681da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 8))
10691da177e4SLinus Torvalds 			goto sigbus;
10701da177e4SLinus Torvalds 
107134c2f668SLeonid Yegoshin 		compute_return_epc(regs);
10721da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
107334c2f668SLeonid Yegoshin 		StoreDW(addr, value, res);
10741da177e4SLinus Torvalds 		if (res)
10751da177e4SLinus Torvalds 			goto fault;
10761da177e4SLinus Torvalds 		break;
1077875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
10801da177e4SLinus Torvalds 		goto sigill;
10811da177e4SLinus Torvalds 
10821da177e4SLinus Torvalds 	case lwc1_op:
10831da177e4SLinus Torvalds 	case ldc1_op:
10841da177e4SLinus Torvalds 	case swc1_op:
10851da177e4SLinus Torvalds 	case sdc1_op:
1086102cedc3SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
1087102cedc3SLeonid Yegoshin 		BUG_ON(!used_math());
1088102cedc3SLeonid Yegoshin 
1089102cedc3SLeonid Yegoshin 		lose_fpu(1);	/* Save FPU state for the emulator. */
1090102cedc3SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
1091102cedc3SLeonid Yegoshin 					       &fault_addr);
1092102cedc3SLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
1093102cedc3SLeonid Yegoshin 
1094102cedc3SLeonid Yegoshin 		/* Signal if something went wrong. */
1095102cedc3SLeonid Yegoshin 		process_fpemu_return(res, fault_addr);
1096102cedc3SLeonid Yegoshin 
1097102cedc3SLeonid Yegoshin 		if (res == 0)
1098102cedc3SLeonid Yegoshin 			break;
1099102cedc3SLeonid Yegoshin 		return;
11001da177e4SLinus Torvalds 
11010593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
11021da177e4SLinus Torvalds 	/*
110369f3a7deSRalf Baechle 	 * COP2 is available to implementor for application specific use.
110469f3a7deSRalf Baechle 	 * It's up to applications to register a notifier chain and do
110569f3a7deSRalf Baechle 	 * whatever they have to do, including possible sending of signals.
11060593a44cSLeonid Yegoshin 	 *
11070593a44cSLeonid Yegoshin 	 * This instruction has been reallocated in Release 6
11081da177e4SLinus Torvalds 	 */
110969f3a7deSRalf Baechle 	case lwc2_op:
111069f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
111169f3a7deSRalf Baechle 		break;
111269f3a7deSRalf Baechle 
111369f3a7deSRalf Baechle 	case ldc2_op:
111469f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
111569f3a7deSRalf Baechle 		break;
111669f3a7deSRalf Baechle 
111769f3a7deSRalf Baechle 	case swc2_op:
111869f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
111969f3a7deSRalf Baechle 		break;
112069f3a7deSRalf Baechle 
112169f3a7deSRalf Baechle 	case sdc2_op:
112269f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
112369f3a7deSRalf Baechle 		break;
11240593a44cSLeonid Yegoshin #endif
11251da177e4SLinus Torvalds 	default:
11261da177e4SLinus Torvalds 		/*
11271da177e4SLinus Torvalds 		 * Pheeee...  We encountered an yet unknown instruction or
11281da177e4SLinus Torvalds 		 * cache coherence problem.  Die sucker, die ...
11291da177e4SLinus Torvalds 		 */
11301da177e4SLinus Torvalds 		goto sigill;
11311da177e4SLinus Torvalds 	}
11321da177e4SLinus Torvalds 
11336312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
11341da177e4SLinus Torvalds 	unaligned_instructions++;
11351da177e4SLinus Torvalds #endif
11361da177e4SLinus Torvalds 
11377f18f151SRalf Baechle 	return;
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds fault:
114034c2f668SLeonid Yegoshin 	/* roll back jump/branch */
114134c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
114234c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
11431da177e4SLinus Torvalds 	/* Did we have an exception handler installed? */
11441da177e4SLinus Torvalds 	if (fixup_exception(regs))
11457f18f151SRalf Baechle 		return;
11461da177e4SLinus Torvalds 
11471da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
1148a6d5ff04SDavid Daney 	force_sig(SIGSEGV, current);
11491da177e4SLinus Torvalds 
11507f18f151SRalf Baechle 	return;
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds sigbus:
11531da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
1154a6d5ff04SDavid Daney 	force_sig(SIGBUS, current);
11551da177e4SLinus Torvalds 
11567f18f151SRalf Baechle 	return;
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds sigill:
115934c2f668SLeonid Yegoshin 	die_if_kernel
116034c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
116134c2f668SLeonid Yegoshin 	force_sig(SIGILL, current);
116234c2f668SLeonid Yegoshin }
116334c2f668SLeonid Yegoshin 
116434c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
116534c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
116634c2f668SLeonid Yegoshin 
116734c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
116834c2f668SLeonid Yegoshin const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
116934c2f668SLeonid Yegoshin 
117074338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
117174338805SDavid Daney 					 void __user *addr)
117234c2f668SLeonid Yegoshin {
117334c2f668SLeonid Yegoshin 	unsigned long value;
117434c2f668SLeonid Yegoshin 	unsigned int res;
117534c2f668SLeonid Yegoshin 	int i;
117634c2f668SLeonid Yegoshin 	unsigned int reg = 0, rvar;
117734c2f668SLeonid Yegoshin 	unsigned long orig31;
117834c2f668SLeonid Yegoshin 	u16 __user *pc16;
117934c2f668SLeonid Yegoshin 	u16 halfword;
118034c2f668SLeonid Yegoshin 	unsigned int word;
118134c2f668SLeonid Yegoshin 	unsigned long origpc, contpc;
118234c2f668SLeonid Yegoshin 	union mips_instruction insn;
118334c2f668SLeonid Yegoshin 	struct mm_decoded_insn mminsn;
118434c2f668SLeonid Yegoshin 	void __user *fault_addr = NULL;
118534c2f668SLeonid Yegoshin 
118634c2f668SLeonid Yegoshin 	origpc = regs->cp0_epc;
118734c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
118834c2f668SLeonid Yegoshin 
118934c2f668SLeonid Yegoshin 	mminsn.micro_mips_mode = 1;
119034c2f668SLeonid Yegoshin 
119134c2f668SLeonid Yegoshin 	/*
119234c2f668SLeonid Yegoshin 	 * This load never faults.
119334c2f668SLeonid Yegoshin 	 */
119434c2f668SLeonid Yegoshin 	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
119534c2f668SLeonid Yegoshin 	__get_user(halfword, pc16);
119634c2f668SLeonid Yegoshin 	pc16++;
119734c2f668SLeonid Yegoshin 	contpc = regs->cp0_epc + 2;
119834c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
119934c2f668SLeonid Yegoshin 	mminsn.pc_inc = 2;
120034c2f668SLeonid Yegoshin 
120134c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
120234c2f668SLeonid Yegoshin 		__get_user(halfword, pc16);
120334c2f668SLeonid Yegoshin 		pc16++;
120434c2f668SLeonid Yegoshin 		contpc = regs->cp0_epc + 4;
120534c2f668SLeonid Yegoshin 		mminsn.pc_inc = 4;
120634c2f668SLeonid Yegoshin 		word |= halfword;
120734c2f668SLeonid Yegoshin 	}
120834c2f668SLeonid Yegoshin 	mminsn.insn = word;
120934c2f668SLeonid Yegoshin 
121034c2f668SLeonid Yegoshin 	if (get_user(halfword, pc16))
121134c2f668SLeonid Yegoshin 		goto fault;
121234c2f668SLeonid Yegoshin 	mminsn.next_pc_inc = 2;
121334c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
121434c2f668SLeonid Yegoshin 
121534c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
121634c2f668SLeonid Yegoshin 		pc16++;
121734c2f668SLeonid Yegoshin 		if (get_user(halfword, pc16))
121834c2f668SLeonid Yegoshin 			goto fault;
121934c2f668SLeonid Yegoshin 		mminsn.next_pc_inc = 4;
122034c2f668SLeonid Yegoshin 		word |= halfword;
122134c2f668SLeonid Yegoshin 	}
122234c2f668SLeonid Yegoshin 	mminsn.next_insn = word;
122334c2f668SLeonid Yegoshin 
122434c2f668SLeonid Yegoshin 	insn = (union mips_instruction)(mminsn.insn);
122534c2f668SLeonid Yegoshin 	if (mm_isBranchInstr(regs, mminsn, &contpc))
122634c2f668SLeonid Yegoshin 		insn = (union mips_instruction)(mminsn.next_insn);
122734c2f668SLeonid Yegoshin 
122834c2f668SLeonid Yegoshin 	/*  Parse instruction to find what to do */
122934c2f668SLeonid Yegoshin 
123034c2f668SLeonid Yegoshin 	switch (insn.mm_i_format.opcode) {
123134c2f668SLeonid Yegoshin 
123234c2f668SLeonid Yegoshin 	case mm_pool32a_op:
123334c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
123434c2f668SLeonid Yegoshin 		case mm_lwxs_op:
123534c2f668SLeonid Yegoshin 			reg = insn.mm_x_format.rd;
123634c2f668SLeonid Yegoshin 			goto loadW;
123734c2f668SLeonid Yegoshin 		}
123834c2f668SLeonid Yegoshin 
123934c2f668SLeonid Yegoshin 		goto sigbus;
124034c2f668SLeonid Yegoshin 
124134c2f668SLeonid Yegoshin 	case mm_pool32b_op:
124234c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
124334c2f668SLeonid Yegoshin 		case mm_lwp_func:
124434c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
124534c2f668SLeonid Yegoshin 			if (reg == 31)
124634c2f668SLeonid Yegoshin 				goto sigbus;
124734c2f668SLeonid Yegoshin 
124834c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 8))
124934c2f668SLeonid Yegoshin 				goto sigbus;
125034c2f668SLeonid Yegoshin 
125134c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
125234c2f668SLeonid Yegoshin 			if (res)
125334c2f668SLeonid Yegoshin 				goto fault;
125434c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
125534c2f668SLeonid Yegoshin 			addr += 4;
125634c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
125734c2f668SLeonid Yegoshin 			if (res)
125834c2f668SLeonid Yegoshin 				goto fault;
125934c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
126034c2f668SLeonid Yegoshin 			goto success;
126134c2f668SLeonid Yegoshin 
126234c2f668SLeonid Yegoshin 		case mm_swp_func:
126334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
126434c2f668SLeonid Yegoshin 			if (reg == 31)
126534c2f668SLeonid Yegoshin 				goto sigbus;
126634c2f668SLeonid Yegoshin 
126734c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 8))
126834c2f668SLeonid Yegoshin 				goto sigbus;
126934c2f668SLeonid Yegoshin 
127034c2f668SLeonid Yegoshin 			value = regs->regs[reg];
127134c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
127234c2f668SLeonid Yegoshin 			if (res)
127334c2f668SLeonid Yegoshin 				goto fault;
127434c2f668SLeonid Yegoshin 			addr += 4;
127534c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
127634c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
127734c2f668SLeonid Yegoshin 			if (res)
127834c2f668SLeonid Yegoshin 				goto fault;
127934c2f668SLeonid Yegoshin 			goto success;
128034c2f668SLeonid Yegoshin 
128134c2f668SLeonid Yegoshin 		case mm_ldp_func:
128234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
128334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
128434c2f668SLeonid Yegoshin 			if (reg == 31)
128534c2f668SLeonid Yegoshin 				goto sigbus;
128634c2f668SLeonid Yegoshin 
128734c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 16))
128834c2f668SLeonid Yegoshin 				goto sigbus;
128934c2f668SLeonid Yegoshin 
129034c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
129134c2f668SLeonid Yegoshin 			if (res)
129234c2f668SLeonid Yegoshin 				goto fault;
129334c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
129434c2f668SLeonid Yegoshin 			addr += 8;
129534c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
129634c2f668SLeonid Yegoshin 			if (res)
129734c2f668SLeonid Yegoshin 				goto fault;
129834c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
129934c2f668SLeonid Yegoshin 			goto success;
130034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
130134c2f668SLeonid Yegoshin 
130234c2f668SLeonid Yegoshin 			goto sigill;
130334c2f668SLeonid Yegoshin 
130434c2f668SLeonid Yegoshin 		case mm_sdp_func:
130534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
130634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
130734c2f668SLeonid Yegoshin 			if (reg == 31)
130834c2f668SLeonid Yegoshin 				goto sigbus;
130934c2f668SLeonid Yegoshin 
131034c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 16))
131134c2f668SLeonid Yegoshin 				goto sigbus;
131234c2f668SLeonid Yegoshin 
131334c2f668SLeonid Yegoshin 			value = regs->regs[reg];
131434c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
131534c2f668SLeonid Yegoshin 			if (res)
131634c2f668SLeonid Yegoshin 				goto fault;
131734c2f668SLeonid Yegoshin 			addr += 8;
131834c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
131934c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
132034c2f668SLeonid Yegoshin 			if (res)
132134c2f668SLeonid Yegoshin 				goto fault;
132234c2f668SLeonid Yegoshin 			goto success;
132334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
132434c2f668SLeonid Yegoshin 
132534c2f668SLeonid Yegoshin 			goto sigill;
132634c2f668SLeonid Yegoshin 
132734c2f668SLeonid Yegoshin 		case mm_lwm32_func:
132834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
132934c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
133034c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
133134c2f668SLeonid Yegoshin 				goto sigill;
133234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
133334c2f668SLeonid Yegoshin 				if (!access_ok
133434c2f668SLeonid Yegoshin 				    (VERIFY_READ, addr, 4 * (rvar + 1)))
133534c2f668SLeonid Yegoshin 					goto sigbus;
133634c2f668SLeonid Yegoshin 			} else {
133734c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 4 * rvar))
133834c2f668SLeonid Yegoshin 					goto sigbus;
133934c2f668SLeonid Yegoshin 			}
134034c2f668SLeonid Yegoshin 			if (rvar == 9)
134134c2f668SLeonid Yegoshin 				rvar = 8;
134234c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
134334c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
134434c2f668SLeonid Yegoshin 				if (res)
134534c2f668SLeonid Yegoshin 					goto fault;
134634c2f668SLeonid Yegoshin 				addr += 4;
134734c2f668SLeonid Yegoshin 				regs->regs[i] = value;
134834c2f668SLeonid Yegoshin 			}
134934c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
135034c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
135134c2f668SLeonid Yegoshin 				if (res)
135234c2f668SLeonid Yegoshin 					goto fault;
135334c2f668SLeonid Yegoshin 				addr += 4;
135434c2f668SLeonid Yegoshin 				regs->regs[30] = value;
135534c2f668SLeonid Yegoshin 			}
135634c2f668SLeonid Yegoshin 			if (reg & 0x10) {
135734c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
135834c2f668SLeonid Yegoshin 				if (res)
135934c2f668SLeonid Yegoshin 					goto fault;
136034c2f668SLeonid Yegoshin 				regs->regs[31] = value;
136134c2f668SLeonid Yegoshin 			}
136234c2f668SLeonid Yegoshin 			goto success;
136334c2f668SLeonid Yegoshin 
136434c2f668SLeonid Yegoshin 		case mm_swm32_func:
136534c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
136634c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
136734c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
136834c2f668SLeonid Yegoshin 				goto sigill;
136934c2f668SLeonid Yegoshin 			if (reg & 0x10) {
137034c2f668SLeonid Yegoshin 				if (!access_ok
137134c2f668SLeonid Yegoshin 				    (VERIFY_WRITE, addr, 4 * (rvar + 1)))
137234c2f668SLeonid Yegoshin 					goto sigbus;
137334c2f668SLeonid Yegoshin 			} else {
137434c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
137534c2f668SLeonid Yegoshin 					goto sigbus;
137634c2f668SLeonid Yegoshin 			}
137734c2f668SLeonid Yegoshin 			if (rvar == 9)
137834c2f668SLeonid Yegoshin 				rvar = 8;
137934c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
138034c2f668SLeonid Yegoshin 				value = regs->regs[i];
138134c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
138234c2f668SLeonid Yegoshin 				if (res)
138334c2f668SLeonid Yegoshin 					goto fault;
138434c2f668SLeonid Yegoshin 				addr += 4;
138534c2f668SLeonid Yegoshin 			}
138634c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
138734c2f668SLeonid Yegoshin 				value = regs->regs[30];
138834c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
138934c2f668SLeonid Yegoshin 				if (res)
139034c2f668SLeonid Yegoshin 					goto fault;
139134c2f668SLeonid Yegoshin 				addr += 4;
139234c2f668SLeonid Yegoshin 			}
139334c2f668SLeonid Yegoshin 			if (reg & 0x10) {
139434c2f668SLeonid Yegoshin 				value = regs->regs[31];
139534c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
139634c2f668SLeonid Yegoshin 				if (res)
139734c2f668SLeonid Yegoshin 					goto fault;
139834c2f668SLeonid Yegoshin 			}
139934c2f668SLeonid Yegoshin 			goto success;
140034c2f668SLeonid Yegoshin 
140134c2f668SLeonid Yegoshin 		case mm_ldm_func:
140234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
140334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
140434c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
140534c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
140634c2f668SLeonid Yegoshin 				goto sigill;
140734c2f668SLeonid Yegoshin 			if (reg & 0x10) {
140834c2f668SLeonid Yegoshin 				if (!access_ok
140934c2f668SLeonid Yegoshin 				    (VERIFY_READ, addr, 8 * (rvar + 1)))
141034c2f668SLeonid Yegoshin 					goto sigbus;
141134c2f668SLeonid Yegoshin 			} else {
141234c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 8 * rvar))
141334c2f668SLeonid Yegoshin 					goto sigbus;
141434c2f668SLeonid Yegoshin 			}
141534c2f668SLeonid Yegoshin 			if (rvar == 9)
141634c2f668SLeonid Yegoshin 				rvar = 8;
141734c2f668SLeonid Yegoshin 
141834c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
141934c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
142034c2f668SLeonid Yegoshin 				if (res)
142134c2f668SLeonid Yegoshin 					goto fault;
142234c2f668SLeonid Yegoshin 				addr += 4;
142334c2f668SLeonid Yegoshin 				regs->regs[i] = value;
142434c2f668SLeonid Yegoshin 			}
142534c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
142634c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
142734c2f668SLeonid Yegoshin 				if (res)
142834c2f668SLeonid Yegoshin 					goto fault;
142934c2f668SLeonid Yegoshin 				addr += 8;
143034c2f668SLeonid Yegoshin 				regs->regs[30] = value;
143134c2f668SLeonid Yegoshin 			}
143234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
143334c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
143434c2f668SLeonid Yegoshin 				if (res)
143534c2f668SLeonid Yegoshin 					goto fault;
143634c2f668SLeonid Yegoshin 				regs->regs[31] = value;
143734c2f668SLeonid Yegoshin 			}
143834c2f668SLeonid Yegoshin 			goto success;
143934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
144034c2f668SLeonid Yegoshin 
144134c2f668SLeonid Yegoshin 			goto sigill;
144234c2f668SLeonid Yegoshin 
144334c2f668SLeonid Yegoshin 		case mm_sdm_func:
144434c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
144534c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
144634c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
144734c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
144834c2f668SLeonid Yegoshin 				goto sigill;
144934c2f668SLeonid Yegoshin 			if (reg & 0x10) {
145034c2f668SLeonid Yegoshin 				if (!access_ok
145134c2f668SLeonid Yegoshin 				    (VERIFY_WRITE, addr, 8 * (rvar + 1)))
145234c2f668SLeonid Yegoshin 					goto sigbus;
145334c2f668SLeonid Yegoshin 			} else {
145434c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 8 * rvar))
145534c2f668SLeonid Yegoshin 					goto sigbus;
145634c2f668SLeonid Yegoshin 			}
145734c2f668SLeonid Yegoshin 			if (rvar == 9)
145834c2f668SLeonid Yegoshin 				rvar = 8;
145934c2f668SLeonid Yegoshin 
146034c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
146134c2f668SLeonid Yegoshin 				value = regs->regs[i];
146234c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
146334c2f668SLeonid Yegoshin 				if (res)
146434c2f668SLeonid Yegoshin 					goto fault;
146534c2f668SLeonid Yegoshin 				addr += 8;
146634c2f668SLeonid Yegoshin 			}
146734c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
146834c2f668SLeonid Yegoshin 				value = regs->regs[30];
146934c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
147034c2f668SLeonid Yegoshin 				if (res)
147134c2f668SLeonid Yegoshin 					goto fault;
147234c2f668SLeonid Yegoshin 				addr += 8;
147334c2f668SLeonid Yegoshin 			}
147434c2f668SLeonid Yegoshin 			if (reg & 0x10) {
147534c2f668SLeonid Yegoshin 				value = regs->regs[31];
147634c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
147734c2f668SLeonid Yegoshin 				if (res)
147834c2f668SLeonid Yegoshin 					goto fault;
147934c2f668SLeonid Yegoshin 			}
148034c2f668SLeonid Yegoshin 			goto success;
148134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
148234c2f668SLeonid Yegoshin 
148334c2f668SLeonid Yegoshin 			goto sigill;
148434c2f668SLeonid Yegoshin 
148534c2f668SLeonid Yegoshin 			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
148634c2f668SLeonid Yegoshin 		}
148734c2f668SLeonid Yegoshin 
148834c2f668SLeonid Yegoshin 		goto sigbus;
148934c2f668SLeonid Yegoshin 
149034c2f668SLeonid Yegoshin 	case mm_pool32c_op:
149134c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
149234c2f668SLeonid Yegoshin 		case mm_lwu_func:
149334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
149434c2f668SLeonid Yegoshin 			goto loadWU;
149534c2f668SLeonid Yegoshin 		}
149634c2f668SLeonid Yegoshin 
149734c2f668SLeonid Yegoshin 		/*  LL,SC,LLD,SCD are not serviced */
149834c2f668SLeonid Yegoshin 		goto sigbus;
149934c2f668SLeonid Yegoshin 
150034c2f668SLeonid Yegoshin 	case mm_pool32f_op:
150134c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
150234c2f668SLeonid Yegoshin 		case mm_lwxc1_func:
150334c2f668SLeonid Yegoshin 		case mm_swxc1_func:
150434c2f668SLeonid Yegoshin 		case mm_ldxc1_func:
150534c2f668SLeonid Yegoshin 		case mm_sdxc1_func:
150634c2f668SLeonid Yegoshin 			goto fpu_emul;
150734c2f668SLeonid Yegoshin 		}
150834c2f668SLeonid Yegoshin 
150934c2f668SLeonid Yegoshin 		goto sigbus;
151034c2f668SLeonid Yegoshin 
151134c2f668SLeonid Yegoshin 	case mm_ldc132_op:
151234c2f668SLeonid Yegoshin 	case mm_sdc132_op:
151334c2f668SLeonid Yegoshin 	case mm_lwc132_op:
151434c2f668SLeonid Yegoshin 	case mm_swc132_op:
151534c2f668SLeonid Yegoshin fpu_emul:
151634c2f668SLeonid Yegoshin 		/* roll back jump/branch */
151734c2f668SLeonid Yegoshin 		regs->cp0_epc = origpc;
151834c2f668SLeonid Yegoshin 		regs->regs[31] = orig31;
151934c2f668SLeonid Yegoshin 
152034c2f668SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
152134c2f668SLeonid Yegoshin 		BUG_ON(!used_math());
152234c2f668SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
152334c2f668SLeonid Yegoshin 
152434c2f668SLeonid Yegoshin 		lose_fpu(1);	/* save the FPU state for the emulator */
152534c2f668SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
152634c2f668SLeonid Yegoshin 					       &fault_addr);
152734c2f668SLeonid Yegoshin 		own_fpu(1);	/* restore FPU state */
152834c2f668SLeonid Yegoshin 
152934c2f668SLeonid Yegoshin 		/* If something went wrong, signal */
153034c2f668SLeonid Yegoshin 		process_fpemu_return(res, fault_addr);
153134c2f668SLeonid Yegoshin 
153234c2f668SLeonid Yegoshin 		if (res == 0)
153334c2f668SLeonid Yegoshin 			goto success;
153434c2f668SLeonid Yegoshin 		return;
153534c2f668SLeonid Yegoshin 
153634c2f668SLeonid Yegoshin 	case mm_lh32_op:
153734c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
153834c2f668SLeonid Yegoshin 		goto loadHW;
153934c2f668SLeonid Yegoshin 
154034c2f668SLeonid Yegoshin 	case mm_lhu32_op:
154134c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
154234c2f668SLeonid Yegoshin 		goto loadHWU;
154334c2f668SLeonid Yegoshin 
154434c2f668SLeonid Yegoshin 	case mm_lw32_op:
154534c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
154634c2f668SLeonid Yegoshin 		goto loadW;
154734c2f668SLeonid Yegoshin 
154834c2f668SLeonid Yegoshin 	case mm_sh32_op:
154934c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
155034c2f668SLeonid Yegoshin 		goto storeHW;
155134c2f668SLeonid Yegoshin 
155234c2f668SLeonid Yegoshin 	case mm_sw32_op:
155334c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
155434c2f668SLeonid Yegoshin 		goto storeW;
155534c2f668SLeonid Yegoshin 
155634c2f668SLeonid Yegoshin 	case mm_ld32_op:
155734c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
155834c2f668SLeonid Yegoshin 		goto loadDW;
155934c2f668SLeonid Yegoshin 
156034c2f668SLeonid Yegoshin 	case mm_sd32_op:
156134c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
156234c2f668SLeonid Yegoshin 		goto storeDW;
156334c2f668SLeonid Yegoshin 
156434c2f668SLeonid Yegoshin 	case mm_pool16c_op:
156534c2f668SLeonid Yegoshin 		switch (insn.mm16_m_format.func) {
156634c2f668SLeonid Yegoshin 		case mm_lwm16_op:
156734c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
156834c2f668SLeonid Yegoshin 			rvar = reg + 1;
156934c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 4 * rvar))
157034c2f668SLeonid Yegoshin 				goto sigbus;
157134c2f668SLeonid Yegoshin 
157234c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
157334c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
157434c2f668SLeonid Yegoshin 				if (res)
157534c2f668SLeonid Yegoshin 					goto fault;
157634c2f668SLeonid Yegoshin 				addr += 4;
157734c2f668SLeonid Yegoshin 				regs->regs[i] = value;
157834c2f668SLeonid Yegoshin 			}
157934c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
158034c2f668SLeonid Yegoshin 			if (res)
158134c2f668SLeonid Yegoshin 				goto fault;
158234c2f668SLeonid Yegoshin 			regs->regs[31] = value;
158334c2f668SLeonid Yegoshin 
158434c2f668SLeonid Yegoshin 			goto success;
158534c2f668SLeonid Yegoshin 
158634c2f668SLeonid Yegoshin 		case mm_swm16_op:
158734c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
158834c2f668SLeonid Yegoshin 			rvar = reg + 1;
158934c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
159034c2f668SLeonid Yegoshin 				goto sigbus;
159134c2f668SLeonid Yegoshin 
159234c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
159334c2f668SLeonid Yegoshin 				value = regs->regs[i];
159434c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
159534c2f668SLeonid Yegoshin 				if (res)
159634c2f668SLeonid Yegoshin 					goto fault;
159734c2f668SLeonid Yegoshin 				addr += 4;
159834c2f668SLeonid Yegoshin 			}
159934c2f668SLeonid Yegoshin 			value = regs->regs[31];
160034c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
160134c2f668SLeonid Yegoshin 			if (res)
160234c2f668SLeonid Yegoshin 				goto fault;
160334c2f668SLeonid Yegoshin 
160434c2f668SLeonid Yegoshin 			goto success;
160534c2f668SLeonid Yegoshin 
160634c2f668SLeonid Yegoshin 		}
160734c2f668SLeonid Yegoshin 
160834c2f668SLeonid Yegoshin 		goto sigbus;
160934c2f668SLeonid Yegoshin 
161034c2f668SLeonid Yegoshin 	case mm_lhu16_op:
161134c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
161234c2f668SLeonid Yegoshin 		goto loadHWU;
161334c2f668SLeonid Yegoshin 
161434c2f668SLeonid Yegoshin 	case mm_lw16_op:
161534c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
161634c2f668SLeonid Yegoshin 		goto loadW;
161734c2f668SLeonid Yegoshin 
161834c2f668SLeonid Yegoshin 	case mm_sh16_op:
161934c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
162034c2f668SLeonid Yegoshin 		goto storeHW;
162134c2f668SLeonid Yegoshin 
162234c2f668SLeonid Yegoshin 	case mm_sw16_op:
162334c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
162434c2f668SLeonid Yegoshin 		goto storeW;
162534c2f668SLeonid Yegoshin 
162634c2f668SLeonid Yegoshin 	case mm_lwsp16_op:
162734c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
162834c2f668SLeonid Yegoshin 		goto loadW;
162934c2f668SLeonid Yegoshin 
163034c2f668SLeonid Yegoshin 	case mm_swsp16_op:
163134c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
163234c2f668SLeonid Yegoshin 		goto storeW;
163334c2f668SLeonid Yegoshin 
163434c2f668SLeonid Yegoshin 	case mm_lwgp16_op:
163534c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_r3_format.rt];
163634c2f668SLeonid Yegoshin 		goto loadW;
163734c2f668SLeonid Yegoshin 
163834c2f668SLeonid Yegoshin 	default:
163934c2f668SLeonid Yegoshin 		goto sigill;
164034c2f668SLeonid Yegoshin 	}
164134c2f668SLeonid Yegoshin 
164234c2f668SLeonid Yegoshin loadHW:
164334c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 2))
164434c2f668SLeonid Yegoshin 		goto sigbus;
164534c2f668SLeonid Yegoshin 
164634c2f668SLeonid Yegoshin 	LoadHW(addr, value, res);
164734c2f668SLeonid Yegoshin 	if (res)
164834c2f668SLeonid Yegoshin 		goto fault;
164934c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
165034c2f668SLeonid Yegoshin 	goto success;
165134c2f668SLeonid Yegoshin 
165234c2f668SLeonid Yegoshin loadHWU:
165334c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 2))
165434c2f668SLeonid Yegoshin 		goto sigbus;
165534c2f668SLeonid Yegoshin 
165634c2f668SLeonid Yegoshin 	LoadHWU(addr, value, res);
165734c2f668SLeonid Yegoshin 	if (res)
165834c2f668SLeonid Yegoshin 		goto fault;
165934c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
166034c2f668SLeonid Yegoshin 	goto success;
166134c2f668SLeonid Yegoshin 
166234c2f668SLeonid Yegoshin loadW:
166334c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 4))
166434c2f668SLeonid Yegoshin 		goto sigbus;
166534c2f668SLeonid Yegoshin 
166634c2f668SLeonid Yegoshin 	LoadW(addr, value, res);
166734c2f668SLeonid Yegoshin 	if (res)
166834c2f668SLeonid Yegoshin 		goto fault;
166934c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
167034c2f668SLeonid Yegoshin 	goto success;
167134c2f668SLeonid Yegoshin 
167234c2f668SLeonid Yegoshin loadWU:
167334c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
167434c2f668SLeonid Yegoshin 	/*
167534c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
167634c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
167734c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
167834c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
167934c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
168034c2f668SLeonid Yegoshin 	 */
168134c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 4))
168234c2f668SLeonid Yegoshin 		goto sigbus;
168334c2f668SLeonid Yegoshin 
168434c2f668SLeonid Yegoshin 	LoadWU(addr, value, res);
168534c2f668SLeonid Yegoshin 	if (res)
168634c2f668SLeonid Yegoshin 		goto fault;
168734c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
168834c2f668SLeonid Yegoshin 	goto success;
168934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
169034c2f668SLeonid Yegoshin 
169134c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
169234c2f668SLeonid Yegoshin 	goto sigill;
169334c2f668SLeonid Yegoshin 
169434c2f668SLeonid Yegoshin loadDW:
169534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
169634c2f668SLeonid Yegoshin 	/*
169734c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
169834c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
169934c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
170034c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
170134c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
170234c2f668SLeonid Yegoshin 	 */
170334c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 8))
170434c2f668SLeonid Yegoshin 		goto sigbus;
170534c2f668SLeonid Yegoshin 
170634c2f668SLeonid Yegoshin 	LoadDW(addr, value, res);
170734c2f668SLeonid Yegoshin 	if (res)
170834c2f668SLeonid Yegoshin 		goto fault;
170934c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
171034c2f668SLeonid Yegoshin 	goto success;
171134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
171234c2f668SLeonid Yegoshin 
171334c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
171434c2f668SLeonid Yegoshin 	goto sigill;
171534c2f668SLeonid Yegoshin 
171634c2f668SLeonid Yegoshin storeHW:
171734c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 2))
171834c2f668SLeonid Yegoshin 		goto sigbus;
171934c2f668SLeonid Yegoshin 
172034c2f668SLeonid Yegoshin 	value = regs->regs[reg];
172134c2f668SLeonid Yegoshin 	StoreHW(addr, value, res);
172234c2f668SLeonid Yegoshin 	if (res)
172334c2f668SLeonid Yegoshin 		goto fault;
172434c2f668SLeonid Yegoshin 	goto success;
172534c2f668SLeonid Yegoshin 
172634c2f668SLeonid Yegoshin storeW:
172734c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 4))
172834c2f668SLeonid Yegoshin 		goto sigbus;
172934c2f668SLeonid Yegoshin 
173034c2f668SLeonid Yegoshin 	value = regs->regs[reg];
173134c2f668SLeonid Yegoshin 	StoreW(addr, value, res);
173234c2f668SLeonid Yegoshin 	if (res)
173334c2f668SLeonid Yegoshin 		goto fault;
173434c2f668SLeonid Yegoshin 	goto success;
173534c2f668SLeonid Yegoshin 
173634c2f668SLeonid Yegoshin storeDW:
173734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
173834c2f668SLeonid Yegoshin 	/*
173934c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
174034c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
174134c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
174234c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
174334c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
174434c2f668SLeonid Yegoshin 	 */
174534c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 8))
174634c2f668SLeonid Yegoshin 		goto sigbus;
174734c2f668SLeonid Yegoshin 
174834c2f668SLeonid Yegoshin 	value = regs->regs[reg];
174934c2f668SLeonid Yegoshin 	StoreDW(addr, value, res);
175034c2f668SLeonid Yegoshin 	if (res)
175134c2f668SLeonid Yegoshin 		goto fault;
175234c2f668SLeonid Yegoshin 	goto success;
175334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
175434c2f668SLeonid Yegoshin 
175534c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
175634c2f668SLeonid Yegoshin 	goto sigill;
175734c2f668SLeonid Yegoshin 
175834c2f668SLeonid Yegoshin success:
175934c2f668SLeonid Yegoshin 	regs->cp0_epc = contpc;	/* advance or branch */
176034c2f668SLeonid Yegoshin 
176134c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
176234c2f668SLeonid Yegoshin 	unaligned_instructions++;
176334c2f668SLeonid Yegoshin #endif
176434c2f668SLeonid Yegoshin 	return;
176534c2f668SLeonid Yegoshin 
176634c2f668SLeonid Yegoshin fault:
176734c2f668SLeonid Yegoshin 	/* roll back jump/branch */
176834c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
176934c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
177034c2f668SLeonid Yegoshin 	/* Did we have an exception handler installed? */
177134c2f668SLeonid Yegoshin 	if (fixup_exception(regs))
177234c2f668SLeonid Yegoshin 		return;
177334c2f668SLeonid Yegoshin 
177434c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
177534c2f668SLeonid Yegoshin 	force_sig(SIGSEGV, current);
177634c2f668SLeonid Yegoshin 
177734c2f668SLeonid Yegoshin 	return;
177834c2f668SLeonid Yegoshin 
177934c2f668SLeonid Yegoshin sigbus:
178034c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
178134c2f668SLeonid Yegoshin 	force_sig(SIGBUS, current);
178234c2f668SLeonid Yegoshin 
178334c2f668SLeonid Yegoshin 	return;
178434c2f668SLeonid Yegoshin 
178534c2f668SLeonid Yegoshin sigill:
178634c2f668SLeonid Yegoshin 	die_if_kernel
178734c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
1788a6d5ff04SDavid Daney 	force_sig(SIGILL, current);
17891da177e4SLinus Torvalds }
17901da177e4SLinus Torvalds 
1791451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1792451b001bSSteven J. Hill {
1793451b001bSSteven J. Hill 	unsigned long value;
1794451b001bSSteven J. Hill 	unsigned int res;
1795451b001bSSteven J. Hill 	int reg;
1796451b001bSSteven J. Hill 	unsigned long orig31;
1797451b001bSSteven J. Hill 	u16 __user *pc16;
1798451b001bSSteven J. Hill 	unsigned long origpc;
1799451b001bSSteven J. Hill 	union mips16e_instruction mips16inst, oldinst;
1800451b001bSSteven J. Hill 
1801451b001bSSteven J. Hill 	origpc = regs->cp0_epc;
1802451b001bSSteven J. Hill 	orig31 = regs->regs[31];
1803451b001bSSteven J. Hill 	pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1804451b001bSSteven J. Hill 	/*
1805451b001bSSteven J. Hill 	 * This load never faults.
1806451b001bSSteven J. Hill 	 */
1807451b001bSSteven J. Hill 	__get_user(mips16inst.full, pc16);
1808451b001bSSteven J. Hill 	oldinst = mips16inst;
1809451b001bSSteven J. Hill 
1810451b001bSSteven J. Hill 	/* skip EXTEND instruction */
1811451b001bSSteven J. Hill 	if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1812451b001bSSteven J. Hill 		pc16++;
1813451b001bSSteven J. Hill 		__get_user(mips16inst.full, pc16);
1814451b001bSSteven J. Hill 	} else if (delay_slot(regs)) {
1815451b001bSSteven J. Hill 		/*  skip jump instructions */
1816451b001bSSteven J. Hill 		/*  JAL/JALX are 32 bits but have OPCODE in first short int */
1817451b001bSSteven J. Hill 		if (mips16inst.ri.opcode == MIPS16e_jal_op)
1818451b001bSSteven J. Hill 			pc16++;
1819451b001bSSteven J. Hill 		pc16++;
1820451b001bSSteven J. Hill 		if (get_user(mips16inst.full, pc16))
1821451b001bSSteven J. Hill 			goto sigbus;
1822451b001bSSteven J. Hill 	}
1823451b001bSSteven J. Hill 
1824451b001bSSteven J. Hill 	switch (mips16inst.ri.opcode) {
1825451b001bSSteven J. Hill 	case MIPS16e_i64_op:	/* I64 or RI64 instruction */
1826451b001bSSteven J. Hill 		switch (mips16inst.i64.func) {	/* I64/RI64 func field check */
1827451b001bSSteven J. Hill 		case MIPS16e_ldpc_func:
1828451b001bSSteven J. Hill 		case MIPS16e_ldsp_func:
1829451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1830451b001bSSteven J. Hill 			goto loadDW;
1831451b001bSSteven J. Hill 
1832451b001bSSteven J. Hill 		case MIPS16e_sdsp_func:
1833451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1834451b001bSSteven J. Hill 			goto writeDW;
1835451b001bSSteven J. Hill 
1836451b001bSSteven J. Hill 		case MIPS16e_sdrasp_func:
1837451b001bSSteven J. Hill 			reg = 29;	/* GPRSP */
1838451b001bSSteven J. Hill 			goto writeDW;
1839451b001bSSteven J. Hill 		}
1840451b001bSSteven J. Hill 
1841451b001bSSteven J. Hill 		goto sigbus;
1842451b001bSSteven J. Hill 
1843451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1844451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1845451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1846451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.ri.rx];
1847451b001bSSteven J. Hill 		break;
1848451b001bSSteven J. Hill 
1849451b001bSSteven J. Hill 	case MIPS16e_i8_op:
1850451b001bSSteven J. Hill 		if (mips16inst.i8.func != MIPS16e_swrasp_func)
1851451b001bSSteven J. Hill 			goto sigbus;
1852451b001bSSteven J. Hill 		reg = 29;	/* GPRSP */
1853451b001bSSteven J. Hill 		break;
1854451b001bSSteven J. Hill 
1855451b001bSSteven J. Hill 	default:
1856451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.rri.ry];
1857451b001bSSteven J. Hill 		break;
1858451b001bSSteven J. Hill 	}
1859451b001bSSteven J. Hill 
1860451b001bSSteven J. Hill 	switch (mips16inst.ri.opcode) {
1861451b001bSSteven J. Hill 
1862451b001bSSteven J. Hill 	case MIPS16e_lb_op:
1863451b001bSSteven J. Hill 	case MIPS16e_lbu_op:
1864451b001bSSteven J. Hill 	case MIPS16e_sb_op:
1865451b001bSSteven J. Hill 		goto sigbus;
1866451b001bSSteven J. Hill 
1867451b001bSSteven J. Hill 	case MIPS16e_lh_op:
1868451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 2))
1869451b001bSSteven J. Hill 			goto sigbus;
1870451b001bSSteven J. Hill 
1871451b001bSSteven J. Hill 		LoadHW(addr, value, res);
1872451b001bSSteven J. Hill 		if (res)
1873451b001bSSteven J. Hill 			goto fault;
1874451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1875451b001bSSteven J. Hill 		regs->regs[reg] = value;
1876451b001bSSteven J. Hill 		break;
1877451b001bSSteven J. Hill 
1878451b001bSSteven J. Hill 	case MIPS16e_lhu_op:
1879451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 2))
1880451b001bSSteven J. Hill 			goto sigbus;
1881451b001bSSteven J. Hill 
1882451b001bSSteven J. Hill 		LoadHWU(addr, value, res);
1883451b001bSSteven J. Hill 		if (res)
1884451b001bSSteven J. Hill 			goto fault;
1885451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1886451b001bSSteven J. Hill 		regs->regs[reg] = value;
1887451b001bSSteven J. Hill 		break;
1888451b001bSSteven J. Hill 
1889451b001bSSteven J. Hill 	case MIPS16e_lw_op:
1890451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1891451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1892451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 4))
1893451b001bSSteven J. Hill 			goto sigbus;
1894451b001bSSteven J. Hill 
1895451b001bSSteven J. Hill 		LoadW(addr, value, res);
1896451b001bSSteven J. Hill 		if (res)
1897451b001bSSteven J. Hill 			goto fault;
1898451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1899451b001bSSteven J. Hill 		regs->regs[reg] = value;
1900451b001bSSteven J. Hill 		break;
1901451b001bSSteven J. Hill 
1902451b001bSSteven J. Hill 	case MIPS16e_lwu_op:
1903451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1904451b001bSSteven J. Hill 		/*
1905451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1906451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1907451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1908451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1909451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1910451b001bSSteven J. Hill 		 */
1911451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 4))
1912451b001bSSteven J. Hill 			goto sigbus;
1913451b001bSSteven J. Hill 
1914451b001bSSteven J. Hill 		LoadWU(addr, value, res);
1915451b001bSSteven J. Hill 		if (res)
1916451b001bSSteven J. Hill 			goto fault;
1917451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1918451b001bSSteven J. Hill 		regs->regs[reg] = value;
1919451b001bSSteven J. Hill 		break;
1920451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1921451b001bSSteven J. Hill 
1922451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1923451b001bSSteven J. Hill 		goto sigill;
1924451b001bSSteven J. Hill 
1925451b001bSSteven J. Hill 	case MIPS16e_ld_op:
1926451b001bSSteven J. Hill loadDW:
1927451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1928451b001bSSteven J. Hill 		/*
1929451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1930451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1931451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1932451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1933451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1934451b001bSSteven J. Hill 		 */
1935451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 8))
1936451b001bSSteven J. Hill 			goto sigbus;
1937451b001bSSteven J. Hill 
1938451b001bSSteven J. Hill 		LoadDW(addr, value, res);
1939451b001bSSteven J. Hill 		if (res)
1940451b001bSSteven J. Hill 			goto fault;
1941451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1942451b001bSSteven J. Hill 		regs->regs[reg] = value;
1943451b001bSSteven J. Hill 		break;
1944451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1945451b001bSSteven J. Hill 
1946451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1947451b001bSSteven J. Hill 		goto sigill;
1948451b001bSSteven J. Hill 
1949451b001bSSteven J. Hill 	case MIPS16e_sh_op:
1950451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 2))
1951451b001bSSteven J. Hill 			goto sigbus;
1952451b001bSSteven J. Hill 
1953451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1954451b001bSSteven J. Hill 		value = regs->regs[reg];
1955451b001bSSteven J. Hill 		StoreHW(addr, value, res);
1956451b001bSSteven J. Hill 		if (res)
1957451b001bSSteven J. Hill 			goto fault;
1958451b001bSSteven J. Hill 		break;
1959451b001bSSteven J. Hill 
1960451b001bSSteven J. Hill 	case MIPS16e_sw_op:
1961451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1962451b001bSSteven J. Hill 	case MIPS16e_i8_op:	/* actually - MIPS16e_swrasp_func */
1963451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 4))
1964451b001bSSteven J. Hill 			goto sigbus;
1965451b001bSSteven J. Hill 
1966451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1967451b001bSSteven J. Hill 		value = regs->regs[reg];
1968451b001bSSteven J. Hill 		StoreW(addr, value, res);
1969451b001bSSteven J. Hill 		if (res)
1970451b001bSSteven J. Hill 			goto fault;
1971451b001bSSteven J. Hill 		break;
1972451b001bSSteven J. Hill 
1973451b001bSSteven J. Hill 	case MIPS16e_sd_op:
1974451b001bSSteven J. Hill writeDW:
1975451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1976451b001bSSteven J. Hill 		/*
1977451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1978451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1979451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1980451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1981451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1982451b001bSSteven J. Hill 		 */
1983451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 8))
1984451b001bSSteven J. Hill 			goto sigbus;
1985451b001bSSteven J. Hill 
1986451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1987451b001bSSteven J. Hill 		value = regs->regs[reg];
1988451b001bSSteven J. Hill 		StoreDW(addr, value, res);
1989451b001bSSteven J. Hill 		if (res)
1990451b001bSSteven J. Hill 			goto fault;
1991451b001bSSteven J. Hill 		break;
1992451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1993451b001bSSteven J. Hill 
1994451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1995451b001bSSteven J. Hill 		goto sigill;
1996451b001bSSteven J. Hill 
1997451b001bSSteven J. Hill 	default:
1998451b001bSSteven J. Hill 		/*
1999451b001bSSteven J. Hill 		 * Pheeee...  We encountered an yet unknown instruction or
2000451b001bSSteven J. Hill 		 * cache coherence problem.  Die sucker, die ...
2001451b001bSSteven J. Hill 		 */
2002451b001bSSteven J. Hill 		goto sigill;
2003451b001bSSteven J. Hill 	}
2004451b001bSSteven J. Hill 
2005451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
2006451b001bSSteven J. Hill 	unaligned_instructions++;
2007451b001bSSteven J. Hill #endif
2008451b001bSSteven J. Hill 
2009451b001bSSteven J. Hill 	return;
2010451b001bSSteven J. Hill 
2011451b001bSSteven J. Hill fault:
2012451b001bSSteven J. Hill 	/* roll back jump/branch */
2013451b001bSSteven J. Hill 	regs->cp0_epc = origpc;
2014451b001bSSteven J. Hill 	regs->regs[31] = orig31;
2015451b001bSSteven J. Hill 	/* Did we have an exception handler installed? */
2016451b001bSSteven J. Hill 	if (fixup_exception(regs))
2017451b001bSSteven J. Hill 		return;
2018451b001bSSteven J. Hill 
2019451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
2020451b001bSSteven J. Hill 	force_sig(SIGSEGV, current);
2021451b001bSSteven J. Hill 
2022451b001bSSteven J. Hill 	return;
2023451b001bSSteven J. Hill 
2024451b001bSSteven J. Hill sigbus:
2025451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
2026451b001bSSteven J. Hill 	force_sig(SIGBUS, current);
2027451b001bSSteven J. Hill 
2028451b001bSSteven J. Hill 	return;
2029451b001bSSteven J. Hill 
2030451b001bSSteven J. Hill sigill:
2031451b001bSSteven J. Hill 	die_if_kernel
2032451b001bSSteven J. Hill 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
2033451b001bSSteven J. Hill 	force_sig(SIGILL, current);
2034451b001bSSteven J. Hill }
2035fc192e50STony Wu 
20361da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
20371da177e4SLinus Torvalds {
2038c3fc5cd5SRalf Baechle 	enum ctx_state prev_state;
2039fe00f943SRalf Baechle 	unsigned int __user *pc;
20401da177e4SLinus Torvalds 	mm_segment_t seg;
20411da177e4SLinus Torvalds 
2042c3fc5cd5SRalf Baechle 	prev_state = exception_enter();
20437f788d2dSDeng-Cheng Zhu 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
2044a8b0ca17SPeter Zijlstra 			1, regs, regs->cp0_badvaddr);
20451da177e4SLinus Torvalds 	/*
20461da177e4SLinus Torvalds 	 * Did we catch a fault trying to load an instruction?
20471da177e4SLinus Torvalds 	 */
204834c2f668SLeonid Yegoshin 	if (regs->cp0_badvaddr == regs->cp0_epc)
20491da177e4SLinus Torvalds 		goto sigbus;
20501da177e4SLinus Torvalds 
2051293c5bd1SRalf Baechle 	if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
20521da177e4SLinus Torvalds 		goto sigbus;
20536312e0eeSAtsushi Nemoto 	if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
20546312e0eeSAtsushi Nemoto 		goto sigbus;
20551da177e4SLinus Torvalds 
20561da177e4SLinus Torvalds 	/*
20571da177e4SLinus Torvalds 	 * Do branch emulation only if we didn't forward the exception.
20581da177e4SLinus Torvalds 	 * This is all so but ugly ...
20591da177e4SLinus Torvalds 	 */
206034c2f668SLeonid Yegoshin 
206134c2f668SLeonid Yegoshin 	/*
206234c2f668SLeonid Yegoshin 	 * Are we running in microMIPS mode?
206334c2f668SLeonid Yegoshin 	 */
206434c2f668SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
206534c2f668SLeonid Yegoshin 		/*
206634c2f668SLeonid Yegoshin 		 * Did we catch a fault trying to load an instruction in
206734c2f668SLeonid Yegoshin 		 * 16-bit mode?
206834c2f668SLeonid Yegoshin 		 */
206934c2f668SLeonid Yegoshin 		if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
207034c2f668SLeonid Yegoshin 			goto sigbus;
207134c2f668SLeonid Yegoshin 		if (unaligned_action == UNALIGNED_ACTION_SHOW)
207234c2f668SLeonid Yegoshin 			show_registers(regs);
207334c2f668SLeonid Yegoshin 
207434c2f668SLeonid Yegoshin 		if (cpu_has_mmips) {
207534c2f668SLeonid Yegoshin 			seg = get_fs();
207634c2f668SLeonid Yegoshin 			if (!user_mode(regs))
207734c2f668SLeonid Yegoshin 				set_fs(KERNEL_DS);
207834c2f668SLeonid Yegoshin 			emulate_load_store_microMIPS(regs,
207934c2f668SLeonid Yegoshin 				(void __user *)regs->cp0_badvaddr);
208034c2f668SLeonid Yegoshin 			set_fs(seg);
208134c2f668SLeonid Yegoshin 
208234c2f668SLeonid Yegoshin 			return;
208334c2f668SLeonid Yegoshin 		}
208434c2f668SLeonid Yegoshin 
2085451b001bSSteven J. Hill 		if (cpu_has_mips16) {
2086451b001bSSteven J. Hill 			seg = get_fs();
2087451b001bSSteven J. Hill 			if (!user_mode(regs))
2088451b001bSSteven J. Hill 				set_fs(KERNEL_DS);
2089451b001bSSteven J. Hill 			emulate_load_store_MIPS16e(regs,
2090451b001bSSteven J. Hill 				(void __user *)regs->cp0_badvaddr);
2091451b001bSSteven J. Hill 			set_fs(seg);
2092451b001bSSteven J. Hill 
2093451b001bSSteven J. Hill 			return;
2094451b001bSSteven J. Hill 	}
2095451b001bSSteven J. Hill 
209634c2f668SLeonid Yegoshin 		goto sigbus;
209734c2f668SLeonid Yegoshin 	}
209834c2f668SLeonid Yegoshin 
209934c2f668SLeonid Yegoshin 	if (unaligned_action == UNALIGNED_ACTION_SHOW)
210034c2f668SLeonid Yegoshin 		show_registers(regs);
210134c2f668SLeonid Yegoshin 	pc = (unsigned int __user *)exception_epc(regs);
210234c2f668SLeonid Yegoshin 
21031da177e4SLinus Torvalds 	seg = get_fs();
21041da177e4SLinus Torvalds 	if (!user_mode(regs))
21051da177e4SLinus Torvalds 		set_fs(KERNEL_DS);
21067f18f151SRalf Baechle 	emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
21071da177e4SLinus Torvalds 	set_fs(seg);
21081da177e4SLinus Torvalds 
21091da177e4SLinus Torvalds 	return;
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds sigbus:
21121da177e4SLinus Torvalds 	die_if_kernel("Kernel unaligned instruction access", regs);
21131da177e4SLinus Torvalds 	force_sig(SIGBUS, current);
21141da177e4SLinus Torvalds 
21151da177e4SLinus Torvalds 	/*
21161da177e4SLinus Torvalds 	 * XXX On return from the signal handler we should advance the epc
21171da177e4SLinus Torvalds 	 */
2118c3fc5cd5SRalf Baechle 	exception_exit(prev_state);
21191da177e4SLinus Torvalds }
21206312e0eeSAtsushi Nemoto 
21216312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
21226312e0eeSAtsushi Nemoto extern struct dentry *mips_debugfs_dir;
21236312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
21246312e0eeSAtsushi Nemoto {
21256312e0eeSAtsushi Nemoto 	struct dentry *d;
21266312e0eeSAtsushi Nemoto 
21276312e0eeSAtsushi Nemoto 	if (!mips_debugfs_dir)
21286312e0eeSAtsushi Nemoto 		return -ENODEV;
21296312e0eeSAtsushi Nemoto 	d = debugfs_create_u32("unaligned_instructions", S_IRUGO,
21306312e0eeSAtsushi Nemoto 			       mips_debugfs_dir, &unaligned_instructions);
2131b517531cSZhaolei 	if (!d)
2132b517531cSZhaolei 		return -ENOMEM;
21336312e0eeSAtsushi Nemoto 	d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
21346312e0eeSAtsushi Nemoto 			       mips_debugfs_dir, &unaligned_action);
2135b517531cSZhaolei 	if (!d)
2136b517531cSZhaolei 		return -ENOMEM;
21376312e0eeSAtsushi Nemoto 	return 0;
21386312e0eeSAtsushi Nemoto }
21396312e0eeSAtsushi Nemoto __initcall(debugfs_unaligned);
21406312e0eeSAtsushi Nemoto #endif
2141