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