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, ¤t->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, ¤t->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