xref: /linux/arch/mips/kernel/unaligned.c (revision 9d8e573683ca85e2bd3cade8b5c42e195e6390ad)
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.
10*9d8e5736SMarkos Chandras  * Copyright (C) 2014 Imagination Technologies Ltd.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * This file contains exception handler for address error exception with the
131da177e4SLinus Torvalds  * special capability to execute faulting instructions in software.  The
141da177e4SLinus Torvalds  * handler does not try to handle the case when the program counter points
151da177e4SLinus Torvalds  * to an address not aligned to a word boundary.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * Putting data to unaligned addresses is a bad practice even on Intel where
181da177e4SLinus Torvalds  * only the performance is affected.  Much worse is that such code is non-
191da177e4SLinus Torvalds  * portable.  Due to several programs that die on MIPS due to alignment
201da177e4SLinus Torvalds  * problems I decided to implement this handler anyway though I originally
211da177e4SLinus Torvalds  * didn't intend to do this at all for user code.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * For now I enable fixing of address errors by default to make life easier.
241da177e4SLinus Torvalds  * I however intend to disable this somewhen in the future when the alignment
251da177e4SLinus Torvalds  * problems with user programs have been fixed.	 For programmers this is the
261da177e4SLinus Torvalds  * right way to go.
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  * Fixing address errors is a per process option.  The option is inherited
291da177e4SLinus Torvalds  * across fork(2) and execve(2) calls.	If you really want to use the
301da177e4SLinus Torvalds  * option in your user programs - I discourage the use of the software
311da177e4SLinus Torvalds  * emulation strongly - use the following code in your userland stuff:
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * #include <sys/sysmips.h>
341da177e4SLinus Torvalds  *
351da177e4SLinus Torvalds  * ...
361da177e4SLinus Torvalds  * sysmips(MIPS_FIXADE, x);
371da177e4SLinus Torvalds  * ...
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds  * The argument x is 0 for disabling software emulation, enabled otherwise.
401da177e4SLinus Torvalds  *
411da177e4SLinus Torvalds  * Below a little program to play around with this feature.
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * #include <stdio.h>
441da177e4SLinus Torvalds  * #include <sys/sysmips.h>
451da177e4SLinus Torvalds  *
461da177e4SLinus Torvalds  * struct foo {
471da177e4SLinus Torvalds  *	   unsigned char bar[8];
481da177e4SLinus Torvalds  * };
491da177e4SLinus Torvalds  *
501da177e4SLinus Torvalds  * main(int argc, char *argv[])
511da177e4SLinus Torvalds  * {
521da177e4SLinus Torvalds  *	   struct foo x = {0, 1, 2, 3, 4, 5, 6, 7};
531da177e4SLinus Torvalds  *	   unsigned int *p = (unsigned int *) (x.bar + 3);
541da177e4SLinus Torvalds  *	   int i;
551da177e4SLinus Torvalds  *
561da177e4SLinus Torvalds  *	   if (argc > 1)
571da177e4SLinus Torvalds  *		   sysmips(MIPS_FIXADE, atoi(argv[1]));
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  *	   printf("*p = %08lx\n", *p);
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  *	   *p = 0xdeadface;
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  *	   for(i = 0; i <= 7; i++)
641da177e4SLinus Torvalds  *	   printf("%02x ", x.bar[i]);
651da177e4SLinus Torvalds  *	   printf("\n");
661da177e4SLinus Torvalds  * }
671da177e4SLinus Torvalds  *
681da177e4SLinus Torvalds  * Coprocessor loads are not supported; I think this case is unimportant
691da177e4SLinus Torvalds  * in the practice.
701da177e4SLinus Torvalds  *
711da177e4SLinus Torvalds  * TODO: Handle ndc (attempted store to doubleword in uncached memory)
721da177e4SLinus Torvalds  *	 exception for the R6000.
731da177e4SLinus Torvalds  *	 A store crossing a page boundary might be executed only partially.
741da177e4SLinus Torvalds  *	 Undo the partial store in this case.
751da177e4SLinus Torvalds  */
76c3fc5cd5SRalf Baechle #include <linux/context_tracking.h>
771da177e4SLinus Torvalds #include <linux/mm.h>
781da177e4SLinus Torvalds #include <linux/signal.h>
791da177e4SLinus Torvalds #include <linux/smp.h>
80e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
816312e0eeSAtsushi Nemoto #include <linux/debugfs.h>
827f788d2dSDeng-Cheng Zhu #include <linux/perf_event.h>
837f788d2dSDeng-Cheng Zhu 
841da177e4SLinus Torvalds #include <asm/asm.h>
851da177e4SLinus Torvalds #include <asm/branch.h>
861da177e4SLinus Torvalds #include <asm/byteorder.h>
8769f3a7deSRalf Baechle #include <asm/cop2.h>
88102cedc3SLeonid Yegoshin #include <asm/fpu.h>
89102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h>
901da177e4SLinus Torvalds #include <asm/inst.h>
911da177e4SLinus Torvalds #include <asm/uaccess.h>
9234c2f668SLeonid Yegoshin #include <asm/fpu.h>
9334c2f668SLeonid Yegoshin #include <asm/fpu_emulator.h>
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds #define STR(x)	__STR(x)
961da177e4SLinus Torvalds #define __STR(x)  #x
971da177e4SLinus Torvalds 
986312e0eeSAtsushi Nemoto enum {
996312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_QUIET,
1006312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SIGNAL,
1016312e0eeSAtsushi Nemoto 	UNALIGNED_ACTION_SHOW,
1026312e0eeSAtsushi Nemoto };
1036312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
1046312e0eeSAtsushi Nemoto static u32 unaligned_instructions;
1056312e0eeSAtsushi Nemoto static u32 unaligned_action;
1066312e0eeSAtsushi Nemoto #else
1076312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET
1081da177e4SLinus Torvalds #endif
1096312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs);
1101da177e4SLinus Torvalds 
11134c2f668SLeonid Yegoshin #ifdef __BIG_ENDIAN
11234c2f668SLeonid Yegoshin #define     LoadHW(addr, value, res)  \
11334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (".set\tnoat\n"        \
114*9d8e5736SMarkos Chandras 			"1:\t"user_lb("%0", "0(%2)")"\n"    \
115*9d8e5736SMarkos Chandras 			"2:\t"user_lbu("$1", "1(%2)")"\n\t" \
11634c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
11734c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
11834c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
11934c2f668SLeonid Yegoshin 			"3:\t.set\tat\n\t"                  \
12034c2f668SLeonid Yegoshin 			".insn\n\t"                         \
12134c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
12234c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
12334c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
12434c2f668SLeonid Yegoshin 			".previous\n\t"                     \
12534c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
12634c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
12734c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
12834c2f668SLeonid Yegoshin 			".previous"                         \
12934c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
13034c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
13134c2f668SLeonid Yegoshin 
13234c2f668SLeonid Yegoshin #define     LoadW(addr, value, res)   \
13334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
134*9d8e5736SMarkos Chandras 			"1:\t"user_lwl("%0", "(%2)")"\n"    \
135*9d8e5736SMarkos Chandras 			"2:\t"user_lwr("%0", "3(%2)")"\n\t" \
13634c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
13734c2f668SLeonid Yegoshin 			"3:\n\t"                            \
13834c2f668SLeonid Yegoshin 			".insn\n\t"                         \
13934c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
14034c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
14134c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
14234c2f668SLeonid Yegoshin 			".previous\n\t"                     \
14334c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
14434c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
14534c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
14634c2f668SLeonid Yegoshin 			".previous"                         \
14734c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
14834c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
14934c2f668SLeonid Yegoshin 
15034c2f668SLeonid Yegoshin #define     LoadHWU(addr, value, res) \
15134c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
15234c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
153*9d8e5736SMarkos Chandras 			"1:\t"user_lbu("%0", "0(%2)")"\n"   \
154*9d8e5736SMarkos Chandras 			"2:\t"user_lbu("$1", "1(%2)")"\n\t" \
15534c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
15634c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
15734c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
15834c2f668SLeonid Yegoshin 			"3:\n\t"                            \
15934c2f668SLeonid Yegoshin 			".insn\n\t"                         \
16034c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
16134c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
16234c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
16334c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
16434c2f668SLeonid Yegoshin 			".previous\n\t"                     \
16534c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
16634c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
16734c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
16834c2f668SLeonid Yegoshin 			".previous"                         \
16934c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
17034c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
17134c2f668SLeonid Yegoshin 
17234c2f668SLeonid Yegoshin #define     LoadWU(addr, value, res)  \
17334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
174*9d8e5736SMarkos Chandras 			"1:\t"user_lwl("%0", "(%2)")"\n"    \
175*9d8e5736SMarkos Chandras 			"2:\t"user_lwr("%0", "3(%2)")"\n\t" \
17634c2f668SLeonid Yegoshin 			"dsll\t%0, %0, 32\n\t"              \
17734c2f668SLeonid Yegoshin 			"dsrl\t%0, %0, 32\n\t"              \
17834c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
17934c2f668SLeonid Yegoshin 			"3:\n\t"                            \
18034c2f668SLeonid Yegoshin 			".insn\n\t"                         \
18134c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
18234c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
18334c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
18434c2f668SLeonid Yegoshin 			".previous\n\t"                     \
18534c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
18634c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
18734c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
18834c2f668SLeonid Yegoshin 			".previous"                         \
18934c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
19034c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
19134c2f668SLeonid Yegoshin 
19234c2f668SLeonid Yegoshin #define     LoadDW(addr, value, res)  \
19334c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
19434c2f668SLeonid Yegoshin 			"1:\tldl\t%0, (%2)\n"               \
19534c2f668SLeonid Yegoshin 			"2:\tldr\t%0, 7(%2)\n\t"            \
19634c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
19734c2f668SLeonid Yegoshin 			"3:\n\t"                            \
19834c2f668SLeonid Yegoshin 			".insn\n\t"                         \
19934c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
20034c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
20134c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
20234c2f668SLeonid Yegoshin 			".previous\n\t"                     \
20334c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
20434c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
20534c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
20634c2f668SLeonid Yegoshin 			".previous"                         \
20734c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
20834c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
20934c2f668SLeonid Yegoshin 
21034c2f668SLeonid Yegoshin #define     StoreHW(addr, value, res) \
21134c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
21234c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
213*9d8e5736SMarkos Chandras 			"1:\t"user_sb("%1", "1(%2)")"\n"    \
21434c2f668SLeonid Yegoshin 			"srl\t$1, %1, 0x8\n"                \
215*9d8e5736SMarkos Chandras 			"2:\t"user_sb("$1", "0(%2)")"\n"    \
21634c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
21734c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
21834c2f668SLeonid Yegoshin 			"3:\n\t"                            \
21934c2f668SLeonid Yegoshin 			".insn\n\t"                         \
22034c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
22134c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
22234c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
22334c2f668SLeonid Yegoshin 			".previous\n\t"                     \
22434c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
22534c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
22634c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
22734c2f668SLeonid Yegoshin 			".previous"                         \
22834c2f668SLeonid Yegoshin 			: "=r" (res)                        \
22934c2f668SLeonid Yegoshin 			: "r" (value), "r" (addr), "i" (-EFAULT));
23034c2f668SLeonid Yegoshin 
23134c2f668SLeonid Yegoshin #define     StoreW(addr, value, res)  \
23234c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
233*9d8e5736SMarkos Chandras 			"1:\t"user_swl("%1", "(%2)")"\n"    \
234*9d8e5736SMarkos Chandras 			"2:\t"user_swr("%1", "3(%2)")"\n\t" \
23534c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
23634c2f668SLeonid Yegoshin 			"3:\n\t"                            \
23734c2f668SLeonid Yegoshin 			".insn\n\t"                         \
23834c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
23934c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
24034c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
24134c2f668SLeonid Yegoshin 			".previous\n\t"                     \
24234c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
24334c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
24434c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
24534c2f668SLeonid Yegoshin 			".previous"                         \
24634c2f668SLeonid Yegoshin 		: "=r" (res)                                \
24734c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
24834c2f668SLeonid Yegoshin 
24934c2f668SLeonid Yegoshin #define     StoreDW(addr, value, res) \
25034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
25134c2f668SLeonid Yegoshin 			"1:\tsdl\t%1,(%2)\n"                \
25234c2f668SLeonid Yegoshin 			"2:\tsdr\t%1, 7(%2)\n\t"            \
25334c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
25434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
25534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
25634c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
25734c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
25834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
25934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
26034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
26134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
26234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
26334c2f668SLeonid Yegoshin 			".previous"                         \
26434c2f668SLeonid Yegoshin 		: "=r" (res)                                \
26534c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
26634c2f668SLeonid Yegoshin #endif
26734c2f668SLeonid Yegoshin 
26834c2f668SLeonid Yegoshin #ifdef __LITTLE_ENDIAN
26934c2f668SLeonid Yegoshin #define     LoadHW(addr, value, res)  \
27034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (".set\tnoat\n"        \
271*9d8e5736SMarkos Chandras 			"1:\t"user_lb("%0", "1(%2)")"\n"    \
272*9d8e5736SMarkos Chandras 			"2:\t"user_lbu("$1", "0(%2)")"\n\t" \
27334c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
27434c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
27534c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
27634c2f668SLeonid Yegoshin 			"3:\t.set\tat\n\t"                  \
27734c2f668SLeonid Yegoshin 			".insn\n\t"                         \
27834c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
27934c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
28034c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
28134c2f668SLeonid Yegoshin 			".previous\n\t"                     \
28234c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
28334c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
28434c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
28534c2f668SLeonid Yegoshin 			".previous"                         \
28634c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
28734c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
28834c2f668SLeonid Yegoshin 
28934c2f668SLeonid Yegoshin #define     LoadW(addr, value, res)   \
29034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
291*9d8e5736SMarkos Chandras 			"1:\t"user_lwl("%0", "3(%2)")"\n"   \
292*9d8e5736SMarkos Chandras 			"2:\t"user_lwr("%0", "(%2)")"\n\t"  \
29334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
29434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
29534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
29634c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
29734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
29834c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
29934c2f668SLeonid Yegoshin 			".previous\n\t"                     \
30034c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
30134c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
30234c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
30334c2f668SLeonid Yegoshin 			".previous"                         \
30434c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
30534c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
30634c2f668SLeonid Yegoshin 
30734c2f668SLeonid Yegoshin #define     LoadHWU(addr, value, res) \
30834c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
30934c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
310*9d8e5736SMarkos Chandras 			"1:\t"user_lbu("%0", "1(%2)")"\n"   \
311*9d8e5736SMarkos Chandras 			"2:\t"user_lbu("$1", "0(%2)")"\n\t" \
31234c2f668SLeonid Yegoshin 			"sll\t%0, 0x8\n\t"                  \
31334c2f668SLeonid Yegoshin 			"or\t%0, $1\n\t"                    \
31434c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
31534c2f668SLeonid Yegoshin 			"3:\n\t"                            \
31634c2f668SLeonid Yegoshin 			".insn\n\t"                         \
31734c2f668SLeonid Yegoshin 			".set\tat\n\t"                      \
31834c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
31934c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
32034c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
32134c2f668SLeonid Yegoshin 			".previous\n\t"                     \
32234c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
32334c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
32434c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
32534c2f668SLeonid Yegoshin 			".previous"                         \
32634c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
32734c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
32834c2f668SLeonid Yegoshin 
32934c2f668SLeonid Yegoshin #define     LoadWU(addr, value, res)  \
33034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
331*9d8e5736SMarkos Chandras 			"1:\t"user_lwl("%0", "3(%2)")"\n"   \
332*9d8e5736SMarkos Chandras 			"2:\t"user_lwr("%0", "(%2)")"\n\t"  \
33334c2f668SLeonid Yegoshin 			"dsll\t%0, %0, 32\n\t"              \
33434c2f668SLeonid Yegoshin 			"dsrl\t%0, %0, 32\n\t"              \
33534c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
33634c2f668SLeonid Yegoshin 			"3:\n\t"                            \
33734c2f668SLeonid Yegoshin 			".insn\n\t"                         \
33834c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
33934c2f668SLeonid Yegoshin 			"4:\tli\t%1, %3\n\t"                \
34034c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
34134c2f668SLeonid Yegoshin 			".previous\n\t"                     \
34234c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
34334c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
34434c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
34534c2f668SLeonid Yegoshin 			".previous"                         \
34634c2f668SLeonid Yegoshin 			: "=&r" (value), "=r" (res)         \
34734c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
34834c2f668SLeonid Yegoshin 
34934c2f668SLeonid Yegoshin #define     LoadDW(addr, value, res)  \
35034c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
35134c2f668SLeonid Yegoshin 			"1:\tldl\t%0, 7(%2)\n"              \
35234c2f668SLeonid Yegoshin 			"2:\tldr\t%0, (%2)\n\t"             \
35334c2f668SLeonid Yegoshin 			"li\t%1, 0\n"                       \
35434c2f668SLeonid Yegoshin 			"3:\n\t"                            \
35534c2f668SLeonid Yegoshin 			".insn\n\t"                         \
35634c2f668SLeonid Yegoshin 			"\t.section\t.fixup,\"ax\"\n\t"     \
35734c2f668SLeonid Yegoshin 			"4:\tli\t%1, %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" (value), "=r" (res)         \
36534c2f668SLeonid Yegoshin 			: "r" (addr), "i" (-EFAULT));
36634c2f668SLeonid Yegoshin 
36734c2f668SLeonid Yegoshin #define     StoreHW(addr, value, res) \
36834c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
36934c2f668SLeonid Yegoshin 			".set\tnoat\n"                      \
370*9d8e5736SMarkos Chandras 			"1:\t"user_sb("%1", "0(%2)")"\n"    \
37134c2f668SLeonid Yegoshin 			"srl\t$1,%1, 0x8\n"                 \
372*9d8e5736SMarkos Chandras 			"2:\t"user_sb("$1", "1(%2)")"\n"    \
37334c2f668SLeonid Yegoshin 			".set\tat\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)                        \
38634c2f668SLeonid Yegoshin 			: "r" (value), "r" (addr), "i" (-EFAULT));
38734c2f668SLeonid Yegoshin 
38834c2f668SLeonid Yegoshin #define     StoreW(addr, value, res)  \
38934c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
390*9d8e5736SMarkos Chandras 			"1:\t"user_swl("%1", "3(%2)")"\n"   \
391*9d8e5736SMarkos Chandras 			"2:\t"user_swr("%1", "(%2)")"\n\t"  \
39234c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
39334c2f668SLeonid Yegoshin 			"3:\n\t"                            \
39434c2f668SLeonid Yegoshin 			".insn\n\t"                         \
39534c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
39634c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
39734c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
39834c2f668SLeonid Yegoshin 			".previous\n\t"                     \
39934c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
40034c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
40134c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
40234c2f668SLeonid Yegoshin 			".previous"                         \
40334c2f668SLeonid Yegoshin 		: "=r" (res)                                \
40434c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
40534c2f668SLeonid Yegoshin 
40634c2f668SLeonid Yegoshin #define     StoreDW(addr, value, res) \
40734c2f668SLeonid Yegoshin 		__asm__ __volatile__ (                      \
40834c2f668SLeonid Yegoshin 			"1:\tsdl\t%1, 7(%2)\n"              \
40934c2f668SLeonid Yegoshin 			"2:\tsdr\t%1, (%2)\n\t"             \
41034c2f668SLeonid Yegoshin 			"li\t%0, 0\n"                       \
41134c2f668SLeonid Yegoshin 			"3:\n\t"                            \
41234c2f668SLeonid Yegoshin 			".insn\n\t"                         \
41334c2f668SLeonid Yegoshin 			".section\t.fixup,\"ax\"\n\t"       \
41434c2f668SLeonid Yegoshin 			"4:\tli\t%0, %3\n\t"                \
41534c2f668SLeonid Yegoshin 			"j\t3b\n\t"                         \
41634c2f668SLeonid Yegoshin 			".previous\n\t"                     \
41734c2f668SLeonid Yegoshin 			".section\t__ex_table,\"a\"\n\t"    \
41834c2f668SLeonid Yegoshin 			STR(PTR)"\t1b, 4b\n\t"              \
41934c2f668SLeonid Yegoshin 			STR(PTR)"\t2b, 4b\n\t"              \
42034c2f668SLeonid Yegoshin 			".previous"                         \
42134c2f668SLeonid Yegoshin 		: "=r" (res)                                \
42234c2f668SLeonid Yegoshin 		: "r" (value), "r" (addr), "i" (-EFAULT));
42334c2f668SLeonid Yegoshin #endif
42434c2f668SLeonid Yegoshin 
4257f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs,
4267f18f151SRalf Baechle 	void __user *addr, unsigned int __user *pc)
4271da177e4SLinus Torvalds {
4281da177e4SLinus Torvalds 	union mips_instruction insn;
4291da177e4SLinus Torvalds 	unsigned long value;
4301da177e4SLinus Torvalds 	unsigned int res;
43134c2f668SLeonid Yegoshin 	unsigned long origpc;
43234c2f668SLeonid Yegoshin 	unsigned long orig31;
433102cedc3SLeonid Yegoshin 	void __user *fault_addr = NULL;
4341da177e4SLinus Torvalds 
43534c2f668SLeonid Yegoshin 	origpc = (unsigned long)pc;
43634c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
43734c2f668SLeonid Yegoshin 
438a8b0ca17SPeter Zijlstra 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
4397f788d2dSDeng-Cheng Zhu 
4401da177e4SLinus Torvalds 	/*
4411da177e4SLinus Torvalds 	 * This load never faults.
4421da177e4SLinus Torvalds 	 */
443fe00f943SRalf Baechle 	__get_user(insn.word, pc);
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	switch (insn.i_format.opcode) {
4461da177e4SLinus Torvalds 		/*
4471da177e4SLinus Torvalds 		 * These are instructions that a compiler doesn't generate.  We
4481da177e4SLinus Torvalds 		 * can assume therefore that the code is MIPS-aware and
4491da177e4SLinus Torvalds 		 * really buggy.  Emulating these instructions would break the
4501da177e4SLinus Torvalds 		 * semantics anyway.
4511da177e4SLinus Torvalds 		 */
4521da177e4SLinus Torvalds 	case ll_op:
4531da177e4SLinus Torvalds 	case lld_op:
4541da177e4SLinus Torvalds 	case sc_op:
4551da177e4SLinus Torvalds 	case scd_op:
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 		/*
4581da177e4SLinus Torvalds 		 * For these instructions the only way to create an address
4591da177e4SLinus Torvalds 		 * error is an attempted access to kernel/supervisor address
4601da177e4SLinus Torvalds 		 * space.
4611da177e4SLinus Torvalds 		 */
4621da177e4SLinus Torvalds 	case ldl_op:
4631da177e4SLinus Torvalds 	case ldr_op:
4641da177e4SLinus Torvalds 	case lwl_op:
4651da177e4SLinus Torvalds 	case lwr_op:
4661da177e4SLinus Torvalds 	case sdl_op:
4671da177e4SLinus Torvalds 	case sdr_op:
4681da177e4SLinus Torvalds 	case swl_op:
4691da177e4SLinus Torvalds 	case swr_op:
4701da177e4SLinus Torvalds 	case lb_op:
4711da177e4SLinus Torvalds 	case lbu_op:
4721da177e4SLinus Torvalds 	case sb_op:
4731da177e4SLinus Torvalds 		goto sigbus;
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 		/*
47634c2f668SLeonid Yegoshin 		 * The remaining opcodes are the ones that are really of
47734c2f668SLeonid Yegoshin 		 * interest.
4781da177e4SLinus Torvalds 		 */
4791da177e4SLinus Torvalds 	case lh_op:
4801da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 2))
4811da177e4SLinus Torvalds 			goto sigbus;
4821da177e4SLinus Torvalds 
48334c2f668SLeonid Yegoshin 		LoadHW(addr, value, res);
4841da177e4SLinus Torvalds 		if (res)
4851da177e4SLinus Torvalds 			goto fault;
4867f18f151SRalf Baechle 		compute_return_epc(regs);
4877f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
4881da177e4SLinus Torvalds 		break;
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 	case lw_op:
4911da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 4))
4921da177e4SLinus Torvalds 			goto sigbus;
4931da177e4SLinus Torvalds 
49434c2f668SLeonid Yegoshin 		LoadW(addr, value, res);
4951da177e4SLinus Torvalds 		if (res)
4961da177e4SLinus Torvalds 			goto fault;
4977f18f151SRalf Baechle 		compute_return_epc(regs);
4987f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
4991da177e4SLinus Torvalds 		break;
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 	case lhu_op:
5021da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 2))
5031da177e4SLinus Torvalds 			goto sigbus;
5041da177e4SLinus Torvalds 
50534c2f668SLeonid Yegoshin 		LoadHWU(addr, value, res);
5061da177e4SLinus Torvalds 		if (res)
5071da177e4SLinus Torvalds 			goto fault;
5087f18f151SRalf Baechle 		compute_return_epc(regs);
5097f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
5101da177e4SLinus Torvalds 		break;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 	case lwu_op:
513875d43e7SRalf Baechle #ifdef CONFIG_64BIT
5141da177e4SLinus Torvalds 		/*
5151da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
5161da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
5171da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
5181da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
5191da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
5201da177e4SLinus Torvalds 		 */
5211da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 4))
5221da177e4SLinus Torvalds 			goto sigbus;
5231da177e4SLinus Torvalds 
52434c2f668SLeonid Yegoshin 		LoadWU(addr, value, res);
5251da177e4SLinus Torvalds 		if (res)
5261da177e4SLinus Torvalds 			goto fault;
5277f18f151SRalf Baechle 		compute_return_epc(regs);
5287f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
5291da177e4SLinus Torvalds 		break;
530875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
5331da177e4SLinus Torvalds 		goto sigill;
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	case ld_op:
536875d43e7SRalf Baechle #ifdef CONFIG_64BIT
5371da177e4SLinus Torvalds 		/*
5381da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
5391da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
5401da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
5411da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
5421da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
5431da177e4SLinus Torvalds 		 */
5441da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, addr, 8))
5451da177e4SLinus Torvalds 			goto sigbus;
5461da177e4SLinus Torvalds 
54734c2f668SLeonid Yegoshin 		LoadDW(addr, value, res);
5481da177e4SLinus Torvalds 		if (res)
5491da177e4SLinus Torvalds 			goto fault;
5507f18f151SRalf Baechle 		compute_return_epc(regs);
5517f18f151SRalf Baechle 		regs->regs[insn.i_format.rt] = value;
5521da177e4SLinus Torvalds 		break;
553875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
5541da177e4SLinus Torvalds 
5551da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
5561da177e4SLinus Torvalds 		goto sigill;
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 	case sh_op:
5591da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 2))
5601da177e4SLinus Torvalds 			goto sigbus;
5611da177e4SLinus Torvalds 
56234c2f668SLeonid Yegoshin 		compute_return_epc(regs);
5631da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
56434c2f668SLeonid Yegoshin 		StoreHW(addr, value, res);
5651da177e4SLinus Torvalds 		if (res)
5661da177e4SLinus Torvalds 			goto fault;
5671da177e4SLinus Torvalds 		break;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	case sw_op:
5701da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 4))
5711da177e4SLinus Torvalds 			goto sigbus;
5721da177e4SLinus Torvalds 
57334c2f668SLeonid Yegoshin 		compute_return_epc(regs);
5741da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
57534c2f668SLeonid Yegoshin 		StoreW(addr, value, res);
5761da177e4SLinus Torvalds 		if (res)
5771da177e4SLinus Torvalds 			goto fault;
5781da177e4SLinus Torvalds 		break;
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 	case sd_op:
581875d43e7SRalf Baechle #ifdef CONFIG_64BIT
5821da177e4SLinus Torvalds 		/*
5831da177e4SLinus Torvalds 		 * A 32-bit kernel might be running on a 64-bit processor.  But
5841da177e4SLinus Torvalds 		 * if we're on a 32-bit processor and an i-cache incoherency
5851da177e4SLinus Torvalds 		 * or race makes us see a 64-bit instruction here the sdl/sdr
5861da177e4SLinus Torvalds 		 * would blow up, so for now we don't handle unaligned 64-bit
5871da177e4SLinus Torvalds 		 * instructions on 32-bit kernels.
5881da177e4SLinus Torvalds 		 */
5891da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, addr, 8))
5901da177e4SLinus Torvalds 			goto sigbus;
5911da177e4SLinus Torvalds 
59234c2f668SLeonid Yegoshin 		compute_return_epc(regs);
5931da177e4SLinus Torvalds 		value = regs->regs[insn.i_format.rt];
59434c2f668SLeonid Yegoshin 		StoreDW(addr, value, res);
5951da177e4SLinus Torvalds 		if (res)
5961da177e4SLinus Torvalds 			goto fault;
5971da177e4SLinus Torvalds 		break;
598875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 		/* Cannot handle 64-bit instructions in 32-bit kernel */
6011da177e4SLinus Torvalds 		goto sigill;
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 	case lwc1_op:
6041da177e4SLinus Torvalds 	case ldc1_op:
6051da177e4SLinus Torvalds 	case swc1_op:
6061da177e4SLinus Torvalds 	case sdc1_op:
607102cedc3SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
608102cedc3SLeonid Yegoshin 		BUG_ON(!used_math());
609102cedc3SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
610102cedc3SLeonid Yegoshin 
611102cedc3SLeonid Yegoshin 		lose_fpu(1);	/* Save FPU state for the emulator. */
612102cedc3SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
613102cedc3SLeonid Yegoshin 					       &fault_addr);
614102cedc3SLeonid Yegoshin 		own_fpu(1);	/* Restore FPU state. */
615102cedc3SLeonid Yegoshin 
616102cedc3SLeonid Yegoshin 		/* Signal if something went wrong. */
617102cedc3SLeonid Yegoshin 		process_fpemu_return(res, fault_addr);
618102cedc3SLeonid Yegoshin 
619102cedc3SLeonid Yegoshin 		if (res == 0)
620102cedc3SLeonid Yegoshin 			break;
621102cedc3SLeonid Yegoshin 		return;
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds 	/*
62469f3a7deSRalf Baechle 	 * COP2 is available to implementor for application specific use.
62569f3a7deSRalf Baechle 	 * It's up to applications to register a notifier chain and do
62669f3a7deSRalf Baechle 	 * whatever they have to do, including possible sending of signals.
6271da177e4SLinus Torvalds 	 */
62869f3a7deSRalf Baechle 	case lwc2_op:
62969f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
63069f3a7deSRalf Baechle 		break;
63169f3a7deSRalf Baechle 
63269f3a7deSRalf Baechle 	case ldc2_op:
63369f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
63469f3a7deSRalf Baechle 		break;
63569f3a7deSRalf Baechle 
63669f3a7deSRalf Baechle 	case swc2_op:
63769f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
63869f3a7deSRalf Baechle 		break;
63969f3a7deSRalf Baechle 
64069f3a7deSRalf Baechle 	case sdc2_op:
64169f3a7deSRalf Baechle 		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
64269f3a7deSRalf Baechle 		break;
64369f3a7deSRalf Baechle 
6441da177e4SLinus Torvalds 	default:
6451da177e4SLinus Torvalds 		/*
6461da177e4SLinus Torvalds 		 * Pheeee...  We encountered an yet unknown instruction or
6471da177e4SLinus Torvalds 		 * cache coherence problem.  Die sucker, die ...
6481da177e4SLinus Torvalds 		 */
6491da177e4SLinus Torvalds 		goto sigill;
6501da177e4SLinus Torvalds 	}
6511da177e4SLinus Torvalds 
6526312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
6531da177e4SLinus Torvalds 	unaligned_instructions++;
6541da177e4SLinus Torvalds #endif
6551da177e4SLinus Torvalds 
6567f18f151SRalf Baechle 	return;
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds fault:
65934c2f668SLeonid Yegoshin 	/* roll back jump/branch */
66034c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
66134c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
6621da177e4SLinus Torvalds 	/* Did we have an exception handler installed? */
6631da177e4SLinus Torvalds 	if (fixup_exception(regs))
6647f18f151SRalf Baechle 		return;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
667a6d5ff04SDavid Daney 	force_sig(SIGSEGV, current);
6681da177e4SLinus Torvalds 
6697f18f151SRalf Baechle 	return;
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds sigbus:
6721da177e4SLinus Torvalds 	die_if_kernel("Unhandled kernel unaligned access", regs);
673a6d5ff04SDavid Daney 	force_sig(SIGBUS, current);
6741da177e4SLinus Torvalds 
6757f18f151SRalf Baechle 	return;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds sigill:
67834c2f668SLeonid Yegoshin 	die_if_kernel
67934c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
68034c2f668SLeonid Yegoshin 	force_sig(SIGILL, current);
68134c2f668SLeonid Yegoshin }
68234c2f668SLeonid Yegoshin 
68334c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
68434c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
68534c2f668SLeonid Yegoshin 
68634c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
68734c2f668SLeonid Yegoshin const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
68834c2f668SLeonid Yegoshin 
68974338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
69074338805SDavid Daney 					 void __user *addr)
69134c2f668SLeonid Yegoshin {
69234c2f668SLeonid Yegoshin 	unsigned long value;
69334c2f668SLeonid Yegoshin 	unsigned int res;
69434c2f668SLeonid Yegoshin 	int i;
69534c2f668SLeonid Yegoshin 	unsigned int reg = 0, rvar;
69634c2f668SLeonid Yegoshin 	unsigned long orig31;
69734c2f668SLeonid Yegoshin 	u16 __user *pc16;
69834c2f668SLeonid Yegoshin 	u16 halfword;
69934c2f668SLeonid Yegoshin 	unsigned int word;
70034c2f668SLeonid Yegoshin 	unsigned long origpc, contpc;
70134c2f668SLeonid Yegoshin 	union mips_instruction insn;
70234c2f668SLeonid Yegoshin 	struct mm_decoded_insn mminsn;
70334c2f668SLeonid Yegoshin 	void __user *fault_addr = NULL;
70434c2f668SLeonid Yegoshin 
70534c2f668SLeonid Yegoshin 	origpc = regs->cp0_epc;
70634c2f668SLeonid Yegoshin 	orig31 = regs->regs[31];
70734c2f668SLeonid Yegoshin 
70834c2f668SLeonid Yegoshin 	mminsn.micro_mips_mode = 1;
70934c2f668SLeonid Yegoshin 
71034c2f668SLeonid Yegoshin 	/*
71134c2f668SLeonid Yegoshin 	 * This load never faults.
71234c2f668SLeonid Yegoshin 	 */
71334c2f668SLeonid Yegoshin 	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
71434c2f668SLeonid Yegoshin 	__get_user(halfword, pc16);
71534c2f668SLeonid Yegoshin 	pc16++;
71634c2f668SLeonid Yegoshin 	contpc = regs->cp0_epc + 2;
71734c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
71834c2f668SLeonid Yegoshin 	mminsn.pc_inc = 2;
71934c2f668SLeonid Yegoshin 
72034c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
72134c2f668SLeonid Yegoshin 		__get_user(halfword, pc16);
72234c2f668SLeonid Yegoshin 		pc16++;
72334c2f668SLeonid Yegoshin 		contpc = regs->cp0_epc + 4;
72434c2f668SLeonid Yegoshin 		mminsn.pc_inc = 4;
72534c2f668SLeonid Yegoshin 		word |= halfword;
72634c2f668SLeonid Yegoshin 	}
72734c2f668SLeonid Yegoshin 	mminsn.insn = word;
72834c2f668SLeonid Yegoshin 
72934c2f668SLeonid Yegoshin 	if (get_user(halfword, pc16))
73034c2f668SLeonid Yegoshin 		goto fault;
73134c2f668SLeonid Yegoshin 	mminsn.next_pc_inc = 2;
73234c2f668SLeonid Yegoshin 	word = ((unsigned int)halfword << 16);
73334c2f668SLeonid Yegoshin 
73434c2f668SLeonid Yegoshin 	if (!mm_insn_16bit(halfword)) {
73534c2f668SLeonid Yegoshin 		pc16++;
73634c2f668SLeonid Yegoshin 		if (get_user(halfword, pc16))
73734c2f668SLeonid Yegoshin 			goto fault;
73834c2f668SLeonid Yegoshin 		mminsn.next_pc_inc = 4;
73934c2f668SLeonid Yegoshin 		word |= halfword;
74034c2f668SLeonid Yegoshin 	}
74134c2f668SLeonid Yegoshin 	mminsn.next_insn = word;
74234c2f668SLeonid Yegoshin 
74334c2f668SLeonid Yegoshin 	insn = (union mips_instruction)(mminsn.insn);
74434c2f668SLeonid Yegoshin 	if (mm_isBranchInstr(regs, mminsn, &contpc))
74534c2f668SLeonid Yegoshin 		insn = (union mips_instruction)(mminsn.next_insn);
74634c2f668SLeonid Yegoshin 
74734c2f668SLeonid Yegoshin 	/*  Parse instruction to find what to do */
74834c2f668SLeonid Yegoshin 
74934c2f668SLeonid Yegoshin 	switch (insn.mm_i_format.opcode) {
75034c2f668SLeonid Yegoshin 
75134c2f668SLeonid Yegoshin 	case mm_pool32a_op:
75234c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
75334c2f668SLeonid Yegoshin 		case mm_lwxs_op:
75434c2f668SLeonid Yegoshin 			reg = insn.mm_x_format.rd;
75534c2f668SLeonid Yegoshin 			goto loadW;
75634c2f668SLeonid Yegoshin 		}
75734c2f668SLeonid Yegoshin 
75834c2f668SLeonid Yegoshin 		goto sigbus;
75934c2f668SLeonid Yegoshin 
76034c2f668SLeonid Yegoshin 	case mm_pool32b_op:
76134c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
76234c2f668SLeonid Yegoshin 		case mm_lwp_func:
76334c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
76434c2f668SLeonid Yegoshin 			if (reg == 31)
76534c2f668SLeonid Yegoshin 				goto sigbus;
76634c2f668SLeonid Yegoshin 
76734c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 8))
76834c2f668SLeonid Yegoshin 				goto sigbus;
76934c2f668SLeonid Yegoshin 
77034c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
77134c2f668SLeonid Yegoshin 			if (res)
77234c2f668SLeonid Yegoshin 				goto fault;
77334c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
77434c2f668SLeonid Yegoshin 			addr += 4;
77534c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
77634c2f668SLeonid Yegoshin 			if (res)
77734c2f668SLeonid Yegoshin 				goto fault;
77834c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
77934c2f668SLeonid Yegoshin 			goto success;
78034c2f668SLeonid Yegoshin 
78134c2f668SLeonid Yegoshin 		case mm_swp_func:
78234c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
78334c2f668SLeonid Yegoshin 			if (reg == 31)
78434c2f668SLeonid Yegoshin 				goto sigbus;
78534c2f668SLeonid Yegoshin 
78634c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 8))
78734c2f668SLeonid Yegoshin 				goto sigbus;
78834c2f668SLeonid Yegoshin 
78934c2f668SLeonid Yegoshin 			value = regs->regs[reg];
79034c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
79134c2f668SLeonid Yegoshin 			if (res)
79234c2f668SLeonid Yegoshin 				goto fault;
79334c2f668SLeonid Yegoshin 			addr += 4;
79434c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
79534c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
79634c2f668SLeonid Yegoshin 			if (res)
79734c2f668SLeonid Yegoshin 				goto fault;
79834c2f668SLeonid Yegoshin 			goto success;
79934c2f668SLeonid Yegoshin 
80034c2f668SLeonid Yegoshin 		case mm_ldp_func:
80134c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
80234c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
80334c2f668SLeonid Yegoshin 			if (reg == 31)
80434c2f668SLeonid Yegoshin 				goto sigbus;
80534c2f668SLeonid Yegoshin 
80634c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 16))
80734c2f668SLeonid Yegoshin 				goto sigbus;
80834c2f668SLeonid Yegoshin 
80934c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
81034c2f668SLeonid Yegoshin 			if (res)
81134c2f668SLeonid Yegoshin 				goto fault;
81234c2f668SLeonid Yegoshin 			regs->regs[reg] = value;
81334c2f668SLeonid Yegoshin 			addr += 8;
81434c2f668SLeonid Yegoshin 			LoadDW(addr, value, res);
81534c2f668SLeonid Yegoshin 			if (res)
81634c2f668SLeonid Yegoshin 				goto fault;
81734c2f668SLeonid Yegoshin 			regs->regs[reg + 1] = value;
81834c2f668SLeonid Yegoshin 			goto success;
81934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
82034c2f668SLeonid Yegoshin 
82134c2f668SLeonid Yegoshin 			goto sigill;
82234c2f668SLeonid Yegoshin 
82334c2f668SLeonid Yegoshin 		case mm_sdp_func:
82434c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
82534c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
82634c2f668SLeonid Yegoshin 			if (reg == 31)
82734c2f668SLeonid Yegoshin 				goto sigbus;
82834c2f668SLeonid Yegoshin 
82934c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 16))
83034c2f668SLeonid Yegoshin 				goto sigbus;
83134c2f668SLeonid Yegoshin 
83234c2f668SLeonid Yegoshin 			value = regs->regs[reg];
83334c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
83434c2f668SLeonid Yegoshin 			if (res)
83534c2f668SLeonid Yegoshin 				goto fault;
83634c2f668SLeonid Yegoshin 			addr += 8;
83734c2f668SLeonid Yegoshin 			value = regs->regs[reg + 1];
83834c2f668SLeonid Yegoshin 			StoreDW(addr, value, res);
83934c2f668SLeonid Yegoshin 			if (res)
84034c2f668SLeonid Yegoshin 				goto fault;
84134c2f668SLeonid Yegoshin 			goto success;
84234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
84334c2f668SLeonid Yegoshin 
84434c2f668SLeonid Yegoshin 			goto sigill;
84534c2f668SLeonid Yegoshin 
84634c2f668SLeonid Yegoshin 		case mm_lwm32_func:
84734c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
84834c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
84934c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
85034c2f668SLeonid Yegoshin 				goto sigill;
85134c2f668SLeonid Yegoshin 			if (reg & 0x10) {
85234c2f668SLeonid Yegoshin 				if (!access_ok
85334c2f668SLeonid Yegoshin 				    (VERIFY_READ, addr, 4 * (rvar + 1)))
85434c2f668SLeonid Yegoshin 					goto sigbus;
85534c2f668SLeonid Yegoshin 			} else {
85634c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 4 * rvar))
85734c2f668SLeonid Yegoshin 					goto sigbus;
85834c2f668SLeonid Yegoshin 			}
85934c2f668SLeonid Yegoshin 			if (rvar == 9)
86034c2f668SLeonid Yegoshin 				rvar = 8;
86134c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
86234c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
86334c2f668SLeonid Yegoshin 				if (res)
86434c2f668SLeonid Yegoshin 					goto fault;
86534c2f668SLeonid Yegoshin 				addr += 4;
86634c2f668SLeonid Yegoshin 				regs->regs[i] = value;
86734c2f668SLeonid Yegoshin 			}
86834c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
86934c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
87034c2f668SLeonid Yegoshin 				if (res)
87134c2f668SLeonid Yegoshin 					goto fault;
87234c2f668SLeonid Yegoshin 				addr += 4;
87334c2f668SLeonid Yegoshin 				regs->regs[30] = value;
87434c2f668SLeonid Yegoshin 			}
87534c2f668SLeonid Yegoshin 			if (reg & 0x10) {
87634c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
87734c2f668SLeonid Yegoshin 				if (res)
87834c2f668SLeonid Yegoshin 					goto fault;
87934c2f668SLeonid Yegoshin 				regs->regs[31] = value;
88034c2f668SLeonid Yegoshin 			}
88134c2f668SLeonid Yegoshin 			goto success;
88234c2f668SLeonid Yegoshin 
88334c2f668SLeonid Yegoshin 		case mm_swm32_func:
88434c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
88534c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
88634c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
88734c2f668SLeonid Yegoshin 				goto sigill;
88834c2f668SLeonid Yegoshin 			if (reg & 0x10) {
88934c2f668SLeonid Yegoshin 				if (!access_ok
89034c2f668SLeonid Yegoshin 				    (VERIFY_WRITE, addr, 4 * (rvar + 1)))
89134c2f668SLeonid Yegoshin 					goto sigbus;
89234c2f668SLeonid Yegoshin 			} else {
89334c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
89434c2f668SLeonid Yegoshin 					goto sigbus;
89534c2f668SLeonid Yegoshin 			}
89634c2f668SLeonid Yegoshin 			if (rvar == 9)
89734c2f668SLeonid Yegoshin 				rvar = 8;
89834c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
89934c2f668SLeonid Yegoshin 				value = regs->regs[i];
90034c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
90134c2f668SLeonid Yegoshin 				if (res)
90234c2f668SLeonid Yegoshin 					goto fault;
90334c2f668SLeonid Yegoshin 				addr += 4;
90434c2f668SLeonid Yegoshin 			}
90534c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
90634c2f668SLeonid Yegoshin 				value = regs->regs[30];
90734c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
90834c2f668SLeonid Yegoshin 				if (res)
90934c2f668SLeonid Yegoshin 					goto fault;
91034c2f668SLeonid Yegoshin 				addr += 4;
91134c2f668SLeonid Yegoshin 			}
91234c2f668SLeonid Yegoshin 			if (reg & 0x10) {
91334c2f668SLeonid Yegoshin 				value = regs->regs[31];
91434c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
91534c2f668SLeonid Yegoshin 				if (res)
91634c2f668SLeonid Yegoshin 					goto fault;
91734c2f668SLeonid Yegoshin 			}
91834c2f668SLeonid Yegoshin 			goto success;
91934c2f668SLeonid Yegoshin 
92034c2f668SLeonid Yegoshin 		case mm_ldm_func:
92134c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
92234c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
92334c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
92434c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
92534c2f668SLeonid Yegoshin 				goto sigill;
92634c2f668SLeonid Yegoshin 			if (reg & 0x10) {
92734c2f668SLeonid Yegoshin 				if (!access_ok
92834c2f668SLeonid Yegoshin 				    (VERIFY_READ, addr, 8 * (rvar + 1)))
92934c2f668SLeonid Yegoshin 					goto sigbus;
93034c2f668SLeonid Yegoshin 			} else {
93134c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_READ, addr, 8 * rvar))
93234c2f668SLeonid Yegoshin 					goto sigbus;
93334c2f668SLeonid Yegoshin 			}
93434c2f668SLeonid Yegoshin 			if (rvar == 9)
93534c2f668SLeonid Yegoshin 				rvar = 8;
93634c2f668SLeonid Yegoshin 
93734c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
93834c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
93934c2f668SLeonid Yegoshin 				if (res)
94034c2f668SLeonid Yegoshin 					goto fault;
94134c2f668SLeonid Yegoshin 				addr += 4;
94234c2f668SLeonid Yegoshin 				regs->regs[i] = value;
94334c2f668SLeonid Yegoshin 			}
94434c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
94534c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
94634c2f668SLeonid Yegoshin 				if (res)
94734c2f668SLeonid Yegoshin 					goto fault;
94834c2f668SLeonid Yegoshin 				addr += 8;
94934c2f668SLeonid Yegoshin 				regs->regs[30] = value;
95034c2f668SLeonid Yegoshin 			}
95134c2f668SLeonid Yegoshin 			if (reg & 0x10) {
95234c2f668SLeonid Yegoshin 				LoadDW(addr, value, res);
95334c2f668SLeonid Yegoshin 				if (res)
95434c2f668SLeonid Yegoshin 					goto fault;
95534c2f668SLeonid Yegoshin 				regs->regs[31] = value;
95634c2f668SLeonid Yegoshin 			}
95734c2f668SLeonid Yegoshin 			goto success;
95834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
95934c2f668SLeonid Yegoshin 
96034c2f668SLeonid Yegoshin 			goto sigill;
96134c2f668SLeonid Yegoshin 
96234c2f668SLeonid Yegoshin 		case mm_sdm_func:
96334c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
96434c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
96534c2f668SLeonid Yegoshin 			rvar = reg & 0xf;
96634c2f668SLeonid Yegoshin 			if ((rvar > 9) || !reg)
96734c2f668SLeonid Yegoshin 				goto sigill;
96834c2f668SLeonid Yegoshin 			if (reg & 0x10) {
96934c2f668SLeonid Yegoshin 				if (!access_ok
97034c2f668SLeonid Yegoshin 				    (VERIFY_WRITE, addr, 8 * (rvar + 1)))
97134c2f668SLeonid Yegoshin 					goto sigbus;
97234c2f668SLeonid Yegoshin 			} else {
97334c2f668SLeonid Yegoshin 				if (!access_ok(VERIFY_WRITE, addr, 8 * rvar))
97434c2f668SLeonid Yegoshin 					goto sigbus;
97534c2f668SLeonid Yegoshin 			}
97634c2f668SLeonid Yegoshin 			if (rvar == 9)
97734c2f668SLeonid Yegoshin 				rvar = 8;
97834c2f668SLeonid Yegoshin 
97934c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
98034c2f668SLeonid Yegoshin 				value = regs->regs[i];
98134c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
98234c2f668SLeonid Yegoshin 				if (res)
98334c2f668SLeonid Yegoshin 					goto fault;
98434c2f668SLeonid Yegoshin 				addr += 8;
98534c2f668SLeonid Yegoshin 			}
98634c2f668SLeonid Yegoshin 			if ((reg & 0xf) == 9) {
98734c2f668SLeonid Yegoshin 				value = regs->regs[30];
98834c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
98934c2f668SLeonid Yegoshin 				if (res)
99034c2f668SLeonid Yegoshin 					goto fault;
99134c2f668SLeonid Yegoshin 				addr += 8;
99234c2f668SLeonid Yegoshin 			}
99334c2f668SLeonid Yegoshin 			if (reg & 0x10) {
99434c2f668SLeonid Yegoshin 				value = regs->regs[31];
99534c2f668SLeonid Yegoshin 				StoreDW(addr, value, res);
99634c2f668SLeonid Yegoshin 				if (res)
99734c2f668SLeonid Yegoshin 					goto fault;
99834c2f668SLeonid Yegoshin 			}
99934c2f668SLeonid Yegoshin 			goto success;
100034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
100134c2f668SLeonid Yegoshin 
100234c2f668SLeonid Yegoshin 			goto sigill;
100334c2f668SLeonid Yegoshin 
100434c2f668SLeonid Yegoshin 			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
100534c2f668SLeonid Yegoshin 		}
100634c2f668SLeonid Yegoshin 
100734c2f668SLeonid Yegoshin 		goto sigbus;
100834c2f668SLeonid Yegoshin 
100934c2f668SLeonid Yegoshin 	case mm_pool32c_op:
101034c2f668SLeonid Yegoshin 		switch (insn.mm_m_format.func) {
101134c2f668SLeonid Yegoshin 		case mm_lwu_func:
101234c2f668SLeonid Yegoshin 			reg = insn.mm_m_format.rd;
101334c2f668SLeonid Yegoshin 			goto loadWU;
101434c2f668SLeonid Yegoshin 		}
101534c2f668SLeonid Yegoshin 
101634c2f668SLeonid Yegoshin 		/*  LL,SC,LLD,SCD are not serviced */
101734c2f668SLeonid Yegoshin 		goto sigbus;
101834c2f668SLeonid Yegoshin 
101934c2f668SLeonid Yegoshin 	case mm_pool32f_op:
102034c2f668SLeonid Yegoshin 		switch (insn.mm_x_format.func) {
102134c2f668SLeonid Yegoshin 		case mm_lwxc1_func:
102234c2f668SLeonid Yegoshin 		case mm_swxc1_func:
102334c2f668SLeonid Yegoshin 		case mm_ldxc1_func:
102434c2f668SLeonid Yegoshin 		case mm_sdxc1_func:
102534c2f668SLeonid Yegoshin 			goto fpu_emul;
102634c2f668SLeonid Yegoshin 		}
102734c2f668SLeonid Yegoshin 
102834c2f668SLeonid Yegoshin 		goto sigbus;
102934c2f668SLeonid Yegoshin 
103034c2f668SLeonid Yegoshin 	case mm_ldc132_op:
103134c2f668SLeonid Yegoshin 	case mm_sdc132_op:
103234c2f668SLeonid Yegoshin 	case mm_lwc132_op:
103334c2f668SLeonid Yegoshin 	case mm_swc132_op:
103434c2f668SLeonid Yegoshin fpu_emul:
103534c2f668SLeonid Yegoshin 		/* roll back jump/branch */
103634c2f668SLeonid Yegoshin 		regs->cp0_epc = origpc;
103734c2f668SLeonid Yegoshin 		regs->regs[31] = orig31;
103834c2f668SLeonid Yegoshin 
103934c2f668SLeonid Yegoshin 		die_if_kernel("Unaligned FP access in kernel code", regs);
104034c2f668SLeonid Yegoshin 		BUG_ON(!used_math());
104134c2f668SLeonid Yegoshin 		BUG_ON(!is_fpu_owner());
104234c2f668SLeonid Yegoshin 
104334c2f668SLeonid Yegoshin 		lose_fpu(1);	/* save the FPU state for the emulator */
104434c2f668SLeonid Yegoshin 		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
104534c2f668SLeonid Yegoshin 					       &fault_addr);
104634c2f668SLeonid Yegoshin 		own_fpu(1);	/* restore FPU state */
104734c2f668SLeonid Yegoshin 
104834c2f668SLeonid Yegoshin 		/* If something went wrong, signal */
104934c2f668SLeonid Yegoshin 		process_fpemu_return(res, fault_addr);
105034c2f668SLeonid Yegoshin 
105134c2f668SLeonid Yegoshin 		if (res == 0)
105234c2f668SLeonid Yegoshin 			goto success;
105334c2f668SLeonid Yegoshin 		return;
105434c2f668SLeonid Yegoshin 
105534c2f668SLeonid Yegoshin 	case mm_lh32_op:
105634c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
105734c2f668SLeonid Yegoshin 		goto loadHW;
105834c2f668SLeonid Yegoshin 
105934c2f668SLeonid Yegoshin 	case mm_lhu32_op:
106034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
106134c2f668SLeonid Yegoshin 		goto loadHWU;
106234c2f668SLeonid Yegoshin 
106334c2f668SLeonid Yegoshin 	case mm_lw32_op:
106434c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
106534c2f668SLeonid Yegoshin 		goto loadW;
106634c2f668SLeonid Yegoshin 
106734c2f668SLeonid Yegoshin 	case mm_sh32_op:
106834c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
106934c2f668SLeonid Yegoshin 		goto storeHW;
107034c2f668SLeonid Yegoshin 
107134c2f668SLeonid Yegoshin 	case mm_sw32_op:
107234c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
107334c2f668SLeonid Yegoshin 		goto storeW;
107434c2f668SLeonid Yegoshin 
107534c2f668SLeonid Yegoshin 	case mm_ld32_op:
107634c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
107734c2f668SLeonid Yegoshin 		goto loadDW;
107834c2f668SLeonid Yegoshin 
107934c2f668SLeonid Yegoshin 	case mm_sd32_op:
108034c2f668SLeonid Yegoshin 		reg = insn.mm_i_format.rt;
108134c2f668SLeonid Yegoshin 		goto storeDW;
108234c2f668SLeonid Yegoshin 
108334c2f668SLeonid Yegoshin 	case mm_pool16c_op:
108434c2f668SLeonid Yegoshin 		switch (insn.mm16_m_format.func) {
108534c2f668SLeonid Yegoshin 		case mm_lwm16_op:
108634c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
108734c2f668SLeonid Yegoshin 			rvar = reg + 1;
108834c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_READ, addr, 4 * rvar))
108934c2f668SLeonid Yegoshin 				goto sigbus;
109034c2f668SLeonid Yegoshin 
109134c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
109234c2f668SLeonid Yegoshin 				LoadW(addr, value, res);
109334c2f668SLeonid Yegoshin 				if (res)
109434c2f668SLeonid Yegoshin 					goto fault;
109534c2f668SLeonid Yegoshin 				addr += 4;
109634c2f668SLeonid Yegoshin 				regs->regs[i] = value;
109734c2f668SLeonid Yegoshin 			}
109834c2f668SLeonid Yegoshin 			LoadW(addr, value, res);
109934c2f668SLeonid Yegoshin 			if (res)
110034c2f668SLeonid Yegoshin 				goto fault;
110134c2f668SLeonid Yegoshin 			regs->regs[31] = value;
110234c2f668SLeonid Yegoshin 
110334c2f668SLeonid Yegoshin 			goto success;
110434c2f668SLeonid Yegoshin 
110534c2f668SLeonid Yegoshin 		case mm_swm16_op:
110634c2f668SLeonid Yegoshin 			reg = insn.mm16_m_format.rlist;
110734c2f668SLeonid Yegoshin 			rvar = reg + 1;
110834c2f668SLeonid Yegoshin 			if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
110934c2f668SLeonid Yegoshin 				goto sigbus;
111034c2f668SLeonid Yegoshin 
111134c2f668SLeonid Yegoshin 			for (i = 16; rvar; rvar--, i++) {
111234c2f668SLeonid Yegoshin 				value = regs->regs[i];
111334c2f668SLeonid Yegoshin 				StoreW(addr, value, res);
111434c2f668SLeonid Yegoshin 				if (res)
111534c2f668SLeonid Yegoshin 					goto fault;
111634c2f668SLeonid Yegoshin 				addr += 4;
111734c2f668SLeonid Yegoshin 			}
111834c2f668SLeonid Yegoshin 			value = regs->regs[31];
111934c2f668SLeonid Yegoshin 			StoreW(addr, value, res);
112034c2f668SLeonid Yegoshin 			if (res)
112134c2f668SLeonid Yegoshin 				goto fault;
112234c2f668SLeonid Yegoshin 
112334c2f668SLeonid Yegoshin 			goto success;
112434c2f668SLeonid Yegoshin 
112534c2f668SLeonid Yegoshin 		}
112634c2f668SLeonid Yegoshin 
112734c2f668SLeonid Yegoshin 		goto sigbus;
112834c2f668SLeonid Yegoshin 
112934c2f668SLeonid Yegoshin 	case mm_lhu16_op:
113034c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
113134c2f668SLeonid Yegoshin 		goto loadHWU;
113234c2f668SLeonid Yegoshin 
113334c2f668SLeonid Yegoshin 	case mm_lw16_op:
113434c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_rb_format.rt];
113534c2f668SLeonid Yegoshin 		goto loadW;
113634c2f668SLeonid Yegoshin 
113734c2f668SLeonid Yegoshin 	case mm_sh16_op:
113834c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
113934c2f668SLeonid Yegoshin 		goto storeHW;
114034c2f668SLeonid Yegoshin 
114134c2f668SLeonid Yegoshin 	case mm_sw16_op:
114234c2f668SLeonid Yegoshin 		reg = reg16to32st[insn.mm16_rb_format.rt];
114334c2f668SLeonid Yegoshin 		goto storeW;
114434c2f668SLeonid Yegoshin 
114534c2f668SLeonid Yegoshin 	case mm_lwsp16_op:
114634c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
114734c2f668SLeonid Yegoshin 		goto loadW;
114834c2f668SLeonid Yegoshin 
114934c2f668SLeonid Yegoshin 	case mm_swsp16_op:
115034c2f668SLeonid Yegoshin 		reg = insn.mm16_r5_format.rt;
115134c2f668SLeonid Yegoshin 		goto storeW;
115234c2f668SLeonid Yegoshin 
115334c2f668SLeonid Yegoshin 	case mm_lwgp16_op:
115434c2f668SLeonid Yegoshin 		reg = reg16to32[insn.mm16_r3_format.rt];
115534c2f668SLeonid Yegoshin 		goto loadW;
115634c2f668SLeonid Yegoshin 
115734c2f668SLeonid Yegoshin 	default:
115834c2f668SLeonid Yegoshin 		goto sigill;
115934c2f668SLeonid Yegoshin 	}
116034c2f668SLeonid Yegoshin 
116134c2f668SLeonid Yegoshin loadHW:
116234c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 2))
116334c2f668SLeonid Yegoshin 		goto sigbus;
116434c2f668SLeonid Yegoshin 
116534c2f668SLeonid Yegoshin 	LoadHW(addr, value, res);
116634c2f668SLeonid Yegoshin 	if (res)
116734c2f668SLeonid Yegoshin 		goto fault;
116834c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
116934c2f668SLeonid Yegoshin 	goto success;
117034c2f668SLeonid Yegoshin 
117134c2f668SLeonid Yegoshin loadHWU:
117234c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 2))
117334c2f668SLeonid Yegoshin 		goto sigbus;
117434c2f668SLeonid Yegoshin 
117534c2f668SLeonid Yegoshin 	LoadHWU(addr, value, res);
117634c2f668SLeonid Yegoshin 	if (res)
117734c2f668SLeonid Yegoshin 		goto fault;
117834c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
117934c2f668SLeonid Yegoshin 	goto success;
118034c2f668SLeonid Yegoshin 
118134c2f668SLeonid Yegoshin loadW:
118234c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 4))
118334c2f668SLeonid Yegoshin 		goto sigbus;
118434c2f668SLeonid Yegoshin 
118534c2f668SLeonid Yegoshin 	LoadW(addr, value, res);
118634c2f668SLeonid Yegoshin 	if (res)
118734c2f668SLeonid Yegoshin 		goto fault;
118834c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
118934c2f668SLeonid Yegoshin 	goto success;
119034c2f668SLeonid Yegoshin 
119134c2f668SLeonid Yegoshin loadWU:
119234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
119334c2f668SLeonid Yegoshin 	/*
119434c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
119534c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
119634c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
119734c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
119834c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
119934c2f668SLeonid Yegoshin 	 */
120034c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 4))
120134c2f668SLeonid Yegoshin 		goto sigbus;
120234c2f668SLeonid Yegoshin 
120334c2f668SLeonid Yegoshin 	LoadWU(addr, value, res);
120434c2f668SLeonid Yegoshin 	if (res)
120534c2f668SLeonid Yegoshin 		goto fault;
120634c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
120734c2f668SLeonid Yegoshin 	goto success;
120834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
120934c2f668SLeonid Yegoshin 
121034c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
121134c2f668SLeonid Yegoshin 	goto sigill;
121234c2f668SLeonid Yegoshin 
121334c2f668SLeonid Yegoshin loadDW:
121434c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
121534c2f668SLeonid Yegoshin 	/*
121634c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
121734c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
121834c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
121934c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
122034c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
122134c2f668SLeonid Yegoshin 	 */
122234c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_READ, addr, 8))
122334c2f668SLeonid Yegoshin 		goto sigbus;
122434c2f668SLeonid Yegoshin 
122534c2f668SLeonid Yegoshin 	LoadDW(addr, value, res);
122634c2f668SLeonid Yegoshin 	if (res)
122734c2f668SLeonid Yegoshin 		goto fault;
122834c2f668SLeonid Yegoshin 	regs->regs[reg] = value;
122934c2f668SLeonid Yegoshin 	goto success;
123034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
123134c2f668SLeonid Yegoshin 
123234c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
123334c2f668SLeonid Yegoshin 	goto sigill;
123434c2f668SLeonid Yegoshin 
123534c2f668SLeonid Yegoshin storeHW:
123634c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 2))
123734c2f668SLeonid Yegoshin 		goto sigbus;
123834c2f668SLeonid Yegoshin 
123934c2f668SLeonid Yegoshin 	value = regs->regs[reg];
124034c2f668SLeonid Yegoshin 	StoreHW(addr, value, res);
124134c2f668SLeonid Yegoshin 	if (res)
124234c2f668SLeonid Yegoshin 		goto fault;
124334c2f668SLeonid Yegoshin 	goto success;
124434c2f668SLeonid Yegoshin 
124534c2f668SLeonid Yegoshin storeW:
124634c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 4))
124734c2f668SLeonid Yegoshin 		goto sigbus;
124834c2f668SLeonid Yegoshin 
124934c2f668SLeonid Yegoshin 	value = regs->regs[reg];
125034c2f668SLeonid Yegoshin 	StoreW(addr, value, res);
125134c2f668SLeonid Yegoshin 	if (res)
125234c2f668SLeonid Yegoshin 		goto fault;
125334c2f668SLeonid Yegoshin 	goto success;
125434c2f668SLeonid Yegoshin 
125534c2f668SLeonid Yegoshin storeDW:
125634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
125734c2f668SLeonid Yegoshin 	/*
125834c2f668SLeonid Yegoshin 	 * A 32-bit kernel might be running on a 64-bit processor.  But
125934c2f668SLeonid Yegoshin 	 * if we're on a 32-bit processor and an i-cache incoherency
126034c2f668SLeonid Yegoshin 	 * or race makes us see a 64-bit instruction here the sdl/sdr
126134c2f668SLeonid Yegoshin 	 * would blow up, so for now we don't handle unaligned 64-bit
126234c2f668SLeonid Yegoshin 	 * instructions on 32-bit kernels.
126334c2f668SLeonid Yegoshin 	 */
126434c2f668SLeonid Yegoshin 	if (!access_ok(VERIFY_WRITE, addr, 8))
126534c2f668SLeonid Yegoshin 		goto sigbus;
126634c2f668SLeonid Yegoshin 
126734c2f668SLeonid Yegoshin 	value = regs->regs[reg];
126834c2f668SLeonid Yegoshin 	StoreDW(addr, value, res);
126934c2f668SLeonid Yegoshin 	if (res)
127034c2f668SLeonid Yegoshin 		goto fault;
127134c2f668SLeonid Yegoshin 	goto success;
127234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
127334c2f668SLeonid Yegoshin 
127434c2f668SLeonid Yegoshin 	/* Cannot handle 64-bit instructions in 32-bit kernel */
127534c2f668SLeonid Yegoshin 	goto sigill;
127634c2f668SLeonid Yegoshin 
127734c2f668SLeonid Yegoshin success:
127834c2f668SLeonid Yegoshin 	regs->cp0_epc = contpc;	/* advance or branch */
127934c2f668SLeonid Yegoshin 
128034c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
128134c2f668SLeonid Yegoshin 	unaligned_instructions++;
128234c2f668SLeonid Yegoshin #endif
128334c2f668SLeonid Yegoshin 	return;
128434c2f668SLeonid Yegoshin 
128534c2f668SLeonid Yegoshin fault:
128634c2f668SLeonid Yegoshin 	/* roll back jump/branch */
128734c2f668SLeonid Yegoshin 	regs->cp0_epc = origpc;
128834c2f668SLeonid Yegoshin 	regs->regs[31] = orig31;
128934c2f668SLeonid Yegoshin 	/* Did we have an exception handler installed? */
129034c2f668SLeonid Yegoshin 	if (fixup_exception(regs))
129134c2f668SLeonid Yegoshin 		return;
129234c2f668SLeonid Yegoshin 
129334c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
129434c2f668SLeonid Yegoshin 	force_sig(SIGSEGV, current);
129534c2f668SLeonid Yegoshin 
129634c2f668SLeonid Yegoshin 	return;
129734c2f668SLeonid Yegoshin 
129834c2f668SLeonid Yegoshin sigbus:
129934c2f668SLeonid Yegoshin 	die_if_kernel("Unhandled kernel unaligned access", regs);
130034c2f668SLeonid Yegoshin 	force_sig(SIGBUS, current);
130134c2f668SLeonid Yegoshin 
130234c2f668SLeonid Yegoshin 	return;
130334c2f668SLeonid Yegoshin 
130434c2f668SLeonid Yegoshin sigill:
130534c2f668SLeonid Yegoshin 	die_if_kernel
130634c2f668SLeonid Yegoshin 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
1307a6d5ff04SDavid Daney 	force_sig(SIGILL, current);
13081da177e4SLinus Torvalds }
13091da177e4SLinus Torvalds 
1310451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1311451b001bSSteven J. Hill {
1312451b001bSSteven J. Hill 	unsigned long value;
1313451b001bSSteven J. Hill 	unsigned int res;
1314451b001bSSteven J. Hill 	int reg;
1315451b001bSSteven J. Hill 	unsigned long orig31;
1316451b001bSSteven J. Hill 	u16 __user *pc16;
1317451b001bSSteven J. Hill 	unsigned long origpc;
1318451b001bSSteven J. Hill 	union mips16e_instruction mips16inst, oldinst;
1319451b001bSSteven J. Hill 
1320451b001bSSteven J. Hill 	origpc = regs->cp0_epc;
1321451b001bSSteven J. Hill 	orig31 = regs->regs[31];
1322451b001bSSteven J. Hill 	pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1323451b001bSSteven J. Hill 	/*
1324451b001bSSteven J. Hill 	 * This load never faults.
1325451b001bSSteven J. Hill 	 */
1326451b001bSSteven J. Hill 	__get_user(mips16inst.full, pc16);
1327451b001bSSteven J. Hill 	oldinst = mips16inst;
1328451b001bSSteven J. Hill 
1329451b001bSSteven J. Hill 	/* skip EXTEND instruction */
1330451b001bSSteven J. Hill 	if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1331451b001bSSteven J. Hill 		pc16++;
1332451b001bSSteven J. Hill 		__get_user(mips16inst.full, pc16);
1333451b001bSSteven J. Hill 	} else if (delay_slot(regs)) {
1334451b001bSSteven J. Hill 		/*  skip jump instructions */
1335451b001bSSteven J. Hill 		/*  JAL/JALX are 32 bits but have OPCODE in first short int */
1336451b001bSSteven J. Hill 		if (mips16inst.ri.opcode == MIPS16e_jal_op)
1337451b001bSSteven J. Hill 			pc16++;
1338451b001bSSteven J. Hill 		pc16++;
1339451b001bSSteven J. Hill 		if (get_user(mips16inst.full, pc16))
1340451b001bSSteven J. Hill 			goto sigbus;
1341451b001bSSteven J. Hill 	}
1342451b001bSSteven J. Hill 
1343451b001bSSteven J. Hill 	switch (mips16inst.ri.opcode) {
1344451b001bSSteven J. Hill 	case MIPS16e_i64_op:	/* I64 or RI64 instruction */
1345451b001bSSteven J. Hill 		switch (mips16inst.i64.func) {	/* I64/RI64 func field check */
1346451b001bSSteven J. Hill 		case MIPS16e_ldpc_func:
1347451b001bSSteven J. Hill 		case MIPS16e_ldsp_func:
1348451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1349451b001bSSteven J. Hill 			goto loadDW;
1350451b001bSSteven J. Hill 
1351451b001bSSteven J. Hill 		case MIPS16e_sdsp_func:
1352451b001bSSteven J. Hill 			reg = reg16to32[mips16inst.ri64.ry];
1353451b001bSSteven J. Hill 			goto writeDW;
1354451b001bSSteven J. Hill 
1355451b001bSSteven J. Hill 		case MIPS16e_sdrasp_func:
1356451b001bSSteven J. Hill 			reg = 29;	/* GPRSP */
1357451b001bSSteven J. Hill 			goto writeDW;
1358451b001bSSteven J. Hill 		}
1359451b001bSSteven J. Hill 
1360451b001bSSteven J. Hill 		goto sigbus;
1361451b001bSSteven J. Hill 
1362451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1363451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1364451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1365451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.ri.rx];
1366451b001bSSteven J. Hill 		break;
1367451b001bSSteven J. Hill 
1368451b001bSSteven J. Hill 	case MIPS16e_i8_op:
1369451b001bSSteven J. Hill 		if (mips16inst.i8.func != MIPS16e_swrasp_func)
1370451b001bSSteven J. Hill 			goto sigbus;
1371451b001bSSteven J. Hill 		reg = 29;	/* GPRSP */
1372451b001bSSteven J. Hill 		break;
1373451b001bSSteven J. Hill 
1374451b001bSSteven J. Hill 	default:
1375451b001bSSteven J. Hill 		reg = reg16to32[mips16inst.rri.ry];
1376451b001bSSteven J. Hill 		break;
1377451b001bSSteven J. Hill 	}
1378451b001bSSteven J. Hill 
1379451b001bSSteven J. Hill 	switch (mips16inst.ri.opcode) {
1380451b001bSSteven J. Hill 
1381451b001bSSteven J. Hill 	case MIPS16e_lb_op:
1382451b001bSSteven J. Hill 	case MIPS16e_lbu_op:
1383451b001bSSteven J. Hill 	case MIPS16e_sb_op:
1384451b001bSSteven J. Hill 		goto sigbus;
1385451b001bSSteven J. Hill 
1386451b001bSSteven J. Hill 	case MIPS16e_lh_op:
1387451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 2))
1388451b001bSSteven J. Hill 			goto sigbus;
1389451b001bSSteven J. Hill 
1390451b001bSSteven J. Hill 		LoadHW(addr, value, res);
1391451b001bSSteven J. Hill 		if (res)
1392451b001bSSteven J. Hill 			goto fault;
1393451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1394451b001bSSteven J. Hill 		regs->regs[reg] = value;
1395451b001bSSteven J. Hill 		break;
1396451b001bSSteven J. Hill 
1397451b001bSSteven J. Hill 	case MIPS16e_lhu_op:
1398451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 2))
1399451b001bSSteven J. Hill 			goto sigbus;
1400451b001bSSteven J. Hill 
1401451b001bSSteven J. Hill 		LoadHWU(addr, value, res);
1402451b001bSSteven J. Hill 		if (res)
1403451b001bSSteven J. Hill 			goto fault;
1404451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1405451b001bSSteven J. Hill 		regs->regs[reg] = value;
1406451b001bSSteven J. Hill 		break;
1407451b001bSSteven J. Hill 
1408451b001bSSteven J. Hill 	case MIPS16e_lw_op:
1409451b001bSSteven J. Hill 	case MIPS16e_lwpc_op:
1410451b001bSSteven J. Hill 	case MIPS16e_lwsp_op:
1411451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 4))
1412451b001bSSteven J. Hill 			goto sigbus;
1413451b001bSSteven J. Hill 
1414451b001bSSteven J. Hill 		LoadW(addr, value, res);
1415451b001bSSteven J. Hill 		if (res)
1416451b001bSSteven J. Hill 			goto fault;
1417451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1418451b001bSSteven J. Hill 		regs->regs[reg] = value;
1419451b001bSSteven J. Hill 		break;
1420451b001bSSteven J. Hill 
1421451b001bSSteven J. Hill 	case MIPS16e_lwu_op:
1422451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1423451b001bSSteven J. Hill 		/*
1424451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1425451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1426451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1427451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1428451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1429451b001bSSteven J. Hill 		 */
1430451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 4))
1431451b001bSSteven J. Hill 			goto sigbus;
1432451b001bSSteven J. Hill 
1433451b001bSSteven J. Hill 		LoadWU(addr, value, res);
1434451b001bSSteven J. Hill 		if (res)
1435451b001bSSteven J. Hill 			goto fault;
1436451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1437451b001bSSteven J. Hill 		regs->regs[reg] = value;
1438451b001bSSteven J. Hill 		break;
1439451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1440451b001bSSteven J. Hill 
1441451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1442451b001bSSteven J. Hill 		goto sigill;
1443451b001bSSteven J. Hill 
1444451b001bSSteven J. Hill 	case MIPS16e_ld_op:
1445451b001bSSteven J. Hill loadDW:
1446451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1447451b001bSSteven J. Hill 		/*
1448451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1449451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1450451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1451451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1452451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1453451b001bSSteven J. Hill 		 */
1454451b001bSSteven J. Hill 		if (!access_ok(VERIFY_READ, addr, 8))
1455451b001bSSteven J. Hill 			goto sigbus;
1456451b001bSSteven J. Hill 
1457451b001bSSteven J. Hill 		LoadDW(addr, value, res);
1458451b001bSSteven J. Hill 		if (res)
1459451b001bSSteven J. Hill 			goto fault;
1460451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1461451b001bSSteven J. Hill 		regs->regs[reg] = value;
1462451b001bSSteven J. Hill 		break;
1463451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1464451b001bSSteven J. Hill 
1465451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1466451b001bSSteven J. Hill 		goto sigill;
1467451b001bSSteven J. Hill 
1468451b001bSSteven J. Hill 	case MIPS16e_sh_op:
1469451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 2))
1470451b001bSSteven J. Hill 			goto sigbus;
1471451b001bSSteven J. Hill 
1472451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1473451b001bSSteven J. Hill 		value = regs->regs[reg];
1474451b001bSSteven J. Hill 		StoreHW(addr, value, res);
1475451b001bSSteven J. Hill 		if (res)
1476451b001bSSteven J. Hill 			goto fault;
1477451b001bSSteven J. Hill 		break;
1478451b001bSSteven J. Hill 
1479451b001bSSteven J. Hill 	case MIPS16e_sw_op:
1480451b001bSSteven J. Hill 	case MIPS16e_swsp_op:
1481451b001bSSteven J. Hill 	case MIPS16e_i8_op:	/* actually - MIPS16e_swrasp_func */
1482451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 4))
1483451b001bSSteven J. Hill 			goto sigbus;
1484451b001bSSteven J. Hill 
1485451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1486451b001bSSteven J. Hill 		value = regs->regs[reg];
1487451b001bSSteven J. Hill 		StoreW(addr, value, res);
1488451b001bSSteven J. Hill 		if (res)
1489451b001bSSteven J. Hill 			goto fault;
1490451b001bSSteven J. Hill 		break;
1491451b001bSSteven J. Hill 
1492451b001bSSteven J. Hill 	case MIPS16e_sd_op:
1493451b001bSSteven J. Hill writeDW:
1494451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1495451b001bSSteven J. Hill 		/*
1496451b001bSSteven J. Hill 		 * A 32-bit kernel might be running on a 64-bit processor.  But
1497451b001bSSteven J. Hill 		 * if we're on a 32-bit processor and an i-cache incoherency
1498451b001bSSteven J. Hill 		 * or race makes us see a 64-bit instruction here the sdl/sdr
1499451b001bSSteven J. Hill 		 * would blow up, so for now we don't handle unaligned 64-bit
1500451b001bSSteven J. Hill 		 * instructions on 32-bit kernels.
1501451b001bSSteven J. Hill 		 */
1502451b001bSSteven J. Hill 		if (!access_ok(VERIFY_WRITE, addr, 8))
1503451b001bSSteven J. Hill 			goto sigbus;
1504451b001bSSteven J. Hill 
1505451b001bSSteven J. Hill 		MIPS16e_compute_return_epc(regs, &oldinst);
1506451b001bSSteven J. Hill 		value = regs->regs[reg];
1507451b001bSSteven J. Hill 		StoreDW(addr, value, res);
1508451b001bSSteven J. Hill 		if (res)
1509451b001bSSteven J. Hill 			goto fault;
1510451b001bSSteven J. Hill 		break;
1511451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1512451b001bSSteven J. Hill 
1513451b001bSSteven J. Hill 		/* Cannot handle 64-bit instructions in 32-bit kernel */
1514451b001bSSteven J. Hill 		goto sigill;
1515451b001bSSteven J. Hill 
1516451b001bSSteven J. Hill 	default:
1517451b001bSSteven J. Hill 		/*
1518451b001bSSteven J. Hill 		 * Pheeee...  We encountered an yet unknown instruction or
1519451b001bSSteven J. Hill 		 * cache coherence problem.  Die sucker, die ...
1520451b001bSSteven J. Hill 		 */
1521451b001bSSteven J. Hill 		goto sigill;
1522451b001bSSteven J. Hill 	}
1523451b001bSSteven J. Hill 
1524451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
1525451b001bSSteven J. Hill 	unaligned_instructions++;
1526451b001bSSteven J. Hill #endif
1527451b001bSSteven J. Hill 
1528451b001bSSteven J. Hill 	return;
1529451b001bSSteven J. Hill 
1530451b001bSSteven J. Hill fault:
1531451b001bSSteven J. Hill 	/* roll back jump/branch */
1532451b001bSSteven J. Hill 	regs->cp0_epc = origpc;
1533451b001bSSteven J. Hill 	regs->regs[31] = orig31;
1534451b001bSSteven J. Hill 	/* Did we have an exception handler installed? */
1535451b001bSSteven J. Hill 	if (fixup_exception(regs))
1536451b001bSSteven J. Hill 		return;
1537451b001bSSteven J. Hill 
1538451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
1539451b001bSSteven J. Hill 	force_sig(SIGSEGV, current);
1540451b001bSSteven J. Hill 
1541451b001bSSteven J. Hill 	return;
1542451b001bSSteven J. Hill 
1543451b001bSSteven J. Hill sigbus:
1544451b001bSSteven J. Hill 	die_if_kernel("Unhandled kernel unaligned access", regs);
1545451b001bSSteven J. Hill 	force_sig(SIGBUS, current);
1546451b001bSSteven J. Hill 
1547451b001bSSteven J. Hill 	return;
1548451b001bSSteven J. Hill 
1549451b001bSSteven J. Hill sigill:
1550451b001bSSteven J. Hill 	die_if_kernel
1551451b001bSSteven J. Hill 	    ("Unhandled kernel unaligned access or invalid instruction", regs);
1552451b001bSSteven J. Hill 	force_sig(SIGILL, current);
1553451b001bSSteven J. Hill }
1554fc192e50STony Wu 
15551da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
15561da177e4SLinus Torvalds {
1557c3fc5cd5SRalf Baechle 	enum ctx_state prev_state;
1558fe00f943SRalf Baechle 	unsigned int __user *pc;
15591da177e4SLinus Torvalds 	mm_segment_t seg;
15601da177e4SLinus Torvalds 
1561c3fc5cd5SRalf Baechle 	prev_state = exception_enter();
15627f788d2dSDeng-Cheng Zhu 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1563a8b0ca17SPeter Zijlstra 			1, regs, regs->cp0_badvaddr);
15641da177e4SLinus Torvalds 	/*
15651da177e4SLinus Torvalds 	 * Did we catch a fault trying to load an instruction?
15661da177e4SLinus Torvalds 	 */
156734c2f668SLeonid Yegoshin 	if (regs->cp0_badvaddr == regs->cp0_epc)
15681da177e4SLinus Torvalds 		goto sigbus;
15691da177e4SLinus Torvalds 
1570293c5bd1SRalf Baechle 	if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
15711da177e4SLinus Torvalds 		goto sigbus;
15726312e0eeSAtsushi Nemoto 	if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
15736312e0eeSAtsushi Nemoto 		goto sigbus;
15741da177e4SLinus Torvalds 
15751da177e4SLinus Torvalds 	/*
15761da177e4SLinus Torvalds 	 * Do branch emulation only if we didn't forward the exception.
15771da177e4SLinus Torvalds 	 * This is all so but ugly ...
15781da177e4SLinus Torvalds 	 */
157934c2f668SLeonid Yegoshin 
158034c2f668SLeonid Yegoshin 	/*
158134c2f668SLeonid Yegoshin 	 * Are we running in microMIPS mode?
158234c2f668SLeonid Yegoshin 	 */
158334c2f668SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
158434c2f668SLeonid Yegoshin 		/*
158534c2f668SLeonid Yegoshin 		 * Did we catch a fault trying to load an instruction in
158634c2f668SLeonid Yegoshin 		 * 16-bit mode?
158734c2f668SLeonid Yegoshin 		 */
158834c2f668SLeonid Yegoshin 		if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
158934c2f668SLeonid Yegoshin 			goto sigbus;
159034c2f668SLeonid Yegoshin 		if (unaligned_action == UNALIGNED_ACTION_SHOW)
159134c2f668SLeonid Yegoshin 			show_registers(regs);
159234c2f668SLeonid Yegoshin 
159334c2f668SLeonid Yegoshin 		if (cpu_has_mmips) {
159434c2f668SLeonid Yegoshin 			seg = get_fs();
159534c2f668SLeonid Yegoshin 			if (!user_mode(regs))
159634c2f668SLeonid Yegoshin 				set_fs(KERNEL_DS);
159734c2f668SLeonid Yegoshin 			emulate_load_store_microMIPS(regs,
159834c2f668SLeonid Yegoshin 				(void __user *)regs->cp0_badvaddr);
159934c2f668SLeonid Yegoshin 			set_fs(seg);
160034c2f668SLeonid Yegoshin 
160134c2f668SLeonid Yegoshin 			return;
160234c2f668SLeonid Yegoshin 		}
160334c2f668SLeonid Yegoshin 
1604451b001bSSteven J. Hill 		if (cpu_has_mips16) {
1605451b001bSSteven J. Hill 			seg = get_fs();
1606451b001bSSteven J. Hill 			if (!user_mode(regs))
1607451b001bSSteven J. Hill 				set_fs(KERNEL_DS);
1608451b001bSSteven J. Hill 			emulate_load_store_MIPS16e(regs,
1609451b001bSSteven J. Hill 				(void __user *)regs->cp0_badvaddr);
1610451b001bSSteven J. Hill 			set_fs(seg);
1611451b001bSSteven J. Hill 
1612451b001bSSteven J. Hill 			return;
1613451b001bSSteven J. Hill 	}
1614451b001bSSteven J. Hill 
161534c2f668SLeonid Yegoshin 		goto sigbus;
161634c2f668SLeonid Yegoshin 	}
161734c2f668SLeonid Yegoshin 
161834c2f668SLeonid Yegoshin 	if (unaligned_action == UNALIGNED_ACTION_SHOW)
161934c2f668SLeonid Yegoshin 		show_registers(regs);
162034c2f668SLeonid Yegoshin 	pc = (unsigned int __user *)exception_epc(regs);
162134c2f668SLeonid Yegoshin 
16221da177e4SLinus Torvalds 	seg = get_fs();
16231da177e4SLinus Torvalds 	if (!user_mode(regs))
16241da177e4SLinus Torvalds 		set_fs(KERNEL_DS);
16257f18f151SRalf Baechle 	emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
16261da177e4SLinus Torvalds 	set_fs(seg);
16271da177e4SLinus Torvalds 
16281da177e4SLinus Torvalds 	return;
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds sigbus:
16311da177e4SLinus Torvalds 	die_if_kernel("Kernel unaligned instruction access", regs);
16321da177e4SLinus Torvalds 	force_sig(SIGBUS, current);
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds 	/*
16351da177e4SLinus Torvalds 	 * XXX On return from the signal handler we should advance the epc
16361da177e4SLinus Torvalds 	 */
1637c3fc5cd5SRalf Baechle 	exception_exit(prev_state);
16381da177e4SLinus Torvalds }
16396312e0eeSAtsushi Nemoto 
16406312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
16416312e0eeSAtsushi Nemoto extern struct dentry *mips_debugfs_dir;
16426312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
16436312e0eeSAtsushi Nemoto {
16446312e0eeSAtsushi Nemoto 	struct dentry *d;
16456312e0eeSAtsushi Nemoto 
16466312e0eeSAtsushi Nemoto 	if (!mips_debugfs_dir)
16476312e0eeSAtsushi Nemoto 		return -ENODEV;
16486312e0eeSAtsushi Nemoto 	d = debugfs_create_u32("unaligned_instructions", S_IRUGO,
16496312e0eeSAtsushi Nemoto 			       mips_debugfs_dir, &unaligned_instructions);
1650b517531cSZhaolei 	if (!d)
1651b517531cSZhaolei 		return -ENOMEM;
16526312e0eeSAtsushi Nemoto 	d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
16536312e0eeSAtsushi Nemoto 			       mips_debugfs_dir, &unaligned_action);
1654b517531cSZhaolei 	if (!d)
1655b517531cSZhaolei 		return -ENOMEM;
16566312e0eeSAtsushi Nemoto 	return 0;
16576312e0eeSAtsushi Nemoto }
16586312e0eeSAtsushi Nemoto __initcall(debugfs_unaligned);
16596312e0eeSAtsushi Nemoto #endif
1660