xref: /linux/arch/mips/kernel/unaligned.c (revision b7fc2cc59aa5f49ecd1eae4f90ec229a7e52c47c)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Handle unaligned accesses by emulation.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
51da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
61da177e4SLinus Torvalds  * for more details.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
91da177e4SLinus Torvalds  * Copyright (C) 1999 Silicon Graphics, Inc.
109d8e5736SMarkos Chandras  * Copyright (C) 2014 Imagination Technologies Ltd.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * This file contains exception handler for address error exception with the
131da177e4SLinus Torvalds  * special capability to execute faulting instructions in software.  The
141da177e4SLinus Torvalds  * handler does not try to handle the case when the program counter points
151da177e4SLinus Torvalds  * to an address not aligned to a word boundary.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * Putting data to unaligned addresses is a bad practice even on Intel where
181da177e4SLinus Torvalds  * only the performance is affected.  Much worse is that such code is non-
191da177e4SLinus Torvalds  * portable.  Due to several programs that die on MIPS due to alignment
201da177e4SLinus Torvalds  * problems I decided to implement this handler anyway though I originally
211da177e4SLinus Torvalds  * didn't intend to do this at all for user code.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * For now I enable fixing of address errors by default to make life easier.
241da177e4SLinus Torvalds  * I however intend to disable this somewhen in the future when the alignment
251da177e4SLinus Torvalds  * problems with user programs have been fixed.	 For programmers this is the
261da177e4SLinus Torvalds  * right way to go.
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  * Fixing address errors is a per process option.  The option is inherited
291da177e4SLinus Torvalds  * across fork(2) and execve(2) calls.	If you really want to use the
301da177e4SLinus Torvalds  * option in your user programs - I discourage the use of the software
311da177e4SLinus Torvalds  * emulation strongly - use the following code in your userland stuff:
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * #include <sys/sysmips.h>
341da177e4SLinus Torvalds  *
351da177e4SLinus Torvalds  * ...
361da177e4SLinus Torvalds  * sysmips(MIPS_FIXADE, x);
371da177e4SLinus Torvalds  * ...
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds  * The argument x is 0 for disabling software emulation, enabled otherwise.
401da177e4SLinus Torvalds  *
411da177e4SLinus Torvalds  * Below a little program to play around with this feature.
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * #include <stdio.h>
441da177e4SLinus Torvalds  * #include <sys/sysmips.h>
451da177e4SLinus Torvalds  *
461da177e4SLinus Torvalds  * struct foo {
471da177e4SLinus Torvalds  *	   unsigned char bar[8];
481da177e4SLinus Torvalds  * };
491da177e4SLinus Torvalds  *
501da177e4SLinus Torvalds  * main(int argc, char *argv[])
511da177e4SLinus Torvalds  * {
521da177e4SLinus Torvalds  *	   struct foo x = {0, 1, 2, 3, 4, 5, 6, 7};
531da177e4SLinus Torvalds  *	   unsigned int *p = (unsigned int *) (x.bar + 3);
541da177e4SLinus Torvalds  *	   int i;
551da177e4SLinus Torvalds  *
561da177e4SLinus Torvalds  *	   if (argc > 1)
571da177e4SLinus Torvalds  *		   sysmips(MIPS_FIXADE, atoi(argv[1]));
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  *	   printf("*p = %08lx\n", *p);
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  *	   *p = 0xdeadface;
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  *	   for(i = 0; i <= 7; i++)
641da177e4SLinus Torvalds  *	   printf("%02x ", x.bar[i]);
651da177e4SLinus Torvalds  *	   printf("\n");
661da177e4SLinus Torvalds  * }
671da177e4SLinus Torvalds  *
681da177e4SLinus Torvalds  * Coprocessor loads are not supported; I think this case is unimportant
691da177e4SLinus Torvalds  * in the practice.
701da177e4SLinus Torvalds  *
711da177e4SLinus Torvalds  * TODO: Handle ndc (attempted store to doubleword in uncached memory)
721da177e4SLinus Torvalds  *	 exception for the R6000.
731da177e4SLinus Torvalds  *	 A store crossing a page boundary might be executed only partially.
741da177e4SLinus Torvalds  *	 Undo the partial store in this case.
751da177e4SLinus Torvalds  */
76c3fc5cd5SRalf Baechle #include <linux/context_tracking.h>
771da177e4SLinus Torvalds #include <linux/mm.h>
781da177e4SLinus Torvalds #include <linux/signal.h>
791da177e4SLinus Torvalds #include <linux/smp.h>
80e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
816312e0eeSAtsushi Nemoto #include <linux/debugfs.h>
827f788d2dSDeng-Cheng Zhu #include <linux/perf_event.h>
837f788d2dSDeng-Cheng Zhu 
841da177e4SLinus Torvalds #include <asm/asm.h>
851da177e4SLinus Torvalds #include <asm/branch.h>
861da177e4SLinus Torvalds #include <asm/byteorder.h>
8769f3a7deSRalf Baechle #include <asm/cop2.h>
8875dcfc1dSPaul Burton #include <asm/debug.h>
89102cedc3SLeonid Yegoshin #include <asm/fpu.h>
90102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h>
911da177e4SLinus Torvalds #include <asm/inst.h>
927c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds #define STR(x)	__STR(x)
951da177e4SLinus Torvalds #define __STR(x)  #x
961da177e4SLinus Torvalds 
976312e0eeSAtsushi Nemoto enum {
986312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_QUIET,
996312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SIGNAL,
1006312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SHOW,
1016312e0eeSAtsushi Nemoto };
1026312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
1036312e0eeSAtsushi Nemoto static u32 unaligned_instructions;
1046312e0eeSAtsushi Nemoto static u32 unaligned_action;
1056312e0eeSAtsushi Nemoto #else
1066312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET
1071da177e4SLinus Torvalds #endif
1086312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs);
1091da177e4SLinus Torvalds 
11034c2f668SLeonid Yegoshin #ifdef __BIG_ENDIAN
111eeb53895SMarkos Chandras #define     _LoadHW(addr, value, res, type)  \
1123563c32dSMarkos Chandras do {                                                        \
11334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (".set\tnoat\n"        \
114eeb53895SMarkos Chandras 			"1:\t"type##_lb("%0", "0(%2)")"\n"  \
115eeb53895SMarkos 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)         \
1303563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
1313563c32dSMarkos Chandras } while(0)
13234c2f668SLeonid Yegoshin 
1330593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
134eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type)   \
1353563c32dSMarkos Chandras do {                                                        \
13634c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
137eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "(%2)")"\n"   \
138eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
13934c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
14034c2f668SLeonid Yegoshin 			"3:\n\t"                            \
14134c2f668SLeonid Yegoshin 			".insn\n\t"                         \
14234c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
14334c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
14434c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
14534c2f668SLeonid Yegoshin 			".previous\n\t"                     \
14634c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
14734c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
14834c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
14934c2f668SLeonid Yegoshin 			".previous"                         \
15034c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
1513563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
1523563c32dSMarkos Chandras } while(0)
1533563c32dSMarkos Chandras 
1540593a44cSLeonid Yegoshin #else
1550593a44cSLeonid Yegoshin /* MIPSR6 has no lwl instruction */
156eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type) \
1573563c32dSMarkos Chandras do {                                                        \
1580593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
1590593a44cSLeonid Yegoshin 			".set\tpush\n"			    \
1600593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
161eeb53895SMarkos Chandras 			"1:"type##_lb("%0", "0(%2)")"\n\t"  \
162eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "1(%2)")"\n\t" \
1630593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
1640593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
165eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "2(%2)")"\n\t" \
1660593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
1670593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
168eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "3(%2)")"\n\t" \
1690593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
1700593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
1710593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
1720593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
1730593a44cSLeonid Yegoshin 			"10:\n\t"			    \
1740593a44cSLeonid Yegoshin 			".insn\n\t"			    \
1750593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
1760593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
1770593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
1780593a44cSLeonid Yegoshin 			".previous\n\t"			    \
1790593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
1800593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
1810593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
1820593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
1830593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
1840593a44cSLeonid Yegoshin 			".previous"			    \
1850593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
1863563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
1873563c32dSMarkos Chandras } while(0)
1883563c32dSMarkos Chandras 
1890593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
19034c2f668SLeonid Yegoshin 
191eeb53895SMarkos Chandras #define     _LoadHWU(addr, value, res, type) \
1923563c32dSMarkos Chandras do {                                                        \
19334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
19434c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
195eeb53895SMarkos Chandras 			"1:\t"type##_lbu("%0", "0(%2)")"\n" \
196eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "1(%2)")"\n\t"\
19734c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
19834c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
19934c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
20034c2f668SLeonid Yegoshin 			"3:\n\t"                            \
20134c2f668SLeonid Yegoshin 			".insn\n\t"                         \
20234c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
20334c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
20434c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
20534c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
20634c2f668SLeonid Yegoshin 			".previous\n\t"                     \
20734c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
20834c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
20934c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
21034c2f668SLeonid Yegoshin 			".previous"                         \
21134c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
2123563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
2133563c32dSMarkos Chandras } while(0)
21434c2f668SLeonid Yegoshin 
2150593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
216eeb53895SMarkos Chandras #define     _LoadWU(addr, value, res, type)  \
2173563c32dSMarkos Chandras do {                                                        \
21834c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
219eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "(%2)")"\n"  \
220eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "3(%2)")"\n\t"\
22134c2f668SLeonid Yegoshin 			"dsll\t%0, %0, 32\n\t"              \
22234c2f668SLeonid Yegoshin 			"dsrl\t%0, %0, 32\n\t"              \
22334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
22434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
22534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
22634c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
22734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
22834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
22934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
23034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
23134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
23234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
23334c2f668SLeonid Yegoshin 			".previous"                         \
23434c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
2353563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
2363563c32dSMarkos Chandras } while(0)
23734c2f668SLeonid Yegoshin 
238eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
2393563c32dSMarkos Chandras do {                                                        \
24034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
24134c2f668SLeonid Yegoshin 			"1:\tldl\t%0, (%2)\n"               \
24234c2f668SLeonid Yegoshin 			"2:\tldr\t%0, 7(%2)\n\t"            \
24334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
24434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
24534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
24634c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
24734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
24834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
24934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
25034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
25134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
25234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
25334c2f668SLeonid Yegoshin 			".previous"                         \
25434c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
2553563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
2563563c32dSMarkos Chandras } while(0)
2573563c32dSMarkos Chandras 
2580593a44cSLeonid Yegoshin #else
2590593a44cSLeonid Yegoshin /* MIPSR6 has not lwl and ldl instructions */
260eeb53895SMarkos Chandras #define	    _LoadWU(addr, value, res, type) \
2613563c32dSMarkos Chandras do {                                                        \
2620593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
2630593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
2640593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
265eeb53895SMarkos Chandras 			"1:"type##_lbu("%0", "0(%2)")"\n\t" \
266eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "1(%2)")"\n\t" \
2670593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
2680593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
269eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "2(%2)")"\n\t" \
2700593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
2710593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
272eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "3(%2)")"\n\t" \
2730593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
2740593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
2750593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
2760593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
2770593a44cSLeonid Yegoshin 			"10:\n\t"			    \
2780593a44cSLeonid Yegoshin 			".insn\n\t"			    \
2790593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
2800593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
2810593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
2820593a44cSLeonid Yegoshin 			".previous\n\t"			    \
2830593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
2840593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
2850593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
2860593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
2870593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
2880593a44cSLeonid Yegoshin 			".previous"			    \
2890593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
2903563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
2913563c32dSMarkos Chandras } while(0)
2920593a44cSLeonid Yegoshin 
293eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
2943563c32dSMarkos Chandras do {                                                        \
2950593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
2960593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
2970593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
2980593a44cSLeonid Yegoshin 			"1:lb\t%0, 0(%2)\n\t"    	    \
2990593a44cSLeonid Yegoshin 			"2:lbu\t $1, 1(%2)\n\t"   	    \
3000593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3010593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3020593a44cSLeonid Yegoshin 			"3:lbu\t$1, 2(%2)\n\t"   	    \
3030593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3040593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3050593a44cSLeonid Yegoshin 			"4:lbu\t$1, 3(%2)\n\t"   	    \
3060593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3070593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3080593a44cSLeonid Yegoshin 			"5:lbu\t$1, 4(%2)\n\t"   	    \
3090593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3100593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3110593a44cSLeonid Yegoshin 			"6:lbu\t$1, 5(%2)\n\t"   	    \
3120593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3130593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3140593a44cSLeonid Yegoshin 			"7:lbu\t$1, 6(%2)\n\t"   	    \
3150593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3160593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3170593a44cSLeonid Yegoshin 			"8:lbu\t$1, 7(%2)\n\t"   	    \
3180593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
3190593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
3200593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
3210593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
3220593a44cSLeonid Yegoshin 			"10:\n\t"			    \
3230593a44cSLeonid Yegoshin 			".insn\n\t"			    \
3240593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
3250593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
3260593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
3270593a44cSLeonid Yegoshin 			".previous\n\t"			    \
3280593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
3290593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
3300593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
3310593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
3320593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
3330593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
3340593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
3350593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
3360593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
3370593a44cSLeonid Yegoshin 			".previous"			    \
3380593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
3393563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
3403563c32dSMarkos Chandras } while(0)
3413563c32dSMarkos Chandras 
3420593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
3430593a44cSLeonid Yegoshin 
34434c2f668SLeonid Yegoshin 
345eeb53895SMarkos Chandras #define     _StoreHW(addr, value, res, type) \
3463563c32dSMarkos Chandras do {                                                        \
34734c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
34834c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
349eeb53895SMarkos Chandras 			"1:\t"type##_sb("%1", "1(%2)")"\n"  \
35034c2f668SLeonid Yegoshin 			"srl\t$1, %1, 0x8\n"                \
351eeb53895SMarkos Chandras 			"2:\t"type##_sb("$1", "0(%2)")"\n"  \
35234c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
35334c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
35434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
35534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
35634c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
35734c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
35834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
35934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
36034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
36134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
36234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
36334c2f668SLeonid Yegoshin 			".previous"                         \
36434c2f668SLeonid Yegoshin 			: "=r" (res)                        \
3653563c32dSMarkos Chandras 			: "r" (value), "r" (addr), "i" (-EFAULT));\
3663563c32dSMarkos Chandras } while(0)
36734c2f668SLeonid Yegoshin 
3680593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
369eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
3703563c32dSMarkos Chandras do {                                                        \
37134c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
372eeb53895SMarkos Chandras 			"1:\t"type##_swl("%1", "(%2)")"\n"  \
373eeb53895SMarkos Chandras 			"2:\t"type##_swr("%1", "3(%2)")"\n\t"\
37434c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
37534c2f668SLeonid Yegoshin 			"3:\n\t"                            \
37634c2f668SLeonid Yegoshin 			".insn\n\t"                         \
37734c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
37834c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
37934c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
38034c2f668SLeonid Yegoshin 			".previous\n\t"                     \
38134c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
38234c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
38334c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
38434c2f668SLeonid Yegoshin 			".previous"                         \
38534c2f668SLeonid Yegoshin 		: "=r" (res)                                \
3863563c32dSMarkos Chandras 		: "r" (value), "r" (addr), "i" (-EFAULT));  \
3873563c32dSMarkos Chandras } while(0)
38834c2f668SLeonid Yegoshin 
389eeb53895SMarkos Chandras #define     _StoreDW(addr, value, res) \
3903563c32dSMarkos Chandras do {                                                        \
39134c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
39234c2f668SLeonid Yegoshin 			"1:\tsdl\t%1,(%2)\n"                \
39334c2f668SLeonid Yegoshin 			"2:\tsdr\t%1, 7(%2)\n\t"            \
39434c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
39534c2f668SLeonid Yegoshin 			"3:\n\t"                            \
39634c2f668SLeonid Yegoshin 			".insn\n\t"                         \
39734c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
39834c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
39934c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
40034c2f668SLeonid Yegoshin 			".previous\n\t"                     \
40134c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
40234c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
40334c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
40434c2f668SLeonid Yegoshin 			".previous"                         \
40534c2f668SLeonid Yegoshin 		: "=r" (res)                                \
4063563c32dSMarkos Chandras 		: "r" (value), "r" (addr), "i" (-EFAULT));  \
4073563c32dSMarkos Chandras } while(0)
4083563c32dSMarkos Chandras 
4090593a44cSLeonid Yegoshin #else
4100593a44cSLeonid Yegoshin /* MIPSR6 has no swl and sdl instructions */
411eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
4123563c32dSMarkos Chandras do {                                                        \
4130593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
4140593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
4150593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
416eeb53895SMarkos Chandras 			"1:"type##_sb("%1", "3(%2)")"\n\t"  \
4170593a44cSLeonid Yegoshin 			"srl\t$1, %1, 0x8\n\t"		    \
418eeb53895SMarkos Chandras 			"2:"type##_sb("$1", "2(%2)")"\n\t"  \
4190593a44cSLeonid Yegoshin 			"srl\t$1, $1,  0x8\n\t"		    \
420eeb53895SMarkos Chandras 			"3:"type##_sb("$1", "1(%2)")"\n\t"  \
4210593a44cSLeonid Yegoshin 			"srl\t$1, $1, 0x8\n\t"		    \
422eeb53895SMarkos Chandras 			"4:"type##_sb("$1", "0(%2)")"\n\t"  \
4230593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
4240593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
4250593a44cSLeonid Yegoshin 			"10:\n\t"			    \
4260593a44cSLeonid Yegoshin 			".insn\n\t"			    \
4270593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
4280593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
4290593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
4300593a44cSLeonid Yegoshin 			".previous\n\t"			    \
4310593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
4320593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
4330593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
4340593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
4350593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
4360593a44cSLeonid Yegoshin 			".previous"			    \
4370593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
4380593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
4393563c32dSMarkos Chandras 		: "memory");                                \
4403563c32dSMarkos Chandras } while(0)
44134c2f668SLeonid Yegoshin 
442531a6d59SJames Cowgill #define     _StoreDW(addr, value, res) \
4433563c32dSMarkos Chandras do {                                                        \
4440593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
4450593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
4460593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
4470593a44cSLeonid Yegoshin 			"1:sb\t%1, 7(%2)\n\t"    	    \
4480593a44cSLeonid Yegoshin 			"dsrl\t$1, %1, 0x8\n\t"		    \
4490593a44cSLeonid Yegoshin 			"2:sb\t$1, 6(%2)\n\t"    	    \
4500593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4510593a44cSLeonid Yegoshin 			"3:sb\t$1, 5(%2)\n\t"    	    \
4520593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4530593a44cSLeonid Yegoshin 			"4:sb\t$1, 4(%2)\n\t"    	    \
4540593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4550593a44cSLeonid Yegoshin 			"5:sb\t$1, 3(%2)\n\t"    	    \
4560593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4570593a44cSLeonid Yegoshin 			"6:sb\t$1, 2(%2)\n\t"    	    \
4580593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4590593a44cSLeonid Yegoshin 			"7:sb\t$1, 1(%2)\n\t"    	    \
4600593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4610593a44cSLeonid Yegoshin 			"8:sb\t$1, 0(%2)\n\t"    	    \
4620593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
4630593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
4640593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
4650593a44cSLeonid Yegoshin 			"10:\n\t"			    \
4660593a44cSLeonid Yegoshin 			".insn\n\t"			    \
4670593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
4680593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
4690593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
4700593a44cSLeonid Yegoshin 			".previous\n\t"			    \
4710593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
4720593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
4730593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
4740593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
4750593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
4760593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
4770593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
4780593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
4790593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
4800593a44cSLeonid Yegoshin 			".previous"			    \
4810593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
4820593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
4833563c32dSMarkos Chandras 		: "memory");                                \
4843563c32dSMarkos Chandras } while(0)
4853563c32dSMarkos Chandras 
4860593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
4870593a44cSLeonid Yegoshin 
4880593a44cSLeonid Yegoshin #else /* __BIG_ENDIAN */
4890593a44cSLeonid Yegoshin 
490eeb53895SMarkos Chandras #define     _LoadHW(addr, value, res, type)  \
4913563c32dSMarkos Chandras do {                                                        \
49234c2f668SLeonid Yegoshin 		__asm__ __volatile__ (".set\tnoat\n"        \
493eeb53895SMarkos Chandras 			"1:\t"type##_lb("%0", "1(%2)")"\n"  \
494eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
49534c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
49634c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
49734c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
49834c2f668SLeonid Yegoshin 			"3:\t.set\tat\n\t"                  \
49934c2f668SLeonid Yegoshin 			".insn\n\t"                         \
50034c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
50134c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
50234c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
50334c2f668SLeonid Yegoshin 			".previous\n\t"                     \
50434c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
50534c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
50634c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
50734c2f668SLeonid Yegoshin 			".previous"                         \
50834c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
5093563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
5103563c32dSMarkos Chandras } while(0)
51134c2f668SLeonid Yegoshin 
5120593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
513eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type)   \
5143563c32dSMarkos Chandras do {                                                        \
51534c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
516eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "3(%2)")"\n" \
517eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
51834c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
51934c2f668SLeonid Yegoshin 			"3:\n\t"                            \
52034c2f668SLeonid Yegoshin 			".insn\n\t"                         \
52134c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
52234c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
52334c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
52434c2f668SLeonid Yegoshin 			".previous\n\t"                     \
52534c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
52634c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
52734c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
52834c2f668SLeonid Yegoshin 			".previous"                         \
52934c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
5303563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
5313563c32dSMarkos Chandras } while(0)
5323563c32dSMarkos Chandras 
5330593a44cSLeonid Yegoshin #else
5340593a44cSLeonid Yegoshin /* MIPSR6 has no lwl instruction */
535eeb53895SMarkos Chandras #define     _LoadW(addr, value, res, type) \
5363563c32dSMarkos Chandras do {                                                        \
5370593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
5380593a44cSLeonid Yegoshin 			".set\tpush\n"			    \
5390593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
540eeb53895SMarkos Chandras 			"1:"type##_lb("%0", "3(%2)")"\n\t"  \
541eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "2(%2)")"\n\t" \
5420593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
5430593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
544eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "1(%2)")"\n\t" \
5450593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
5460593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
547eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "0(%2)")"\n\t" \
5480593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
5490593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
5500593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
5510593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
5520593a44cSLeonid Yegoshin 			"10:\n\t"			    \
5530593a44cSLeonid Yegoshin 			".insn\n\t"			    \
5540593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
5550593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
5560593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
5570593a44cSLeonid Yegoshin 			".previous\n\t"			    \
5580593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
5590593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
5600593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
5610593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
5620593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
5630593a44cSLeonid Yegoshin 			".previous"			    \
5640593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
5653563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
5663563c32dSMarkos Chandras } while(0)
5673563c32dSMarkos Chandras 
5680593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
5690593a44cSLeonid Yegoshin 
57034c2f668SLeonid Yegoshin 
571eeb53895SMarkos Chandras #define     _LoadHWU(addr, value, res, type) \
5723563c32dSMarkos Chandras do {                                                        \
57334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
57434c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
575eeb53895SMarkos Chandras 			"1:\t"type##_lbu("%0", "1(%2)")"\n" \
576eeb53895SMarkos Chandras 			"2:\t"type##_lbu("$1", "0(%2)")"\n\t"\
57734c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
57834c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
57934c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
58034c2f668SLeonid Yegoshin 			"3:\n\t"                            \
58134c2f668SLeonid Yegoshin 			".insn\n\t"                         \
58234c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
58334c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
58434c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
58534c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
58634c2f668SLeonid Yegoshin 			".previous\n\t"                     \
58734c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
58834c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
58934c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
59034c2f668SLeonid Yegoshin 			".previous"                         \
59134c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
5923563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
5933563c32dSMarkos Chandras } while(0)
59434c2f668SLeonid Yegoshin 
5950593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
596eeb53895SMarkos Chandras #define     _LoadWU(addr, value, res, type)  \
5973563c32dSMarkos Chandras do {                                                        \
59834c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
599eeb53895SMarkos Chandras 			"1:\t"type##_lwl("%0", "3(%2)")"\n" \
600eeb53895SMarkos Chandras 			"2:\t"type##_lwr("%0", "(%2)")"\n\t"\
60134c2f668SLeonid Yegoshin 			"dsll\t%0, %0, 32\n\t"              \
60234c2f668SLeonid Yegoshin 			"dsrl\t%0, %0, 32\n\t"              \
60334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
60434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
60534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
60634c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
60734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
60834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
60934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
61034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
61134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
61234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
61334c2f668SLeonid Yegoshin 			".previous"                         \
61434c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
6153563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
6163563c32dSMarkos Chandras } while(0)
61734c2f668SLeonid Yegoshin 
618eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
6193563c32dSMarkos Chandras do {                                                        \
62034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
62134c2f668SLeonid Yegoshin 			"1:\tldl\t%0, 7(%2)\n"              \
62234c2f668SLeonid Yegoshin 			"2:\tldr\t%0, (%2)\n\t"             \
62334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
62434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
62534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
62634c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
62734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
62834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
62934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
63034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
63134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
63234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
63334c2f668SLeonid Yegoshin 			".previous"                         \
63434c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
6353563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
6363563c32dSMarkos Chandras } while(0)
6373563c32dSMarkos Chandras 
6380593a44cSLeonid Yegoshin #else
6390593a44cSLeonid Yegoshin /* MIPSR6 has not lwl and ldl instructions */
640eeb53895SMarkos Chandras #define	    _LoadWU(addr, value, res, type) \
6413563c32dSMarkos Chandras do {                                                        \
6420593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
6430593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
6440593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
645eeb53895SMarkos Chandras 			"1:"type##_lbu("%0", "3(%2)")"\n\t" \
646eeb53895SMarkos Chandras 			"2:"type##_lbu("$1", "2(%2)")"\n\t" \
6470593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
6480593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
649eeb53895SMarkos Chandras 			"3:"type##_lbu("$1", "1(%2)")"\n\t" \
6500593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
6510593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
652eeb53895SMarkos Chandras 			"4:"type##_lbu("$1", "0(%2)")"\n\t" \
6530593a44cSLeonid Yegoshin 			"sll\t%0, 0x8\n\t"		    \
6540593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6550593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
6560593a44cSLeonid Yegoshin 			".set\tpop\n"			    \
6570593a44cSLeonid Yegoshin 			"10:\n\t"			    \
6580593a44cSLeonid Yegoshin 			".insn\n\t"			    \
6590593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
6600593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
6610593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
6620593a44cSLeonid Yegoshin 			".previous\n\t"			    \
6630593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
6640593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
6650593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
6660593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
6670593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
6680593a44cSLeonid Yegoshin 			".previous"			    \
6690593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
6703563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
6713563c32dSMarkos Chandras } while(0)
6720593a44cSLeonid Yegoshin 
673eeb53895SMarkos Chandras #define     _LoadDW(addr, value, res)  \
6743563c32dSMarkos Chandras do {                                                        \
6750593a44cSLeonid Yegoshin 		__asm__ __volatile__ (			    \
6760593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
6770593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
6780593a44cSLeonid Yegoshin 			"1:lb\t%0, 7(%2)\n\t"    	    \
6790593a44cSLeonid Yegoshin 			"2:lbu\t$1, 6(%2)\n\t"   	    \
6800593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6810593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6820593a44cSLeonid Yegoshin 			"3:lbu\t$1, 5(%2)\n\t"   	    \
6830593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6840593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6850593a44cSLeonid Yegoshin 			"4:lbu\t$1, 4(%2)\n\t"   	    \
6860593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6870593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6880593a44cSLeonid Yegoshin 			"5:lbu\t$1, 3(%2)\n\t"   	    \
6890593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6900593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6910593a44cSLeonid Yegoshin 			"6:lbu\t$1, 2(%2)\n\t"   	    \
6920593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6930593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6940593a44cSLeonid Yegoshin 			"7:lbu\t$1, 1(%2)\n\t"   	    \
6950593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6960593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
6970593a44cSLeonid Yegoshin 			"8:lbu\t$1, 0(%2)\n\t"   	    \
6980593a44cSLeonid Yegoshin 			"dsll\t%0, 0x8\n\t"		    \
6990593a44cSLeonid Yegoshin 			"or\t%0, $1\n\t"		    \
7000593a44cSLeonid Yegoshin 			"li\t%1, 0\n"			    \
7010593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
7020593a44cSLeonid Yegoshin 			"10:\n\t"			    \
7030593a44cSLeonid Yegoshin 			".insn\n\t"			    \
7040593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
7050593a44cSLeonid Yegoshin 			"11:\tli\t%1, %3\n\t"		    \
7060593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
7070593a44cSLeonid Yegoshin 			".previous\n\t"			    \
7080593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
7090593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
7100593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
7110593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
7120593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
7130593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
7140593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
7150593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
7160593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
7170593a44cSLeonid Yegoshin 			".previous"			    \
7180593a44cSLeonid Yegoshin 			: "=&r" (value), "=r" (res)	    \
7193563c32dSMarkos Chandras 			: "r" (addr), "i" (-EFAULT));       \
7203563c32dSMarkos Chandras } while(0)
7210593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
72234c2f668SLeonid Yegoshin 
723eeb53895SMarkos Chandras #define     _StoreHW(addr, value, res, type) \
7243563c32dSMarkos Chandras do {                                                        \
72534c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
72634c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
727eeb53895SMarkos Chandras 			"1:\t"type##_sb("%1", "0(%2)")"\n"  \
72834c2f668SLeonid Yegoshin 			"srl\t$1,%1, 0x8\n"                 \
729eeb53895SMarkos Chandras 			"2:\t"type##_sb("$1", "1(%2)")"\n"  \
73034c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
73134c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
73234c2f668SLeonid Yegoshin 			"3:\n\t"                            \
73334c2f668SLeonid Yegoshin 			".insn\n\t"                         \
73434c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
73534c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
73634c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
73734c2f668SLeonid Yegoshin 			".previous\n\t"                     \
73834c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
73934c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
74034c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
74134c2f668SLeonid Yegoshin 			".previous"                         \
74234c2f668SLeonid Yegoshin 			: "=r" (res)                        \
7433563c32dSMarkos Chandras 			: "r" (value), "r" (addr), "i" (-EFAULT));\
7443563c32dSMarkos Chandras } while(0)
7453563c32dSMarkos Chandras 
7460593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
747eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
7483563c32dSMarkos Chandras do {                                                        \
74934c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
750eeb53895SMarkos Chandras 			"1:\t"type##_swl("%1", "3(%2)")"\n" \
751eeb53895SMarkos Chandras 			"2:\t"type##_swr("%1", "(%2)")"\n\t"\
75234c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
75334c2f668SLeonid Yegoshin 			"3:\n\t"                            \
75434c2f668SLeonid Yegoshin 			".insn\n\t"                         \
75534c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
75634c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
75734c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
75834c2f668SLeonid Yegoshin 			".previous\n\t"                     \
75934c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
76034c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
76134c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
76234c2f668SLeonid Yegoshin 			".previous"                         \
76334c2f668SLeonid Yegoshin 		: "=r" (res)                                \
7643563c32dSMarkos Chandras 		: "r" (value), "r" (addr), "i" (-EFAULT));  \
7653563c32dSMarkos Chandras } while(0)
76634c2f668SLeonid Yegoshin 
767eeb53895SMarkos Chandras #define     _StoreDW(addr, value, res) \
7683563c32dSMarkos Chandras do {                                                        \
76934c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
77034c2f668SLeonid Yegoshin 			"1:\tsdl\t%1, 7(%2)\n"              \
77134c2f668SLeonid Yegoshin 			"2:\tsdr\t%1, (%2)\n\t"             \
77234c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
77334c2f668SLeonid Yegoshin 			"3:\n\t"                            \
77434c2f668SLeonid Yegoshin 			".insn\n\t"                         \
77534c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
77634c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
77734c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
77834c2f668SLeonid Yegoshin 			".previous\n\t"                     \
77934c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
78034c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
78134c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
78234c2f668SLeonid Yegoshin 			".previous"                         \
78334c2f668SLeonid Yegoshin 		: "=r" (res)                                \
7843563c32dSMarkos Chandras 		: "r" (value), "r" (addr), "i" (-EFAULT));  \
7853563c32dSMarkos Chandras } while(0)
7863563c32dSMarkos Chandras 
7870593a44cSLeonid Yegoshin #else
7880593a44cSLeonid Yegoshin /* MIPSR6 has no swl and sdl instructions */
789eeb53895SMarkos Chandras #define     _StoreW(addr, value, res, type)  \
7903563c32dSMarkos Chandras do {                                                        \
7910593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
7920593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
7930593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
794eeb53895SMarkos Chandras 			"1:"type##_sb("%1", "0(%2)")"\n\t"  \
7950593a44cSLeonid Yegoshin 			"srl\t$1, %1, 0x8\n\t"		    \
796eeb53895SMarkos Chandras 			"2:"type##_sb("$1", "1(%2)")"\n\t"  \
7970593a44cSLeonid Yegoshin 			"srl\t$1, $1,  0x8\n\t"		    \
798eeb53895SMarkos Chandras 			"3:"type##_sb("$1", "2(%2)")"\n\t"  \
7990593a44cSLeonid Yegoshin 			"srl\t$1, $1, 0x8\n\t"		    \
800eeb53895SMarkos Chandras 			"4:"type##_sb("$1", "3(%2)")"\n\t"  \
8010593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
8020593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
8030593a44cSLeonid Yegoshin 			"10:\n\t"			    \
8040593a44cSLeonid Yegoshin 			".insn\n\t"			    \
8050593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
8060593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
8070593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
8080593a44cSLeonid Yegoshin 			".previous\n\t"			    \
8090593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
8100593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
8110593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
8120593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
8130593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
8140593a44cSLeonid Yegoshin 			".previous"			    \
8150593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
8160593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
8173563c32dSMarkos Chandras 		: "memory");                                \
8183563c32dSMarkos Chandras } while(0)
8190593a44cSLeonid Yegoshin 
820eeb53895SMarkos Chandras #define     _StoreDW(addr, value, res) \
8213563c32dSMarkos Chandras do {                                                        \
8220593a44cSLeonid Yegoshin 		__asm__ __volatile__ (                      \
8230593a44cSLeonid Yegoshin 			".set\tpush\n\t"		    \
8240593a44cSLeonid Yegoshin 			".set\tnoat\n\t"		    \
8250593a44cSLeonid Yegoshin 			"1:sb\t%1, 0(%2)\n\t"    	    \
8260593a44cSLeonid Yegoshin 			"dsrl\t$1, %1, 0x8\n\t"		    \
8270593a44cSLeonid Yegoshin 			"2:sb\t$1, 1(%2)\n\t"    	    \
8280593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8290593a44cSLeonid Yegoshin 			"3:sb\t$1, 2(%2)\n\t"    	    \
8300593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8310593a44cSLeonid Yegoshin 			"4:sb\t$1, 3(%2)\n\t"    	    \
8320593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8330593a44cSLeonid Yegoshin 			"5:sb\t$1, 4(%2)\n\t"    	    \
8340593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8350593a44cSLeonid Yegoshin 			"6:sb\t$1, 5(%2)\n\t"    	    \
8360593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8370593a44cSLeonid Yegoshin 			"7:sb\t$1, 6(%2)\n\t"    	    \
8380593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8390593a44cSLeonid Yegoshin 			"8:sb\t$1, 7(%2)\n\t"    	    \
8400593a44cSLeonid Yegoshin 			"dsrl\t$1, $1, 0x8\n\t"		    \
8410593a44cSLeonid Yegoshin 			".set\tpop\n\t"			    \
8420593a44cSLeonid Yegoshin 			"li\t%0, 0\n"			    \
8430593a44cSLeonid Yegoshin 			"10:\n\t"			    \
8440593a44cSLeonid Yegoshin 			".insn\n\t"			    \
8450593a44cSLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"	    \
8460593a44cSLeonid Yegoshin 			"11:\tli\t%0, %3\n\t"		    \
8470593a44cSLeonid Yegoshin 			"j\t10b\n\t"			    \
8480593a44cSLeonid Yegoshin 			".previous\n\t"			    \
8490593a44cSLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
8500593a44cSLeonid Yegoshin 			STR(PTR)"\t1b, 11b\n\t"		    \
8510593a44cSLeonid Yegoshin 			STR(PTR)"\t2b, 11b\n\t"		    \
8520593a44cSLeonid Yegoshin 			STR(PTR)"\t3b, 11b\n\t"		    \
8530593a44cSLeonid Yegoshin 			STR(PTR)"\t4b, 11b\n\t"		    \
8540593a44cSLeonid Yegoshin 			STR(PTR)"\t5b, 11b\n\t"		    \
8550593a44cSLeonid Yegoshin 			STR(PTR)"\t6b, 11b\n\t"		    \
8560593a44cSLeonid Yegoshin 			STR(PTR)"\t7b, 11b\n\t"		    \
8570593a44cSLeonid Yegoshin 			STR(PTR)"\t8b, 11b\n\t"		    \
8580593a44cSLeonid Yegoshin 			".previous"			    \
8590593a44cSLeonid Yegoshin 		: "=&r" (res)			    	    \
8600593a44cSLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT)    \
8613563c32dSMarkos Chandras 		: "memory");                                \
8623563c32dSMarkos Chandras } while(0)
8633563c32dSMarkos Chandras 
8640593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */
86534c2f668SLeonid Yegoshin #endif
86634c2f668SLeonid Yegoshin 
867eeb53895SMarkos Chandras #define LoadHWU(addr, value, res)	_LoadHWU(addr, value, res, kernel)
868eeb53895SMarkos Chandras #define LoadHWUE(addr, value, res)	_LoadHWU(addr, value, res, user)
869eeb53895SMarkos Chandras #define LoadWU(addr, value, res)	_LoadWU(addr, value, res, kernel)
870eeb53895SMarkos Chandras #define LoadWUE(addr, value, res)	_LoadWU(addr, value, res, user)
871eeb53895SMarkos Chandras #define LoadHW(addr, value, res)	_LoadHW(addr, value, res, kernel)
872eeb53895SMarkos Chandras #define LoadHWE(addr, value, res)	_LoadHW(addr, value, res, user)
873eeb53895SMarkos Chandras #define LoadW(addr, value, res)		_LoadW(addr, value, res, kernel)
874eeb53895SMarkos Chandras #define LoadWE(addr, value, res)	_LoadW(addr, value, res, user)
875eeb53895SMarkos Chandras #define LoadDW(addr, value, res)	_LoadDW(addr, value, res)
876eeb53895SMarkos Chandras 
877eeb53895SMarkos Chandras #define StoreHW(addr, value, res)	_StoreHW(addr, value, res, kernel)
878eeb53895SMarkos Chandras #define StoreHWE(addr, value, res)	_StoreHW(addr, value, res, user)
879eeb53895SMarkos Chandras #define StoreW(addr, value, res)	_StoreW(addr, value, res, kernel)
880eeb53895SMarkos Chandras #define StoreWE(addr, value, res)	_StoreW(addr, value, res, user)
881eeb53895SMarkos Chandras #define StoreDW(addr, value, res)	_StoreDW(addr, value, res)
882eeb53895SMarkos Chandras 
8837f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs,
8847f18f151SRalf Baechle 	void __user *addr, unsigned int __user *pc)
8851da177e4SLinus Torvalds {
8861da177e4SLinus Torvalds 	union mips_instruction insn;
8871da177e4SLinus Torvalds 	unsigned long value;
888fa8ff601SPaul Burton 	unsigned int res, preempted;
88934c2f668SLeonid Yegoshin 	unsigned long origpc;
89034c2f668SLeonid Yegoshin 	unsigned long orig31;
891102cedc3SLeonid Yegoshin 	void __user *fault_addr = NULL;
892c1771216SLeonid Yegoshin #ifdef	CONFIG_EVA
893c1771216SLeonid Yegoshin 	mm_segment_t seg;
894c1771216SLeonid Yegoshin #endif
895e4aa1f15SLeonid Yegoshin 	union fpureg *fpr;
896e4aa1f15SLeonid Yegoshin 	enum msa_2b_fmt df;
897e4aa1f15SLeonid Yegoshin 	unsigned int wd;
89834c2f668SLeonid Yegoshin 	origpc = (unsigned long)pc;
89934c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
90034c2f668SLeonid Yegoshin 
901a8b0ca17SPeter Zijlstra 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
9027f788d2dSDeng-Cheng Zhu 
9031da177e4SLinus Torvalds 	/*
9041da177e4SLinus Torvalds 	 * This load never faults.
9051da177e4SLinus Torvalds 	 */
906fe00f943SRalf Baechle 	__get_user(insn.word, pc);
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds 	switch (insn.i_format.opcode) {
9091da177e4SLinus Torvalds 		/*
9101da177e4SLinus Torvalds 		 * These are instructions that a compiler doesn't generate.  We
9111da177e4SLinus Torvalds 		 * can assume therefore that the code is MIPS-aware and
9121da177e4SLinus Torvalds 		 * really buggy.  Emulating these instructions would break the
9131da177e4SLinus Torvalds 		 * semantics anyway.
9141da177e4SLinus Torvalds 		 */
9151da177e4SLinus Torvalds 	case ll_op:
9161da177e4SLinus Torvalds 	case lld_op:
9171da177e4SLinus Torvalds 	case sc_op:
9181da177e4SLinus Torvalds 	case scd_op:
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 		/*
9211da177e4SLinus Torvalds 		 * For these instructions the only way to create an address
9221da177e4SLinus Torvalds 		 * error is an attempted access to kernel/supervisor address
9231da177e4SLinus Torvalds 		 * space.
9241da177e4SLinus Torvalds 		 */
9251da177e4SLinus Torvalds 	case ldl_op:
9261da177e4SLinus Torvalds 	case ldr_op:
9271da177e4SLinus Torvalds 	case lwl_op:
9281da177e4SLinus Torvalds 	case lwr_op:
9291da177e4SLinus Torvalds 	case sdl_op:
9301da177e4SLinus Torvalds 	case sdr_op:
9311da177e4SLinus Torvalds 	case swl_op:
9321da177e4SLinus Torvalds 	case swr_op:
9331da177e4SLinus Torvalds 	case lb_op:
9341da177e4SLinus Torvalds 	case lbu_op:
9351da177e4SLinus Torvalds 	case sb_op:
9361da177e4SLinus Torvalds 		goto sigbus;
9371da177e4SLinus Torvalds 
9381da177e4SLinus Torvalds 		/*
93934c2f668SLeonid Yegoshin 		 * The remaining opcodes are the ones that are really of
94034c2f668SLeonid Yegoshin 		 * interest.
9411da177e4SLinus Torvalds 		 */
942c1771216SLeonid Yegoshin 	case spec3_op:
9433f88ec63SMiodrag Dinic 		if (insn.dsp_format.func == lx_op) {
9443f88ec63SMiodrag Dinic 			switch (insn.dsp_format.op) {
9453f88ec63SMiodrag Dinic 			case lwx_op:
9463f88ec63SMiodrag Dinic 				if (!access_ok(VERIFY_READ, addr, 4))
9473f88ec63SMiodrag Dinic 					goto sigbus;
9483f88ec63SMiodrag Dinic 				LoadW(addr, value, res);
9493f88ec63SMiodrag Dinic 				if (res)
9503f88ec63SMiodrag Dinic 					goto fault;
9513f88ec63SMiodrag Dinic 				compute_return_epc(regs);
9523f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
9533f88ec63SMiodrag Dinic 				break;
9543f88ec63SMiodrag Dinic 			case lhx_op:
9553f88ec63SMiodrag Dinic 				if (!access_ok(VERIFY_READ, addr, 2))
9563f88ec63SMiodrag Dinic 					goto sigbus;
9573f88ec63SMiodrag Dinic 				LoadHW(addr, value, res);
9583f88ec63SMiodrag Dinic 				if (res)
9593f88ec63SMiodrag Dinic 					goto fault;
9603f88ec63SMiodrag Dinic 				compute_return_epc(regs);
9613f88ec63SMiodrag Dinic 				regs->regs[insn.dsp_format.rd] = value;
9623f88ec63SMiodrag Dinic 				break;
9633f88ec63SMiodrag Dinic 			default:
9643f88ec63SMiodrag Dinic 				goto sigill;
9653f88ec63SMiodrag Dinic 			}
9663f88ec63SMiodrag Dinic 		}
9673f88ec63SMiodrag Dinic #ifdef CONFIG_EVA
9683f88ec63SMiodrag Dinic 		else {
969c1771216SLeonid Yegoshin 			/*
9703f88ec63SMiodrag Dinic 			 * we can land here only from kernel accessing user
9713f88ec63SMiodrag Dinic 			 * memory, so we need to "switch" the address limit to
9723f88ec63SMiodrag Dinic 			 * user space, so that address check can work properly.
973c1771216SLeonid Yegoshin 			 */
974c1771216SLeonid Yegoshin 			seg = get_fs();
975c1771216SLeonid Yegoshin 			set_fs(USER_DS);
976c1771216SLeonid Yegoshin 			switch (insn.spec3_format.func) {
977c1771216SLeonid Yegoshin 			case lhe_op:
978c1771216SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 2)) {
979c1771216SLeonid Yegoshin 					set_fs(seg);
980c1771216SLeonid Yegoshin 					goto sigbus;
981c1771216SLeonid Yegoshin 				}
982eeb53895SMarkos Chandras 				LoadHWE(addr, value, res);
983c1771216SLeonid Yegoshin 				if (res) {
984c1771216SLeonid Yegoshin 					set_fs(seg);
985c1771216SLeonid Yegoshin 					goto fault;
986c1771216SLeonid Yegoshin 				}
987c1771216SLeonid Yegoshin 				compute_return_epc(regs);
988c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
989c1771216SLeonid Yegoshin 				break;
990c1771216SLeonid Yegoshin 			case lwe_op:
991c1771216SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 4)) {
992c1771216SLeonid Yegoshin 					set_fs(seg);
993c1771216SLeonid Yegoshin 					goto sigbus;
994c1771216SLeonid Yegoshin 				}
995eeb53895SMarkos Chandras 				LoadWE(addr, value, res);
996c1771216SLeonid Yegoshin 				if (res) {
997c1771216SLeonid Yegoshin 					set_fs(seg);
998c1771216SLeonid Yegoshin 					goto fault;
999c1771216SLeonid Yegoshin 				}
1000c1771216SLeonid Yegoshin 				compute_return_epc(regs);
1001c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
1002c1771216SLeonid Yegoshin 				break;
1003c1771216SLeonid Yegoshin 			case lhue_op:
1004c1771216SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 2)) {
1005c1771216SLeonid Yegoshin 					set_fs(seg);
1006c1771216SLeonid Yegoshin 					goto sigbus;
1007c1771216SLeonid Yegoshin 				}
1008eeb53895SMarkos Chandras 				LoadHWUE(addr, value, res);
1009c1771216SLeonid Yegoshin 				if (res) {
1010c1771216SLeonid Yegoshin 					set_fs(seg);
1011c1771216SLeonid Yegoshin 					goto fault;
1012c1771216SLeonid Yegoshin 				}
1013c1771216SLeonid Yegoshin 				compute_return_epc(regs);
1014c1771216SLeonid Yegoshin 				regs->regs[insn.spec3_format.rt] = value;
1015c1771216SLeonid Yegoshin 				break;
1016c1771216SLeonid Yegoshin 			case she_op:
1017c1771216SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 2)) {
1018c1771216SLeonid Yegoshin 					set_fs(seg);
1019c1771216SLeonid Yegoshin 					goto sigbus;
1020c1771216SLeonid Yegoshin 				}
1021c1771216SLeonid Yegoshin 				compute_return_epc(regs);
1022c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
1023eeb53895SMarkos Chandras 				StoreHWE(addr, value, res);
1024c1771216SLeonid Yegoshin 				if (res) {
1025c1771216SLeonid Yegoshin 					set_fs(seg);
1026c1771216SLeonid Yegoshin 					goto fault;
1027c1771216SLeonid Yegoshin 				}
1028c1771216SLeonid Yegoshin 				break;
1029c1771216SLeonid Yegoshin 			case swe_op:
1030c1771216SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 4)) {
1031c1771216SLeonid Yegoshin 					set_fs(seg);
1032c1771216SLeonid Yegoshin 					goto sigbus;
1033c1771216SLeonid Yegoshin 				}
1034c1771216SLeonid Yegoshin 				compute_return_epc(regs);
1035c1771216SLeonid Yegoshin 				value = regs->regs[insn.spec3_format.rt];
1036eeb53895SMarkos Chandras 				StoreWE(addr, value, res);
1037c1771216SLeonid Yegoshin 				if (res) {
1038c1771216SLeonid Yegoshin 					set_fs(seg);
1039c1771216SLeonid Yegoshin 					goto fault;
1040c1771216SLeonid Yegoshin 				}
1041c1771216SLeonid Yegoshin 				break;
1042c1771216SLeonid Yegoshin 			default:
1043c1771216SLeonid Yegoshin 				set_fs(seg);
1044c1771216SLeonid Yegoshin 				goto sigill;
1045c1771216SLeonid Yegoshin 			}
1046c1771216SLeonid Yegoshin 			set_fs(seg);
10473f88ec63SMiodrag Dinic 		}
1048c1771216SLeonid Yegoshin #endif
10493f88ec63SMiodrag Dinic 		break;
10501da177e4SLinus Torvalds 	case lh_op:
10511da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 2))
10521da177e4SLinus Torvalds 			goto sigbus;
10531da177e4SLinus Torvalds 
105497f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_EVA)) {
1055db68ce10SAl Viro 			if (uaccess_kernel())
105634c2f668SLeonid Yegoshin 				LoadHW(addr, value, res);
10576eae3548SMarkos Chandras 			else
10586eae3548SMarkos Chandras 				LoadHWE(addr, value, res);
10596eae3548SMarkos Chandras 		} else {
10606eae3548SMarkos Chandras 			LoadHW(addr, value, res);
10616eae3548SMarkos Chandras 		}
10626eae3548SMarkos Chandras 
10631da177e4SLinus Torvalds 		if (res)
10641da177e4SLinus Torvalds 			goto fault;
10657f18f151SRalf Baechle 		compute_return_epc(regs);
10667f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
10671da177e4SLinus Torvalds 		break;
10681da177e4SLinus Torvalds 
10691da177e4SLinus Torvalds 	case lw_op:
10701da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 4))
10711da177e4SLinus Torvalds 			goto sigbus;
10721da177e4SLinus Torvalds 
107397f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_EVA)) {
1074db68ce10SAl Viro 			if (uaccess_kernel())
107534c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
10766eae3548SMarkos Chandras 			else
10776eae3548SMarkos Chandras 				LoadWE(addr, value, res);
10786eae3548SMarkos Chandras 		} else {
10796eae3548SMarkos Chandras 			LoadW(addr, value, res);
10806eae3548SMarkos Chandras 		}
10816eae3548SMarkos Chandras 
10821da177e4SLinus Torvalds 		if (res)
10831da177e4SLinus Torvalds 			goto fault;
10847f18f151SRalf Baechle 		compute_return_epc(regs);
10857f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
10861da177e4SLinus Torvalds 		break;
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds 	case lhu_op:
10891da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 2))
10901da177e4SLinus Torvalds 			goto sigbus;
10911da177e4SLinus Torvalds 
109297f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_EVA)) {
1093db68ce10SAl Viro 			if (uaccess_kernel())
109434c2f668SLeonid Yegoshin 				LoadHWU(addr, value, res);
10956eae3548SMarkos Chandras 			else
10966eae3548SMarkos Chandras 				LoadHWUE(addr, value, res);
10976eae3548SMarkos Chandras 		} else {
10986eae3548SMarkos Chandras 			LoadHWU(addr, value, res);
10996eae3548SMarkos Chandras 		}
11006eae3548SMarkos Chandras 
11011da177e4SLinus Torvalds 		if (res)
11021da177e4SLinus Torvalds 			goto fault;
11037f18f151SRalf Baechle 		compute_return_epc(regs);
11047f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
11051da177e4SLinus Torvalds 		break;
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds 	case lwu_op:
1108875d43e7SRalf Baechle #ifdef CONFIG_64BIT
11091da177e4SLinus Torvalds 		/*
11101da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
11111da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
11121da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
11131da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
11141da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
11151da177e4SLinus Torvalds 		 */
11161da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 4))
11171da177e4SLinus Torvalds 			goto sigbus;
11181da177e4SLinus Torvalds 
111934c2f668SLeonid Yegoshin 		LoadWU(addr, value, res);
11201da177e4SLinus Torvalds 		if (res)
11211da177e4SLinus Torvalds 			goto fault;
11227f18f151SRalf Baechle 		compute_return_epc(regs);
11237f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
11241da177e4SLinus Torvalds 		break;
1125875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
11281da177e4SLinus Torvalds 		goto sigill;
11291da177e4SLinus Torvalds 
11301da177e4SLinus Torvalds 	case ld_op:
1131875d43e7SRalf Baechle #ifdef CONFIG_64BIT
11321da177e4SLinus Torvalds 		/*
11331da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
11341da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
11351da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
11361da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
11371da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
11381da177e4SLinus Torvalds 		 */
11391da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 8))
11401da177e4SLinus Torvalds 			goto sigbus;
11411da177e4SLinus Torvalds 
114234c2f668SLeonid Yegoshin 		LoadDW(addr, value, res);
11431da177e4SLinus Torvalds 		if (res)
11441da177e4SLinus Torvalds 			goto fault;
11457f18f151SRalf Baechle 		compute_return_epc(regs);
11467f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
11471da177e4SLinus Torvalds 		break;
1148875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
11511da177e4SLinus Torvalds 		goto sigill;
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 	case sh_op:
11541da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 2))
11551da177e4SLinus Torvalds 			goto sigbus;
11561da177e4SLinus Torvalds 
115734c2f668SLeonid Yegoshin 		compute_return_epc(regs);
11581da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
11596eae3548SMarkos Chandras 
116097f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_EVA)) {
1161db68ce10SAl Viro 			if (uaccess_kernel())
116234c2f668SLeonid Yegoshin 				StoreHW(addr, value, res);
11636eae3548SMarkos Chandras 			else
11646eae3548SMarkos Chandras 				StoreHWE(addr, value, res);
11656eae3548SMarkos Chandras 		} else {
11666eae3548SMarkos Chandras 			StoreHW(addr, value, res);
11676eae3548SMarkos Chandras 		}
11686eae3548SMarkos Chandras 
11691da177e4SLinus Torvalds 		if (res)
11701da177e4SLinus Torvalds 			goto fault;
11711da177e4SLinus Torvalds 		break;
11721da177e4SLinus Torvalds 
11731da177e4SLinus Torvalds 	case sw_op:
11741da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 4))
11751da177e4SLinus Torvalds 			goto sigbus;
11761da177e4SLinus Torvalds 
117734c2f668SLeonid Yegoshin 		compute_return_epc(regs);
11781da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
11796eae3548SMarkos Chandras 
118097f2645fSMasahiro Yamada 		if (IS_ENABLED(CONFIG_EVA)) {
1181db68ce10SAl Viro 			if (uaccess_kernel())
118234c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
11836eae3548SMarkos Chandras 			else
11846eae3548SMarkos Chandras 				StoreWE(addr, value, res);
11856eae3548SMarkos Chandras 		} else {
11866eae3548SMarkos Chandras 			StoreW(addr, value, res);
11876eae3548SMarkos Chandras 		}
11886eae3548SMarkos Chandras 
11891da177e4SLinus Torvalds 		if (res)
11901da177e4SLinus Torvalds 			goto fault;
11911da177e4SLinus Torvalds 		break;
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 	case sd_op:
1194875d43e7SRalf Baechle #ifdef CONFIG_64BIT
11951da177e4SLinus Torvalds 		/*
11961da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
11971da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
11981da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
11991da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
12001da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
12011da177e4SLinus Torvalds 		 */
12021da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 8))
12031da177e4SLinus Torvalds 			goto sigbus;
12041da177e4SLinus Torvalds 
120534c2f668SLeonid Yegoshin 		compute_return_epc(regs);
12061da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
120734c2f668SLeonid Yegoshin 		StoreDW(addr, value, res);
12081da177e4SLinus Torvalds 		if (res)
12091da177e4SLinus Torvalds 			goto fault;
12101da177e4SLinus Torvalds 		break;
1211875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
12141da177e4SLinus Torvalds 		goto sigill;
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds 	case lwc1_op:
12171da177e4SLinus Torvalds 	case ldc1_op:
12181da177e4SLinus Torvalds 	case swc1_op:
12191da177e4SLinus Torvalds 	case sdc1_op:
1220e70ac023SPaul Burton 	case cop1x_op:
1221102cedc3SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
1222102cedc3SLeonid Yegoshin 		BUG_ON(!used_math());
1223102cedc3SLeonid Yegoshin 
1224102cedc3SLeonid Yegoshin 		lose_fpu(1);	/* Save FPU state for the emulator. */
1225102cedc3SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
1226102cedc3SLeonid Yegoshin 					       &fault_addr);
1227102cedc3SLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
1228102cedc3SLeonid Yegoshin 
1229102cedc3SLeonid Yegoshin 		/* Signal if something went wrong. */
1230304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
1231102cedc3SLeonid Yegoshin 
1232102cedc3SLeonid Yegoshin 		if (res == 0)
1233102cedc3SLeonid Yegoshin 			break;
1234102cedc3SLeonid Yegoshin 		return;
12351da177e4SLinus Torvalds 
1236e4aa1f15SLeonid Yegoshin 	case msa_op:
1237e4aa1f15SLeonid Yegoshin 		if (!cpu_has_msa)
1238e4aa1f15SLeonid Yegoshin 			goto sigill;
1239e4aa1f15SLeonid Yegoshin 
1240e4aa1f15SLeonid Yegoshin 		/*
1241e4aa1f15SLeonid Yegoshin 		 * If we've reached this point then userland should have taken
1242e4aa1f15SLeonid Yegoshin 		 * the MSA disabled exception & initialised vector context at
1243e4aa1f15SLeonid Yegoshin 		 * some point in the past.
1244e4aa1f15SLeonid Yegoshin 		 */
1245e4aa1f15SLeonid Yegoshin 		BUG_ON(!thread_msa_context_live());
1246e4aa1f15SLeonid Yegoshin 
1247e4aa1f15SLeonid Yegoshin 		df = insn.msa_mi10_format.df;
1248e4aa1f15SLeonid Yegoshin 		wd = insn.msa_mi10_format.wd;
1249e4aa1f15SLeonid Yegoshin 		fpr = &current->thread.fpu.fpr[wd];
1250e4aa1f15SLeonid Yegoshin 
1251e4aa1f15SLeonid Yegoshin 		switch (insn.msa_mi10_format.func) {
1252e4aa1f15SLeonid Yegoshin 		case msa_ld_op:
1253e4aa1f15SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, sizeof(*fpr)))
1254e4aa1f15SLeonid Yegoshin 				goto sigbus;
1255e4aa1f15SLeonid Yegoshin 
1256fa8ff601SPaul Burton 			do {
1257e4aa1f15SLeonid Yegoshin 				/*
1258fa8ff601SPaul Burton 				 * If we have live MSA context keep track of
1259fa8ff601SPaul Burton 				 * whether we get preempted in order to avoid
1260fa8ff601SPaul Burton 				 * the register context we load being clobbered
1261fa8ff601SPaul Burton 				 * by the live context as it's saved during
1262fa8ff601SPaul Burton 				 * preemption. If we don't have live context
1263fa8ff601SPaul Burton 				 * then it can't be saved to clobber the value
1264fa8ff601SPaul Burton 				 * we load.
1265e4aa1f15SLeonid Yegoshin 				 */
1266fa8ff601SPaul Burton 				preempted = test_thread_flag(TIF_USEDMSA);
1267e4aa1f15SLeonid Yegoshin 
1268e4aa1f15SLeonid Yegoshin 				res = __copy_from_user_inatomic(fpr, addr,
1269e4aa1f15SLeonid Yegoshin 								sizeof(*fpr));
1270e4aa1f15SLeonid Yegoshin 				if (res)
1271e4aa1f15SLeonid Yegoshin 					goto fault;
1272e4aa1f15SLeonid Yegoshin 
1273e4aa1f15SLeonid Yegoshin 				/*
1274fa8ff601SPaul Burton 				 * Update the hardware register if it is in use
1275fa8ff601SPaul Burton 				 * by the task in this quantum, in order to
1276fa8ff601SPaul Burton 				 * avoid having to save & restore the whole
1277fa8ff601SPaul Burton 				 * vector context.
1278e4aa1f15SLeonid Yegoshin 				 */
1279fa8ff601SPaul Burton 				preempt_disable();
1280fa8ff601SPaul Burton 				if (test_thread_flag(TIF_USEDMSA)) {
1281e4aa1f15SLeonid Yegoshin 					write_msa_wr(wd, fpr, df);
1282fa8ff601SPaul Burton 					preempted = 0;
1283fa8ff601SPaul Burton 				}
1284e4aa1f15SLeonid Yegoshin 				preempt_enable();
1285fa8ff601SPaul Burton 			} while (preempted);
1286e4aa1f15SLeonid Yegoshin 			break;
1287e4aa1f15SLeonid Yegoshin 
1288e4aa1f15SLeonid Yegoshin 		case msa_st_op:
1289e4aa1f15SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, sizeof(*fpr)))
1290e4aa1f15SLeonid Yegoshin 				goto sigbus;
1291e4aa1f15SLeonid Yegoshin 
1292e4aa1f15SLeonid Yegoshin 			/*
1293e4aa1f15SLeonid Yegoshin 			 * Update from the hardware register if it is in use by
1294e4aa1f15SLeonid Yegoshin 			 * the task in this quantum, in order to avoid having to
1295e4aa1f15SLeonid Yegoshin 			 * save & restore the whole vector context.
1296e4aa1f15SLeonid Yegoshin 			 */
1297e4aa1f15SLeonid Yegoshin 			preempt_disable();
1298e4aa1f15SLeonid Yegoshin 			if (test_thread_flag(TIF_USEDMSA))
1299e4aa1f15SLeonid Yegoshin 				read_msa_wr(wd, fpr, df);
1300e4aa1f15SLeonid Yegoshin 			preempt_enable();
1301e4aa1f15SLeonid Yegoshin 
1302e4aa1f15SLeonid Yegoshin 			res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr));
1303e4aa1f15SLeonid Yegoshin 			if (res)
1304e4aa1f15SLeonid Yegoshin 				goto fault;
1305e4aa1f15SLeonid Yegoshin 			break;
1306e4aa1f15SLeonid Yegoshin 
1307e4aa1f15SLeonid Yegoshin 		default:
1308e4aa1f15SLeonid Yegoshin 			goto sigbus;
1309e4aa1f15SLeonid Yegoshin 		}
1310e4aa1f15SLeonid Yegoshin 
1311e4aa1f15SLeonid Yegoshin 		compute_return_epc(regs);
1312e4aa1f15SLeonid Yegoshin 		break;
1313e4aa1f15SLeonid Yegoshin 
13140593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
13151da177e4SLinus Torvalds 	/*
131669f3a7deSRalf Baechle 	 * COP2 is available to implementor for application specific use.
131769f3a7deSRalf Baechle 	 * It's up to applications to register a notifier chain and do
131869f3a7deSRalf Baechle 	 * whatever they have to do, including possible sending of signals.
13190593a44cSLeonid Yegoshin 	 *
13200593a44cSLeonid Yegoshin 	 * This instruction has been reallocated in Release 6
13211da177e4SLinus Torvalds 	 */
132269f3a7deSRalf Baechle 	case lwc2_op:
132369f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
132469f3a7deSRalf Baechle 		break;
132569f3a7deSRalf Baechle 
132669f3a7deSRalf Baechle 	case ldc2_op:
132769f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
132869f3a7deSRalf Baechle 		break;
132969f3a7deSRalf Baechle 
133069f3a7deSRalf Baechle 	case swc2_op:
133169f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
133269f3a7deSRalf Baechle 		break;
133369f3a7deSRalf Baechle 
133469f3a7deSRalf Baechle 	case sdc2_op:
133569f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
133669f3a7deSRalf Baechle 		break;
13370593a44cSLeonid Yegoshin #endif
13381da177e4SLinus Torvalds 	default:
13391da177e4SLinus Torvalds 		/*
13401da177e4SLinus Torvalds 		 * Pheeee...  We encountered an yet unknown instruction or
13411da177e4SLinus Torvalds 		 * cache coherence problem.  Die sucker, die ...
13421da177e4SLinus Torvalds 		 */
13431da177e4SLinus Torvalds 		goto sigill;
13441da177e4SLinus Torvalds 	}
13451da177e4SLinus Torvalds 
13466312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
13471da177e4SLinus Torvalds 	unaligned_instructions++;
13481da177e4SLinus Torvalds #endif
13491da177e4SLinus Torvalds 
13507f18f151SRalf Baechle 	return;
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds fault:
135334c2f668SLeonid Yegoshin 	/* roll back jump/branch */
135434c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
135534c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
13561da177e4SLinus Torvalds 	/* Did we have an exception handler installed? */
13571da177e4SLinus Torvalds 	if (fixup_exception(regs))
13587f18f151SRalf Baechle 		return;
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
1361a6d5ff04SDavid Daney 	force_sig(SIGSEGV, current);
13621da177e4SLinus Torvalds 
13637f18f151SRalf Baechle 	return;
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds sigbus:
13661da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
1367a6d5ff04SDavid Daney 	force_sig(SIGBUS, current);
13681da177e4SLinus Torvalds 
13697f18f151SRalf Baechle 	return;
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds sigill:
137234c2f668SLeonid Yegoshin 	die_if_kernel
137334c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
137434c2f668SLeonid Yegoshin 	force_sig(SIGILL, current);
137534c2f668SLeonid Yegoshin }
137634c2f668SLeonid Yegoshin 
137734c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
137834c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
137934c2f668SLeonid Yegoshin 
138034c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
1381*b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
138234c2f668SLeonid Yegoshin 
138374338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
138474338805SDavid Daney 					 void __user *addr)
138534c2f668SLeonid Yegoshin {
138634c2f668SLeonid Yegoshin 	unsigned long value;
138734c2f668SLeonid Yegoshin 	unsigned int res;
138834c2f668SLeonid Yegoshin 	int i;
138934c2f668SLeonid Yegoshin 	unsigned int reg = 0, rvar;
139034c2f668SLeonid Yegoshin 	unsigned long orig31;
139134c2f668SLeonid Yegoshin 	u16 __user *pc16;
139234c2f668SLeonid Yegoshin 	u16 halfword;
139334c2f668SLeonid Yegoshin 	unsigned int word;
139434c2f668SLeonid Yegoshin 	unsigned long origpc, contpc;
139534c2f668SLeonid Yegoshin 	union mips_instruction insn;
139634c2f668SLeonid Yegoshin 	struct mm_decoded_insn mminsn;
139734c2f668SLeonid Yegoshin 	void __user *fault_addr = NULL;
139834c2f668SLeonid Yegoshin 
139934c2f668SLeonid Yegoshin 	origpc = regs->cp0_epc;
140034c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
140134c2f668SLeonid Yegoshin 
140234c2f668SLeonid Yegoshin 	mminsn.micro_mips_mode = 1;
140334c2f668SLeonid Yegoshin 
140434c2f668SLeonid Yegoshin 	/*
140534c2f668SLeonid Yegoshin 	 * This load never faults.
140634c2f668SLeonid Yegoshin 	 */
140734c2f668SLeonid Yegoshin 	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
140834c2f668SLeonid Yegoshin 	__get_user(halfword, pc16);
140934c2f668SLeonid Yegoshin 	pc16++;
141034c2f668SLeonid Yegoshin 	contpc = regs->cp0_epc + 2;
141134c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
141234c2f668SLeonid Yegoshin 	mminsn.pc_inc = 2;
141334c2f668SLeonid Yegoshin 
141434c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
141534c2f668SLeonid Yegoshin 		__get_user(halfword, pc16);
141634c2f668SLeonid Yegoshin 		pc16++;
141734c2f668SLeonid Yegoshin 		contpc = regs->cp0_epc + 4;
141834c2f668SLeonid Yegoshin 		mminsn.pc_inc = 4;
141934c2f668SLeonid Yegoshin 		word |= halfword;
142034c2f668SLeonid Yegoshin 	}
142134c2f668SLeonid Yegoshin 	mminsn.insn = word;
142234c2f668SLeonid Yegoshin 
142334c2f668SLeonid Yegoshin 	if (get_user(halfword, pc16))
142434c2f668SLeonid Yegoshin 		goto fault;
142534c2f668SLeonid Yegoshin 	mminsn.next_pc_inc = 2;
142634c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
142734c2f668SLeonid Yegoshin 
142834c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
142934c2f668SLeonid Yegoshin 		pc16++;
143034c2f668SLeonid Yegoshin 		if (get_user(halfword, pc16))
143134c2f668SLeonid Yegoshin 			goto fault;
143234c2f668SLeonid Yegoshin 		mminsn.next_pc_inc = 4;
143334c2f668SLeonid Yegoshin 		word |= halfword;
143434c2f668SLeonid Yegoshin 	}
143534c2f668SLeonid Yegoshin 	mminsn.next_insn = word;
143634c2f668SLeonid Yegoshin 
143734c2f668SLeonid Yegoshin 	insn = (union mips_instruction)(mminsn.insn);
143834c2f668SLeonid Yegoshin 	if (mm_isBranchInstr(regs, mminsn, &contpc))
143934c2f668SLeonid Yegoshin 		insn = (union mips_instruction)(mminsn.next_insn);
144034c2f668SLeonid Yegoshin 
144134c2f668SLeonid Yegoshin 	/*  Parse instruction to find what to do */
144234c2f668SLeonid Yegoshin 
144334c2f668SLeonid Yegoshin 	switch (insn.mm_i_format.opcode) {
144434c2f668SLeonid Yegoshin 
144534c2f668SLeonid Yegoshin 	case mm_pool32a_op:
144634c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
144734c2f668SLeonid Yegoshin 		case mm_lwxs_op:
144834c2f668SLeonid Yegoshin 			reg = insn.mm_x_format.rd;
144934c2f668SLeonid Yegoshin 			goto loadW;
145034c2f668SLeonid Yegoshin 		}
145134c2f668SLeonid Yegoshin 
145234c2f668SLeonid Yegoshin 		goto sigbus;
145334c2f668SLeonid Yegoshin 
145434c2f668SLeonid Yegoshin 	case mm_pool32b_op:
145534c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
145634c2f668SLeonid Yegoshin 		case mm_lwp_func:
145734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
145834c2f668SLeonid Yegoshin 			if (reg == 31)
145934c2f668SLeonid Yegoshin 				goto sigbus;
146034c2f668SLeonid Yegoshin 
146134c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 8))
146234c2f668SLeonid Yegoshin 				goto sigbus;
146334c2f668SLeonid Yegoshin 
146434c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
146534c2f668SLeonid Yegoshin 			if (res)
146634c2f668SLeonid Yegoshin 				goto fault;
146734c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
146834c2f668SLeonid Yegoshin 			addr += 4;
146934c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
147034c2f668SLeonid Yegoshin 			if (res)
147134c2f668SLeonid Yegoshin 				goto fault;
147234c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
147334c2f668SLeonid Yegoshin 			goto success;
147434c2f668SLeonid Yegoshin 
147534c2f668SLeonid Yegoshin 		case mm_swp_func:
147634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
147734c2f668SLeonid Yegoshin 			if (reg == 31)
147834c2f668SLeonid Yegoshin 				goto sigbus;
147934c2f668SLeonid Yegoshin 
148034c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 8))
148134c2f668SLeonid Yegoshin 				goto sigbus;
148234c2f668SLeonid Yegoshin 
148334c2f668SLeonid Yegoshin 			value = regs->regs[reg];
148434c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
148534c2f668SLeonid Yegoshin 			if (res)
148634c2f668SLeonid Yegoshin 				goto fault;
148734c2f668SLeonid Yegoshin 			addr += 4;
148834c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
148934c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
149034c2f668SLeonid Yegoshin 			if (res)
149134c2f668SLeonid Yegoshin 				goto fault;
149234c2f668SLeonid Yegoshin 			goto success;
149334c2f668SLeonid Yegoshin 
149434c2f668SLeonid Yegoshin 		case mm_ldp_func:
149534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
149634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
149734c2f668SLeonid Yegoshin 			if (reg == 31)
149834c2f668SLeonid Yegoshin 				goto sigbus;
149934c2f668SLeonid Yegoshin 
150034c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 16))
150134c2f668SLeonid Yegoshin 				goto sigbus;
150234c2f668SLeonid Yegoshin 
150334c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
150434c2f668SLeonid Yegoshin 			if (res)
150534c2f668SLeonid Yegoshin 				goto fault;
150634c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
150734c2f668SLeonid Yegoshin 			addr += 8;
150834c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
150934c2f668SLeonid Yegoshin 			if (res)
151034c2f668SLeonid Yegoshin 				goto fault;
151134c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
151234c2f668SLeonid Yegoshin 			goto success;
151334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
151434c2f668SLeonid Yegoshin 
151534c2f668SLeonid Yegoshin 			goto sigill;
151634c2f668SLeonid Yegoshin 
151734c2f668SLeonid Yegoshin 		case mm_sdp_func:
151834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
151934c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
152034c2f668SLeonid Yegoshin 			if (reg == 31)
152134c2f668SLeonid Yegoshin 				goto sigbus;
152234c2f668SLeonid Yegoshin 
152334c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 16))
152434c2f668SLeonid Yegoshin 				goto sigbus;
152534c2f668SLeonid Yegoshin 
152634c2f668SLeonid Yegoshin 			value = regs->regs[reg];
152734c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
152834c2f668SLeonid Yegoshin 			if (res)
152934c2f668SLeonid Yegoshin 				goto fault;
153034c2f668SLeonid Yegoshin 			addr += 8;
153134c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
153234c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
153334c2f668SLeonid Yegoshin 			if (res)
153434c2f668SLeonid Yegoshin 				goto fault;
153534c2f668SLeonid Yegoshin 			goto success;
153634c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
153734c2f668SLeonid Yegoshin 
153834c2f668SLeonid Yegoshin 			goto sigill;
153934c2f668SLeonid Yegoshin 
154034c2f668SLeonid Yegoshin 		case mm_lwm32_func:
154134c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
154234c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
154334c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
154434c2f668SLeonid Yegoshin 				goto sigill;
154534c2f668SLeonid Yegoshin 			if (reg & 0x10) {
154634c2f668SLeonid Yegoshin 				if (!access_ok
154734c2f668SLeonid Yegoshin 				    (VERIFY_READ, addr, 4 * (rvar + 1)))
154834c2f668SLeonid Yegoshin 					goto sigbus;
154934c2f668SLeonid Yegoshin 			} else {
155034c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 4 * rvar))
155134c2f668SLeonid Yegoshin 					goto sigbus;
155234c2f668SLeonid Yegoshin 			}
155334c2f668SLeonid Yegoshin 			if (rvar == 9)
155434c2f668SLeonid Yegoshin 				rvar = 8;
155534c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
155634c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
155734c2f668SLeonid Yegoshin 				if (res)
155834c2f668SLeonid Yegoshin 					goto fault;
155934c2f668SLeonid Yegoshin 				addr += 4;
156034c2f668SLeonid Yegoshin 				regs->regs[i] = value;
156134c2f668SLeonid Yegoshin 			}
156234c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
156334c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
156434c2f668SLeonid Yegoshin 				if (res)
156534c2f668SLeonid Yegoshin 					goto fault;
156634c2f668SLeonid Yegoshin 				addr += 4;
156734c2f668SLeonid Yegoshin 				regs->regs[30] = value;
156834c2f668SLeonid Yegoshin 			}
156934c2f668SLeonid Yegoshin 			if (reg & 0x10) {
157034c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
157134c2f668SLeonid Yegoshin 				if (res)
157234c2f668SLeonid Yegoshin 					goto fault;
157334c2f668SLeonid Yegoshin 				regs->regs[31] = value;
157434c2f668SLeonid Yegoshin 			}
157534c2f668SLeonid Yegoshin 			goto success;
157634c2f668SLeonid Yegoshin 
157734c2f668SLeonid Yegoshin 		case mm_swm32_func:
157834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
157934c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
158034c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
158134c2f668SLeonid Yegoshin 				goto sigill;
158234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
158334c2f668SLeonid Yegoshin 				if (!access_ok
158434c2f668SLeonid Yegoshin 				    (VERIFY_WRITE, addr, 4 * (rvar + 1)))
158534c2f668SLeonid Yegoshin 					goto sigbus;
158634c2f668SLeonid Yegoshin 			} else {
158734c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
158834c2f668SLeonid Yegoshin 					goto sigbus;
158934c2f668SLeonid Yegoshin 			}
159034c2f668SLeonid Yegoshin 			if (rvar == 9)
159134c2f668SLeonid Yegoshin 				rvar = 8;
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 			if ((reg & 0xf) == 9) {
160034c2f668SLeonid Yegoshin 				value = regs->regs[30];
160134c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
160234c2f668SLeonid Yegoshin 				if (res)
160334c2f668SLeonid Yegoshin 					goto fault;
160434c2f668SLeonid Yegoshin 				addr += 4;
160534c2f668SLeonid Yegoshin 			}
160634c2f668SLeonid Yegoshin 			if (reg & 0x10) {
160734c2f668SLeonid Yegoshin 				value = regs->regs[31];
160834c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
160934c2f668SLeonid Yegoshin 				if (res)
161034c2f668SLeonid Yegoshin 					goto fault;
161134c2f668SLeonid Yegoshin 			}
161234c2f668SLeonid Yegoshin 			goto success;
161334c2f668SLeonid Yegoshin 
161434c2f668SLeonid Yegoshin 		case mm_ldm_func:
161534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
161634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
161734c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
161834c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
161934c2f668SLeonid Yegoshin 				goto sigill;
162034c2f668SLeonid Yegoshin 			if (reg & 0x10) {
162134c2f668SLeonid Yegoshin 				if (!access_ok
162234c2f668SLeonid Yegoshin 				    (VERIFY_READ, addr, 8 * (rvar + 1)))
162334c2f668SLeonid Yegoshin 					goto sigbus;
162434c2f668SLeonid Yegoshin 			} else {
162534c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 8 * rvar))
162634c2f668SLeonid Yegoshin 					goto sigbus;
162734c2f668SLeonid Yegoshin 			}
162834c2f668SLeonid Yegoshin 			if (rvar == 9)
162934c2f668SLeonid Yegoshin 				rvar = 8;
163034c2f668SLeonid Yegoshin 
163134c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
163234c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
163334c2f668SLeonid Yegoshin 				if (res)
163434c2f668SLeonid Yegoshin 					goto fault;
163534c2f668SLeonid Yegoshin 				addr += 4;
163634c2f668SLeonid Yegoshin 				regs->regs[i] = value;
163734c2f668SLeonid Yegoshin 			}
163834c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
163934c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
164034c2f668SLeonid Yegoshin 				if (res)
164134c2f668SLeonid Yegoshin 					goto fault;
164234c2f668SLeonid Yegoshin 				addr += 8;
164334c2f668SLeonid Yegoshin 				regs->regs[30] = value;
164434c2f668SLeonid Yegoshin 			}
164534c2f668SLeonid Yegoshin 			if (reg & 0x10) {
164634c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
164734c2f668SLeonid Yegoshin 				if (res)
164834c2f668SLeonid Yegoshin 					goto fault;
164934c2f668SLeonid Yegoshin 				regs->regs[31] = value;
165034c2f668SLeonid Yegoshin 			}
165134c2f668SLeonid Yegoshin 			goto success;
165234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
165334c2f668SLeonid Yegoshin 
165434c2f668SLeonid Yegoshin 			goto sigill;
165534c2f668SLeonid Yegoshin 
165634c2f668SLeonid Yegoshin 		case mm_sdm_func:
165734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
165834c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
165934c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
166034c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
166134c2f668SLeonid Yegoshin 				goto sigill;
166234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
166334c2f668SLeonid Yegoshin 				if (!access_ok
166434c2f668SLeonid Yegoshin 				    (VERIFY_WRITE, addr, 8 * (rvar + 1)))
166534c2f668SLeonid Yegoshin 					goto sigbus;
166634c2f668SLeonid Yegoshin 			} else {
166734c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 8 * rvar))
166834c2f668SLeonid Yegoshin 					goto sigbus;
166934c2f668SLeonid Yegoshin 			}
167034c2f668SLeonid Yegoshin 			if (rvar == 9)
167134c2f668SLeonid Yegoshin 				rvar = 8;
167234c2f668SLeonid Yegoshin 
167334c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
167434c2f668SLeonid Yegoshin 				value = regs->regs[i];
167534c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
167634c2f668SLeonid Yegoshin 				if (res)
167734c2f668SLeonid Yegoshin 					goto fault;
167834c2f668SLeonid Yegoshin 				addr += 8;
167934c2f668SLeonid Yegoshin 			}
168034c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
168134c2f668SLeonid Yegoshin 				value = regs->regs[30];
168234c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
168334c2f668SLeonid Yegoshin 				if (res)
168434c2f668SLeonid Yegoshin 					goto fault;
168534c2f668SLeonid Yegoshin 				addr += 8;
168634c2f668SLeonid Yegoshin 			}
168734c2f668SLeonid Yegoshin 			if (reg & 0x10) {
168834c2f668SLeonid Yegoshin 				value = regs->regs[31];
168934c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
169034c2f668SLeonid Yegoshin 				if (res)
169134c2f668SLeonid Yegoshin 					goto fault;
169234c2f668SLeonid Yegoshin 			}
169334c2f668SLeonid Yegoshin 			goto success;
169434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
169534c2f668SLeonid Yegoshin 
169634c2f668SLeonid Yegoshin 			goto sigill;
169734c2f668SLeonid Yegoshin 
169834c2f668SLeonid Yegoshin 			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
169934c2f668SLeonid Yegoshin 		}
170034c2f668SLeonid Yegoshin 
170134c2f668SLeonid Yegoshin 		goto sigbus;
170234c2f668SLeonid Yegoshin 
170334c2f668SLeonid Yegoshin 	case mm_pool32c_op:
170434c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
170534c2f668SLeonid Yegoshin 		case mm_lwu_func:
170634c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
170734c2f668SLeonid Yegoshin 			goto loadWU;
170834c2f668SLeonid Yegoshin 		}
170934c2f668SLeonid Yegoshin 
171034c2f668SLeonid Yegoshin 		/*  LL,SC,LLD,SCD are not serviced */
171134c2f668SLeonid Yegoshin 		goto sigbus;
171234c2f668SLeonid Yegoshin 
171334c2f668SLeonid Yegoshin 	case mm_pool32f_op:
171434c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
171534c2f668SLeonid Yegoshin 		case mm_lwxc1_func:
171634c2f668SLeonid Yegoshin 		case mm_swxc1_func:
171734c2f668SLeonid Yegoshin 		case mm_ldxc1_func:
171834c2f668SLeonid Yegoshin 		case mm_sdxc1_func:
171934c2f668SLeonid Yegoshin 			goto fpu_emul;
172034c2f668SLeonid Yegoshin 		}
172134c2f668SLeonid Yegoshin 
172234c2f668SLeonid Yegoshin 		goto sigbus;
172334c2f668SLeonid Yegoshin 
172434c2f668SLeonid Yegoshin 	case mm_ldc132_op:
172534c2f668SLeonid Yegoshin 	case mm_sdc132_op:
172634c2f668SLeonid Yegoshin 	case mm_lwc132_op:
172734c2f668SLeonid Yegoshin 	case mm_swc132_op:
172834c2f668SLeonid Yegoshin fpu_emul:
172934c2f668SLeonid Yegoshin 		/* roll back jump/branch */
173034c2f668SLeonid Yegoshin 		regs->cp0_epc = origpc;
173134c2f668SLeonid Yegoshin 		regs->regs[31] = orig31;
173234c2f668SLeonid Yegoshin 
173334c2f668SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
173434c2f668SLeonid Yegoshin 		BUG_ON(!used_math());
173534c2f668SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
173634c2f668SLeonid Yegoshin 
173734c2f668SLeonid Yegoshin 		lose_fpu(1);	/* save the FPU state for the emulator */
173834c2f668SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
173934c2f668SLeonid Yegoshin 					       &fault_addr);
174034c2f668SLeonid Yegoshin 		own_fpu(1);	/* restore FPU state */
174134c2f668SLeonid Yegoshin 
174234c2f668SLeonid Yegoshin 		/* If something went wrong, signal */
1743304acb71SMaciej W. Rozycki 		process_fpemu_return(res, fault_addr, 0);
174434c2f668SLeonid Yegoshin 
174534c2f668SLeonid Yegoshin 		if (res == 0)
174634c2f668SLeonid Yegoshin 			goto success;
174734c2f668SLeonid Yegoshin 		return;
174834c2f668SLeonid Yegoshin 
174934c2f668SLeonid Yegoshin 	case mm_lh32_op:
175034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
175134c2f668SLeonid Yegoshin 		goto loadHW;
175234c2f668SLeonid Yegoshin 
175334c2f668SLeonid Yegoshin 	case mm_lhu32_op:
175434c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
175534c2f668SLeonid Yegoshin 		goto loadHWU;
175634c2f668SLeonid Yegoshin 
175734c2f668SLeonid Yegoshin 	case mm_lw32_op:
175834c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
175934c2f668SLeonid Yegoshin 		goto loadW;
176034c2f668SLeonid Yegoshin 
176134c2f668SLeonid Yegoshin 	case mm_sh32_op:
176234c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
176334c2f668SLeonid Yegoshin 		goto storeHW;
176434c2f668SLeonid Yegoshin 
176534c2f668SLeonid Yegoshin 	case mm_sw32_op:
176634c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
176734c2f668SLeonid Yegoshin 		goto storeW;
176834c2f668SLeonid Yegoshin 
176934c2f668SLeonid Yegoshin 	case mm_ld32_op:
177034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
177134c2f668SLeonid Yegoshin 		goto loadDW;
177234c2f668SLeonid Yegoshin 
177334c2f668SLeonid Yegoshin 	case mm_sd32_op:
177434c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
177534c2f668SLeonid Yegoshin 		goto storeDW;
177634c2f668SLeonid Yegoshin 
177734c2f668SLeonid Yegoshin 	case mm_pool16c_op:
177834c2f668SLeonid Yegoshin 		switch (insn.mm16_m_format.func) {
177934c2f668SLeonid Yegoshin 		case mm_lwm16_op:
178034c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
178134c2f668SLeonid Yegoshin 			rvar = reg + 1;
178234c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 4 * rvar))
178334c2f668SLeonid Yegoshin 				goto sigbus;
178434c2f668SLeonid Yegoshin 
178534c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
178634c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
178734c2f668SLeonid Yegoshin 				if (res)
178834c2f668SLeonid Yegoshin 					goto fault;
178934c2f668SLeonid Yegoshin 				addr += 4;
179034c2f668SLeonid Yegoshin 				regs->regs[i] = value;
179134c2f668SLeonid Yegoshin 			}
179234c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
179334c2f668SLeonid Yegoshin 			if (res)
179434c2f668SLeonid Yegoshin 				goto fault;
179534c2f668SLeonid Yegoshin 			regs->regs[31] = value;
179634c2f668SLeonid Yegoshin 
179734c2f668SLeonid Yegoshin 			goto success;
179834c2f668SLeonid Yegoshin 
179934c2f668SLeonid Yegoshin 		case mm_swm16_op:
180034c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
180134c2f668SLeonid Yegoshin 			rvar = reg + 1;
180234c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
180334c2f668SLeonid Yegoshin 				goto sigbus;
180434c2f668SLeonid Yegoshin 
180534c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
180634c2f668SLeonid Yegoshin 				value = regs->regs[i];
180734c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
180834c2f668SLeonid Yegoshin 				if (res)
180934c2f668SLeonid Yegoshin 					goto fault;
181034c2f668SLeonid Yegoshin 				addr += 4;
181134c2f668SLeonid Yegoshin 			}
181234c2f668SLeonid Yegoshin 			value = regs->regs[31];
181334c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
181434c2f668SLeonid Yegoshin 			if (res)
181534c2f668SLeonid Yegoshin 				goto fault;
181634c2f668SLeonid Yegoshin 
181734c2f668SLeonid Yegoshin 			goto success;
181834c2f668SLeonid Yegoshin 
181934c2f668SLeonid Yegoshin 		}
182034c2f668SLeonid Yegoshin 
182134c2f668SLeonid Yegoshin 		goto sigbus;
182234c2f668SLeonid Yegoshin 
182334c2f668SLeonid Yegoshin 	case mm_lhu16_op:
182434c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
182534c2f668SLeonid Yegoshin 		goto loadHWU;
182634c2f668SLeonid Yegoshin 
182734c2f668SLeonid Yegoshin 	case mm_lw16_op:
182834c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
182934c2f668SLeonid Yegoshin 		goto loadW;
183034c2f668SLeonid Yegoshin 
183134c2f668SLeonid Yegoshin 	case mm_sh16_op:
183234c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
183334c2f668SLeonid Yegoshin 		goto storeHW;
183434c2f668SLeonid Yegoshin 
183534c2f668SLeonid Yegoshin 	case mm_sw16_op:
183634c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
183734c2f668SLeonid Yegoshin 		goto storeW;
183834c2f668SLeonid Yegoshin 
183934c2f668SLeonid Yegoshin 	case mm_lwsp16_op:
184034c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
184134c2f668SLeonid Yegoshin 		goto loadW;
184234c2f668SLeonid Yegoshin 
184334c2f668SLeonid Yegoshin 	case mm_swsp16_op:
184434c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
184534c2f668SLeonid Yegoshin 		goto storeW;
184634c2f668SLeonid Yegoshin 
184734c2f668SLeonid Yegoshin 	case mm_lwgp16_op:
184834c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_r3_format.rt];
184934c2f668SLeonid Yegoshin 		goto loadW;
185034c2f668SLeonid Yegoshin 
185134c2f668SLeonid Yegoshin 	default:
185234c2f668SLeonid Yegoshin 		goto sigill;
185334c2f668SLeonid Yegoshin 	}
185434c2f668SLeonid Yegoshin 
185534c2f668SLeonid Yegoshin loadHW:
185634c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 2))
185734c2f668SLeonid Yegoshin 		goto sigbus;
185834c2f668SLeonid Yegoshin 
185934c2f668SLeonid Yegoshin 	LoadHW(addr, value, res);
186034c2f668SLeonid Yegoshin 	if (res)
186134c2f668SLeonid Yegoshin 		goto fault;
186234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
186334c2f668SLeonid Yegoshin 	goto success;
186434c2f668SLeonid Yegoshin 
186534c2f668SLeonid Yegoshin loadHWU:
186634c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 2))
186734c2f668SLeonid Yegoshin 		goto sigbus;
186834c2f668SLeonid Yegoshin 
186934c2f668SLeonid Yegoshin 	LoadHWU(addr, value, res);
187034c2f668SLeonid Yegoshin 	if (res)
187134c2f668SLeonid Yegoshin 		goto fault;
187234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
187334c2f668SLeonid Yegoshin 	goto success;
187434c2f668SLeonid Yegoshin 
187534c2f668SLeonid Yegoshin loadW:
187634c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 4))
187734c2f668SLeonid Yegoshin 		goto sigbus;
187834c2f668SLeonid Yegoshin 
187934c2f668SLeonid Yegoshin 	LoadW(addr, value, res);
188034c2f668SLeonid Yegoshin 	if (res)
188134c2f668SLeonid Yegoshin 		goto fault;
188234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
188334c2f668SLeonid Yegoshin 	goto success;
188434c2f668SLeonid Yegoshin 
188534c2f668SLeonid Yegoshin loadWU:
188634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
188734c2f668SLeonid Yegoshin 	/*
188834c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
188934c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
189034c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
189134c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
189234c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
189334c2f668SLeonid Yegoshin 	 */
189434c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 4))
189534c2f668SLeonid Yegoshin 		goto sigbus;
189634c2f668SLeonid Yegoshin 
189734c2f668SLeonid Yegoshin 	LoadWU(addr, value, res);
189834c2f668SLeonid Yegoshin 	if (res)
189934c2f668SLeonid Yegoshin 		goto fault;
190034c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
190134c2f668SLeonid Yegoshin 	goto success;
190234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
190334c2f668SLeonid Yegoshin 
190434c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
190534c2f668SLeonid Yegoshin 	goto sigill;
190634c2f668SLeonid Yegoshin 
190734c2f668SLeonid Yegoshin loadDW:
190834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
190934c2f668SLeonid Yegoshin 	/*
191034c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
191134c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
191234c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
191334c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
191434c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
191534c2f668SLeonid Yegoshin 	 */
191634c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 8))
191734c2f668SLeonid Yegoshin 		goto sigbus;
191834c2f668SLeonid Yegoshin 
191934c2f668SLeonid Yegoshin 	LoadDW(addr, value, res);
192034c2f668SLeonid Yegoshin 	if (res)
192134c2f668SLeonid Yegoshin 		goto fault;
192234c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
192334c2f668SLeonid Yegoshin 	goto success;
192434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
192534c2f668SLeonid Yegoshin 
192634c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
192734c2f668SLeonid Yegoshin 	goto sigill;
192834c2f668SLeonid Yegoshin 
192934c2f668SLeonid Yegoshin storeHW:
193034c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 2))
193134c2f668SLeonid Yegoshin 		goto sigbus;
193234c2f668SLeonid Yegoshin 
193334c2f668SLeonid Yegoshin 	value = regs->regs[reg];
193434c2f668SLeonid Yegoshin 	StoreHW(addr, value, res);
193534c2f668SLeonid Yegoshin 	if (res)
193634c2f668SLeonid Yegoshin 		goto fault;
193734c2f668SLeonid Yegoshin 	goto success;
193834c2f668SLeonid Yegoshin 
193934c2f668SLeonid Yegoshin storeW:
194034c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 4))
194134c2f668SLeonid Yegoshin 		goto sigbus;
194234c2f668SLeonid Yegoshin 
194334c2f668SLeonid Yegoshin 	value = regs->regs[reg];
194434c2f668SLeonid Yegoshin 	StoreW(addr, value, res);
194534c2f668SLeonid Yegoshin 	if (res)
194634c2f668SLeonid Yegoshin 		goto fault;
194734c2f668SLeonid Yegoshin 	goto success;
194834c2f668SLeonid Yegoshin 
194934c2f668SLeonid Yegoshin storeDW:
195034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
195134c2f668SLeonid Yegoshin 	/*
195234c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
195334c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
195434c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
195534c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
195634c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
195734c2f668SLeonid Yegoshin 	 */
195834c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 8))
195934c2f668SLeonid Yegoshin 		goto sigbus;
196034c2f668SLeonid Yegoshin 
196134c2f668SLeonid Yegoshin 	value = regs->regs[reg];
196234c2f668SLeonid Yegoshin 	StoreDW(addr, value, res);
196334c2f668SLeonid Yegoshin 	if (res)
196434c2f668SLeonid Yegoshin 		goto fault;
196534c2f668SLeonid Yegoshin 	goto success;
196634c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
196734c2f668SLeonid Yegoshin 
196834c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
196934c2f668SLeonid Yegoshin 	goto sigill;
197034c2f668SLeonid Yegoshin 
197134c2f668SLeonid Yegoshin success:
197234c2f668SLeonid Yegoshin 	regs->cp0_epc = contpc;	/* advance or branch */
197334c2f668SLeonid Yegoshin 
197434c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
197534c2f668SLeonid Yegoshin 	unaligned_instructions++;
197634c2f668SLeonid Yegoshin #endif
197734c2f668SLeonid Yegoshin 	return;
197834c2f668SLeonid Yegoshin 
197934c2f668SLeonid Yegoshin fault:
198034c2f668SLeonid Yegoshin 	/* roll back jump/branch */
198134c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
198234c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
198334c2f668SLeonid Yegoshin 	/* Did we have an exception handler installed? */
198434c2f668SLeonid Yegoshin 	if (fixup_exception(regs))
198534c2f668SLeonid Yegoshin 		return;
198634c2f668SLeonid Yegoshin 
198734c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
198834c2f668SLeonid Yegoshin 	force_sig(SIGSEGV, current);
198934c2f668SLeonid Yegoshin 
199034c2f668SLeonid Yegoshin 	return;
199134c2f668SLeonid Yegoshin 
199234c2f668SLeonid Yegoshin sigbus:
199334c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
199434c2f668SLeonid Yegoshin 	force_sig(SIGBUS, current);
199534c2f668SLeonid Yegoshin 
199634c2f668SLeonid Yegoshin 	return;
199734c2f668SLeonid Yegoshin 
199834c2f668SLeonid Yegoshin sigill:
199934c2f668SLeonid Yegoshin 	die_if_kernel
200034c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
2001a6d5ff04SDavid Daney 	force_sig(SIGILL, current);
20021da177e4SLinus Torvalds }
20031da177e4SLinus Torvalds 
2004451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
2005451b001bSSteven J. Hill {
2006451b001bSSteven J. Hill 	unsigned long value;
2007451b001bSSteven J. Hill 	unsigned int res;
2008451b001bSSteven J. Hill 	int reg;
2009451b001bSSteven J. Hill 	unsigned long orig31;
2010451b001bSSteven J. Hill 	u16 __user *pc16;
2011451b001bSSteven J. Hill 	unsigned long origpc;
2012451b001bSSteven J. Hill 	union mips16e_instruction mips16inst, oldinst;
2013f3235d32SMaciej W. Rozycki 	unsigned int opcode;
2014f3235d32SMaciej W. Rozycki 	int extended = 0;
2015451b001bSSteven J. Hill 
2016451b001bSSteven J. Hill 	origpc = regs->cp0_epc;
2017451b001bSSteven J. Hill 	orig31 = regs->regs[31];
2018451b001bSSteven J. Hill 	pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
2019451b001bSSteven J. Hill 	/*
2020451b001bSSteven J. Hill 	 * This load never faults.
2021451b001bSSteven J. Hill 	 */
2022451b001bSSteven J. Hill 	__get_user(mips16inst.full, pc16);
2023451b001bSSteven J. Hill 	oldinst = mips16inst;
2024451b001bSSteven J. Hill 
2025451b001bSSteven J. Hill 	/* skip EXTEND instruction */
2026451b001bSSteven J. Hill 	if (mips16inst.ri.opcode == MIPS16e_extend_op) {
2027f3235d32SMaciej W. Rozycki 		extended = 1;
2028451b001bSSteven J. Hill 		pc16++;
2029451b001bSSteven J. Hill 		__get_user(mips16inst.full, pc16);
2030451b001bSSteven J. Hill 	} else if (delay_slot(regs)) {
2031451b001bSSteven J. Hill 		/*  skip jump instructions */
2032451b001bSSteven J. Hill 		/*  JAL/JALX are 32 bits but have OPCODE in first short int */
2033451b001bSSteven J. Hill 		if (mips16inst.ri.opcode == MIPS16e_jal_op)
2034451b001bSSteven J. Hill 			pc16++;
2035451b001bSSteven J. Hill 		pc16++;
2036451b001bSSteven J. Hill 		if (get_user(mips16inst.full, pc16))
2037451b001bSSteven J. Hill 			goto sigbus;
2038451b001bSSteven J. Hill 	}
2039451b001bSSteven J. Hill 
2040f3235d32SMaciej W. Rozycki 	opcode = mips16inst.ri.opcode;
2041f3235d32SMaciej W. Rozycki 	switch (opcode) {
2042451b001bSSteven J. Hill 	case MIPS16e_i64_op:	/* I64 or RI64 instruction */
2043451b001bSSteven J. Hill 		switch (mips16inst.i64.func) {	/* I64/RI64 func field check */
2044451b001bSSteven J. Hill 		case MIPS16e_ldpc_func:
2045451b001bSSteven J. Hill 		case MIPS16e_ldsp_func:
2046451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
2047451b001bSSteven J. Hill 			goto loadDW;
2048451b001bSSteven J. Hill 
2049451b001bSSteven J. Hill 		case MIPS16e_sdsp_func:
2050451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
2051451b001bSSteven J. Hill 			goto writeDW;
2052451b001bSSteven J. Hill 
2053451b001bSSteven J. Hill 		case MIPS16e_sdrasp_func:
2054451b001bSSteven J. Hill 			reg = 29;	/* GPRSP */
2055451b001bSSteven J. Hill 			goto writeDW;
2056451b001bSSteven J. Hill 		}
2057451b001bSSteven J. Hill 
2058451b001bSSteven J. Hill 		goto sigbus;
2059451b001bSSteven J. Hill 
2060451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
2061f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
2062f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
2063f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
2064f3235d32SMaciej W. Rozycki 			case 0:		/* SWSP */
2065f3235d32SMaciej W. Rozycki 			case 1:		/* SWGP */
2066f3235d32SMaciej W. Rozycki 				break;
2067f3235d32SMaciej W. Rozycki 			case 2:		/* SHGP */
2068f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_sh_op;
2069f3235d32SMaciej W. Rozycki 				break;
2070f3235d32SMaciej W. Rozycki 			default:
2071f3235d32SMaciej W. Rozycki 				goto sigbus;
2072f3235d32SMaciej W. Rozycki 			}
2073f3235d32SMaciej W. Rozycki 		break;
2074f3235d32SMaciej W. Rozycki 
2075451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
2076f3235d32SMaciej W. Rozycki 		reg = reg16to32[mips16inst.ri.rx];
2077f3235d32SMaciej W. Rozycki 		break;
2078f3235d32SMaciej W. Rozycki 
2079451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
2080451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.ri.rx];
2081f3235d32SMaciej W. Rozycki 		if (extended && cpu_has_mips16e2)
2082f3235d32SMaciej W. Rozycki 			switch (mips16inst.ri.imm >> 5) {
2083f3235d32SMaciej W. Rozycki 			case 0:		/* LWSP */
2084f3235d32SMaciej W. Rozycki 			case 1:		/* LWGP */
2085f3235d32SMaciej W. Rozycki 				break;
2086f3235d32SMaciej W. Rozycki 			case 2:		/* LHGP */
2087f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lh_op;
2088f3235d32SMaciej W. Rozycki 				break;
2089f3235d32SMaciej W. Rozycki 			case 4:		/* LHUGP */
2090f3235d32SMaciej W. Rozycki 				opcode = MIPS16e_lhu_op;
2091f3235d32SMaciej W. Rozycki 				break;
2092f3235d32SMaciej W. Rozycki 			default:
2093f3235d32SMaciej W. Rozycki 				goto sigbus;
2094f3235d32SMaciej W. Rozycki 			}
2095451b001bSSteven J. Hill 		break;
2096451b001bSSteven J. Hill 
2097451b001bSSteven J. Hill 	case MIPS16e_i8_op:
2098451b001bSSteven J. Hill 		if (mips16inst.i8.func != MIPS16e_swrasp_func)
2099451b001bSSteven J. Hill 			goto sigbus;
2100451b001bSSteven J. Hill 		reg = 29;	/* GPRSP */
2101451b001bSSteven J. Hill 		break;
2102451b001bSSteven J. Hill 
2103451b001bSSteven J. Hill 	default:
2104451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.rri.ry];
2105451b001bSSteven J. Hill 		break;
2106451b001bSSteven J. Hill 	}
2107451b001bSSteven J. Hill 
2108f3235d32SMaciej W. Rozycki 	switch (opcode) {
2109451b001bSSteven J. Hill 
2110451b001bSSteven J. Hill 	case MIPS16e_lb_op:
2111451b001bSSteven J. Hill 	case MIPS16e_lbu_op:
2112451b001bSSteven J. Hill 	case MIPS16e_sb_op:
2113451b001bSSteven J. Hill 		goto sigbus;
2114451b001bSSteven J. Hill 
2115451b001bSSteven J. Hill 	case MIPS16e_lh_op:
2116451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 2))
2117451b001bSSteven J. Hill 			goto sigbus;
2118451b001bSSteven J. Hill 
2119451b001bSSteven J. Hill 		LoadHW(addr, value, res);
2120451b001bSSteven J. Hill 		if (res)
2121451b001bSSteven J. Hill 			goto fault;
2122451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2123451b001bSSteven J. Hill 		regs->regs[reg] = value;
2124451b001bSSteven J. Hill 		break;
2125451b001bSSteven J. Hill 
2126451b001bSSteven J. Hill 	case MIPS16e_lhu_op:
2127451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 2))
2128451b001bSSteven J. Hill 			goto sigbus;
2129451b001bSSteven J. Hill 
2130451b001bSSteven J. Hill 		LoadHWU(addr, value, res);
2131451b001bSSteven J. Hill 		if (res)
2132451b001bSSteven J. Hill 			goto fault;
2133451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2134451b001bSSteven J. Hill 		regs->regs[reg] = value;
2135451b001bSSteven J. Hill 		break;
2136451b001bSSteven J. Hill 
2137451b001bSSteven J. Hill 	case MIPS16e_lw_op:
2138451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
2139451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
2140451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 4))
2141451b001bSSteven J. Hill 			goto sigbus;
2142451b001bSSteven J. Hill 
2143451b001bSSteven J. Hill 		LoadW(addr, value, res);
2144451b001bSSteven J. Hill 		if (res)
2145451b001bSSteven J. Hill 			goto fault;
2146451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2147451b001bSSteven J. Hill 		regs->regs[reg] = value;
2148451b001bSSteven J. Hill 		break;
2149451b001bSSteven J. Hill 
2150451b001bSSteven J. Hill 	case MIPS16e_lwu_op:
2151451b001bSSteven J. Hill #ifdef CONFIG_64BIT
2152451b001bSSteven J. Hill 		/*
2153451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
2154451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
2155451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
2156451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
2157451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
2158451b001bSSteven J. Hill 		 */
2159451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 4))
2160451b001bSSteven J. Hill 			goto sigbus;
2161451b001bSSteven J. Hill 
2162451b001bSSteven J. Hill 		LoadWU(addr, value, res);
2163451b001bSSteven J. Hill 		if (res)
2164451b001bSSteven J. Hill 			goto fault;
2165451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2166451b001bSSteven J. Hill 		regs->regs[reg] = value;
2167451b001bSSteven J. Hill 		break;
2168451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
2169451b001bSSteven J. Hill 
2170451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
2171451b001bSSteven J. Hill 		goto sigill;
2172451b001bSSteven J. Hill 
2173451b001bSSteven J. Hill 	case MIPS16e_ld_op:
2174451b001bSSteven J. Hill loadDW:
2175451b001bSSteven J. Hill #ifdef CONFIG_64BIT
2176451b001bSSteven J. Hill 		/*
2177451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
2178451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
2179451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
2180451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
2181451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
2182451b001bSSteven J. Hill 		 */
2183451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 8))
2184451b001bSSteven J. Hill 			goto sigbus;
2185451b001bSSteven J. Hill 
2186451b001bSSteven J. Hill 		LoadDW(addr, value, res);
2187451b001bSSteven J. Hill 		if (res)
2188451b001bSSteven J. Hill 			goto fault;
2189451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2190451b001bSSteven J. Hill 		regs->regs[reg] = value;
2191451b001bSSteven J. Hill 		break;
2192451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
2193451b001bSSteven J. Hill 
2194451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
2195451b001bSSteven J. Hill 		goto sigill;
2196451b001bSSteven J. Hill 
2197451b001bSSteven J. Hill 	case MIPS16e_sh_op:
2198451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 2))
2199451b001bSSteven J. Hill 			goto sigbus;
2200451b001bSSteven J. Hill 
2201451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2202451b001bSSteven J. Hill 		value = regs->regs[reg];
2203451b001bSSteven J. Hill 		StoreHW(addr, value, res);
2204451b001bSSteven J. Hill 		if (res)
2205451b001bSSteven J. Hill 			goto fault;
2206451b001bSSteven J. Hill 		break;
2207451b001bSSteven J. Hill 
2208451b001bSSteven J. Hill 	case MIPS16e_sw_op:
2209451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
2210451b001bSSteven J. Hill 	case MIPS16e_i8_op:	/* actually - MIPS16e_swrasp_func */
2211451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 4))
2212451b001bSSteven J. Hill 			goto sigbus;
2213451b001bSSteven J. Hill 
2214451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2215451b001bSSteven J. Hill 		value = regs->regs[reg];
2216451b001bSSteven J. Hill 		StoreW(addr, value, res);
2217451b001bSSteven J. Hill 		if (res)
2218451b001bSSteven J. Hill 			goto fault;
2219451b001bSSteven J. Hill 		break;
2220451b001bSSteven J. Hill 
2221451b001bSSteven J. Hill 	case MIPS16e_sd_op:
2222451b001bSSteven J. Hill writeDW:
2223451b001bSSteven J. Hill #ifdef CONFIG_64BIT
2224451b001bSSteven J. Hill 		/*
2225451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
2226451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
2227451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
2228451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
2229451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
2230451b001bSSteven J. Hill 		 */
2231451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 8))
2232451b001bSSteven J. Hill 			goto sigbus;
2233451b001bSSteven J. Hill 
2234451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
2235451b001bSSteven J. Hill 		value = regs->regs[reg];
2236451b001bSSteven J. Hill 		StoreDW(addr, value, res);
2237451b001bSSteven J. Hill 		if (res)
2238451b001bSSteven J. Hill 			goto fault;
2239451b001bSSteven J. Hill 		break;
2240451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
2241451b001bSSteven J. Hill 
2242451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
2243451b001bSSteven J. Hill 		goto sigill;
2244451b001bSSteven J. Hill 
2245451b001bSSteven J. Hill 	default:
2246451b001bSSteven J. Hill 		/*
2247451b001bSSteven J. Hill 		 * Pheeee...  We encountered an yet unknown instruction or
2248451b001bSSteven J. Hill 		 * cache coherence problem.  Die sucker, die ...
2249451b001bSSteven J. Hill 		 */
2250451b001bSSteven J. Hill 		goto sigill;
2251451b001bSSteven J. Hill 	}
2252451b001bSSteven J. Hill 
2253451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
2254451b001bSSteven J. Hill 	unaligned_instructions++;
2255451b001bSSteven J. Hill #endif
2256451b001bSSteven J. Hill 
2257451b001bSSteven J. Hill 	return;
2258451b001bSSteven J. Hill 
2259451b001bSSteven J. Hill fault:
2260451b001bSSteven J. Hill 	/* roll back jump/branch */
2261451b001bSSteven J. Hill 	regs->cp0_epc = origpc;
2262451b001bSSteven J. Hill 	regs->regs[31] = orig31;
2263451b001bSSteven J. Hill 	/* Did we have an exception handler installed? */
2264451b001bSSteven J. Hill 	if (fixup_exception(regs))
2265451b001bSSteven J. Hill 		return;
2266451b001bSSteven J. Hill 
2267451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
2268451b001bSSteven J. Hill 	force_sig(SIGSEGV, current);
2269451b001bSSteven J. Hill 
2270451b001bSSteven J. Hill 	return;
2271451b001bSSteven J. Hill 
2272451b001bSSteven J. Hill sigbus:
2273451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
2274451b001bSSteven J. Hill 	force_sig(SIGBUS, current);
2275451b001bSSteven J. Hill 
2276451b001bSSteven J. Hill 	return;
2277451b001bSSteven J. Hill 
2278451b001bSSteven J. Hill sigill:
2279451b001bSSteven J. Hill 	die_if_kernel
2280451b001bSSteven J. Hill 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
2281451b001bSSteven J. Hill 	force_sig(SIGILL, current);
2282451b001bSSteven J. Hill }
2283fc192e50STony Wu 
22841da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
22851da177e4SLinus Torvalds {
2286c3fc5cd5SRalf Baechle 	enum ctx_state prev_state;
2287fe00f943SRalf Baechle 	unsigned int __user *pc;
22881da177e4SLinus Torvalds 	mm_segment_t seg;
22891da177e4SLinus Torvalds 
2290c3fc5cd5SRalf Baechle 	prev_state = exception_enter();
22917f788d2dSDeng-Cheng Zhu 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
2292a8b0ca17SPeter Zijlstra 			1, regs, regs->cp0_badvaddr);
22931da177e4SLinus Torvalds 	/*
22941da177e4SLinus Torvalds 	 * Did we catch a fault trying to load an instruction?
22951da177e4SLinus Torvalds 	 */
229634c2f668SLeonid Yegoshin 	if (regs->cp0_badvaddr == regs->cp0_epc)
22971da177e4SLinus Torvalds 		goto sigbus;
22981da177e4SLinus Torvalds 
2299293c5bd1SRalf Baechle 	if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
23001da177e4SLinus Torvalds 		goto sigbus;
23016312e0eeSAtsushi Nemoto 	if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
23026312e0eeSAtsushi Nemoto 		goto sigbus;
23031da177e4SLinus Torvalds 
23041da177e4SLinus Torvalds 	/*
23051da177e4SLinus Torvalds 	 * Do branch emulation only if we didn't forward the exception.
23061da177e4SLinus Torvalds 	 * This is all so but ugly ...
23071da177e4SLinus Torvalds 	 */
230834c2f668SLeonid Yegoshin 
230934c2f668SLeonid Yegoshin 	/*
231034c2f668SLeonid Yegoshin 	 * Are we running in microMIPS mode?
231134c2f668SLeonid Yegoshin 	 */
231234c2f668SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
231334c2f668SLeonid Yegoshin 		/*
231434c2f668SLeonid Yegoshin 		 * Did we catch a fault trying to load an instruction in
231534c2f668SLeonid Yegoshin 		 * 16-bit mode?
231634c2f668SLeonid Yegoshin 		 */
231734c2f668SLeonid Yegoshin 		if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
231834c2f668SLeonid Yegoshin 			goto sigbus;
231934c2f668SLeonid Yegoshin 		if (unaligned_action == UNALIGNED_ACTION_SHOW)
232034c2f668SLeonid Yegoshin 			show_registers(regs);
232134c2f668SLeonid Yegoshin 
232234c2f668SLeonid Yegoshin 		if (cpu_has_mmips) {
232334c2f668SLeonid Yegoshin 			seg = get_fs();
232434c2f668SLeonid Yegoshin 			if (!user_mode(regs))
232534c2f668SLeonid Yegoshin 				set_fs(KERNEL_DS);
232634c2f668SLeonid Yegoshin 			emulate_load_store_microMIPS(regs,
232734c2f668SLeonid Yegoshin 				(void __user *)regs->cp0_badvaddr);
232834c2f668SLeonid Yegoshin 			set_fs(seg);
232934c2f668SLeonid Yegoshin 
233034c2f668SLeonid Yegoshin 			return;
233134c2f668SLeonid Yegoshin 		}
233234c2f668SLeonid Yegoshin 
2333451b001bSSteven J. Hill 		if (cpu_has_mips16) {
2334451b001bSSteven J. Hill 			seg = get_fs();
2335451b001bSSteven J. Hill 			if (!user_mode(regs))
2336451b001bSSteven J. Hill 				set_fs(KERNEL_DS);
2337451b001bSSteven J. Hill 			emulate_load_store_MIPS16e(regs,
2338451b001bSSteven J. Hill 				(void __user *)regs->cp0_badvaddr);
2339451b001bSSteven J. Hill 			set_fs(seg);
2340451b001bSSteven J. Hill 
2341451b001bSSteven J. Hill 			return;
2342451b001bSSteven J. Hill 	}
2343451b001bSSteven J. Hill 
234434c2f668SLeonid Yegoshin 		goto sigbus;
234534c2f668SLeonid Yegoshin 	}
234634c2f668SLeonid Yegoshin 
234734c2f668SLeonid Yegoshin 	if (unaligned_action == UNALIGNED_ACTION_SHOW)
234834c2f668SLeonid Yegoshin 		show_registers(regs);
234934c2f668SLeonid Yegoshin 	pc = (unsigned int __user *)exception_epc(regs);
235034c2f668SLeonid Yegoshin 
23511da177e4SLinus Torvalds 	seg = get_fs();
23521da177e4SLinus Torvalds 	if (!user_mode(regs))
23531da177e4SLinus Torvalds 		set_fs(KERNEL_DS);
23547f18f151SRalf Baechle 	emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
23551da177e4SLinus Torvalds 	set_fs(seg);
23561da177e4SLinus Torvalds 
23571da177e4SLinus Torvalds 	return;
23581da177e4SLinus Torvalds 
23591da177e4SLinus Torvalds sigbus:
23601da177e4SLinus Torvalds 	die_if_kernel("Kernel unaligned instruction access", regs);
23611da177e4SLinus Torvalds 	force_sig(SIGBUS, current);
23621da177e4SLinus Torvalds 
23631da177e4SLinus Torvalds 	/*
23641da177e4SLinus Torvalds 	 * XXX On return from the signal handler we should advance the epc
23651da177e4SLinus Torvalds 	 */
2366c3fc5cd5SRalf Baechle 	exception_exit(prev_state);
23671da177e4SLinus Torvalds }
23686312e0eeSAtsushi Nemoto 
23696312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
23706312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
23716312e0eeSAtsushi Nemoto {
23726312e0eeSAtsushi Nemoto 	struct dentry *d;
23736312e0eeSAtsushi Nemoto 
23746312e0eeSAtsushi Nemoto 	if (!mips_debugfs_dir)
23756312e0eeSAtsushi Nemoto 		return -ENODEV;
23766312e0eeSAtsushi Nemoto 	d = debugfs_create_u32("unaligned_instructions", S_IRUGO,
23776312e0eeSAtsushi Nemoto 			       mips_debugfs_dir, &unaligned_instructions);
2378b517531cSZhaolei 	if (!d)
2379b517531cSZhaolei 		return -ENOMEM;
23806312e0eeSAtsushi Nemoto 	d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
23816312e0eeSAtsushi Nemoto 			       mips_debugfs_dir, &unaligned_action);
2382b517531cSZhaolei 	if (!d)
2383b517531cSZhaolei 		return -ENOMEM;
23846312e0eeSAtsushi Nemoto 	return 0;
23856312e0eeSAtsushi Nemoto }
23868d6b591cSRalf Baechle arch_initcall(debugfs_unaligned);
23876312e0eeSAtsushi Nemoto #endif
2388