11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Handle unaligned accesses by emulation. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 51da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 61da177e4SLinus Torvalds * for more details. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle 91da177e4SLinus Torvalds * Copyright (C) 1999 Silicon Graphics, Inc. 109d8e5736SMarkos Chandras * Copyright (C) 2014 Imagination Technologies Ltd. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This file contains exception handler for address error exception with the 131da177e4SLinus Torvalds * special capability to execute faulting instructions in software. The 141da177e4SLinus Torvalds * handler does not try to handle the case when the program counter points 151da177e4SLinus Torvalds * to an address not aligned to a word boundary. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Putting data to unaligned addresses is a bad practice even on Intel where 181da177e4SLinus Torvalds * only the performance is affected. Much worse is that such code is non- 191da177e4SLinus Torvalds * portable. Due to several programs that die on MIPS due to alignment 201da177e4SLinus Torvalds * problems I decided to implement this handler anyway though I originally 211da177e4SLinus Torvalds * didn't intend to do this at all for user code. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * For now I enable fixing of address errors by default to make life easier. 241da177e4SLinus Torvalds * I however intend to disable this somewhen in the future when the alignment 251da177e4SLinus Torvalds * problems with user programs have been fixed. For programmers this is the 261da177e4SLinus Torvalds * right way to go. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * Fixing address errors is a per process option. The option is inherited 291da177e4SLinus Torvalds * across fork(2) and execve(2) calls. If you really want to use the 301da177e4SLinus Torvalds * option in your user programs - I discourage the use of the software 311da177e4SLinus Torvalds * emulation strongly - use the following code in your userland stuff: 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * #include <sys/sysmips.h> 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds * ... 361da177e4SLinus Torvalds * sysmips(MIPS_FIXADE, x); 371da177e4SLinus Torvalds * ... 381da177e4SLinus Torvalds * 391da177e4SLinus Torvalds * The argument x is 0 for disabling software emulation, enabled otherwise. 401da177e4SLinus Torvalds * 411da177e4SLinus Torvalds * Below a little program to play around with this feature. 421da177e4SLinus Torvalds * 431da177e4SLinus Torvalds * #include <stdio.h> 441da177e4SLinus Torvalds * #include <sys/sysmips.h> 451da177e4SLinus Torvalds * 461da177e4SLinus Torvalds * struct foo { 471da177e4SLinus Torvalds * unsigned char bar[8]; 481da177e4SLinus Torvalds * }; 491da177e4SLinus Torvalds * 501da177e4SLinus Torvalds * main(int argc, char *argv[]) 511da177e4SLinus Torvalds * { 521da177e4SLinus Torvalds * struct foo x = {0, 1, 2, 3, 4, 5, 6, 7}; 531da177e4SLinus Torvalds * unsigned int *p = (unsigned int *) (x.bar + 3); 541da177e4SLinus Torvalds * int i; 551da177e4SLinus Torvalds * 561da177e4SLinus Torvalds * if (argc > 1) 571da177e4SLinus Torvalds * sysmips(MIPS_FIXADE, atoi(argv[1])); 581da177e4SLinus Torvalds * 591da177e4SLinus Torvalds * printf("*p = %08lx\n", *p); 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * *p = 0xdeadface; 621da177e4SLinus Torvalds * 631da177e4SLinus Torvalds * for(i = 0; i <= 7; i++) 641da177e4SLinus Torvalds * printf("%02x ", x.bar[i]); 651da177e4SLinus Torvalds * printf("\n"); 661da177e4SLinus Torvalds * } 671da177e4SLinus Torvalds * 681da177e4SLinus Torvalds * Coprocessor loads are not supported; I think this case is unimportant 691da177e4SLinus Torvalds * in the practice. 701da177e4SLinus Torvalds * 711da177e4SLinus Torvalds * TODO: Handle ndc (attempted store to doubleword in uncached memory) 721da177e4SLinus Torvalds * exception for the R6000. 731da177e4SLinus Torvalds * A store crossing a page boundary might be executed only partially. 741da177e4SLinus Torvalds * Undo the partial store in this case. 751da177e4SLinus Torvalds */ 76c3fc5cd5SRalf Baechle #include <linux/context_tracking.h> 771da177e4SLinus Torvalds #include <linux/mm.h> 781da177e4SLinus Torvalds #include <linux/signal.h> 791da177e4SLinus Torvalds #include <linux/smp.h> 80e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 816312e0eeSAtsushi Nemoto #include <linux/debugfs.h> 827f788d2dSDeng-Cheng Zhu #include <linux/perf_event.h> 837f788d2dSDeng-Cheng Zhu 841da177e4SLinus Torvalds #include <asm/asm.h> 851da177e4SLinus Torvalds #include <asm/branch.h> 861da177e4SLinus Torvalds #include <asm/byteorder.h> 8769f3a7deSRalf Baechle #include <asm/cop2.h> 8875dcfc1dSPaul Burton #include <asm/debug.h> 89102cedc3SLeonid Yegoshin #include <asm/fpu.h> 90102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h> 911da177e4SLinus Torvalds #include <asm/inst.h> 927c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds #define STR(x) __STR(x) 951da177e4SLinus Torvalds #define __STR(x) #x 961da177e4SLinus Torvalds 976312e0eeSAtsushi Nemoto enum { 986312e0eeSAtsushi Nemoto UNALIGNED_ACTION_QUIET, 996312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SIGNAL, 1006312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SHOW, 1016312e0eeSAtsushi Nemoto }; 1026312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 1036312e0eeSAtsushi Nemoto static u32 unaligned_instructions; 1046312e0eeSAtsushi Nemoto static u32 unaligned_action; 1056312e0eeSAtsushi Nemoto #else 1066312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET 1071da177e4SLinus Torvalds #endif 1086312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs); 1091da177e4SLinus Torvalds 11034c2f668SLeonid Yegoshin #ifdef __BIG_ENDIAN 111eeb53895SMarkos Chandras #define _LoadHW(addr, value, res, type) \ 1123563c32dSMarkos Chandras do { \ 11334c2f668SLeonid Yegoshin __asm__ __volatile__ (".set\tnoat\n" \ 114eeb53895SMarkos Chandras "1:\t"type##_lb("%0", "0(%2)")"\n" \ 115eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "1(%2)")"\n\t"\ 11634c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 11734c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 11834c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 11934c2f668SLeonid Yegoshin "3:\t.set\tat\n\t" \ 12034c2f668SLeonid Yegoshin ".insn\n\t" \ 12134c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 12234c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 12334c2f668SLeonid Yegoshin "j\t3b\n\t" \ 12434c2f668SLeonid Yegoshin ".previous\n\t" \ 12534c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 12634c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 12734c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 12834c2f668SLeonid Yegoshin ".previous" \ 12934c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 1303563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 1313563c32dSMarkos Chandras } while(0) 13234c2f668SLeonid Yegoshin 133932afdeeSYasha Cherikovsky #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR 134eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 1353563c32dSMarkos Chandras do { \ 13634c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 137eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "(%2)")"\n" \ 138eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "3(%2)")"\n\t"\ 13934c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 14034c2f668SLeonid Yegoshin "3:\n\t" \ 14134c2f668SLeonid Yegoshin ".insn\n\t" \ 14234c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 14334c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 14434c2f668SLeonid Yegoshin "j\t3b\n\t" \ 14534c2f668SLeonid Yegoshin ".previous\n\t" \ 14634c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 14734c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 14834c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 14934c2f668SLeonid Yegoshin ".previous" \ 15034c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 1513563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 1523563c32dSMarkos Chandras } while(0) 1533563c32dSMarkos Chandras 154932afdeeSYasha Cherikovsky #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 155932afdeeSYasha Cherikovsky /* For CPUs without lwl instruction */ 156eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 1573563c32dSMarkos Chandras do { \ 1580593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 1590593a44cSLeonid Yegoshin ".set\tpush\n" \ 1600593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 161eeb53895SMarkos Chandras "1:"type##_lb("%0", "0(%2)")"\n\t" \ 162eeb53895SMarkos Chandras "2:"type##_lbu("$1", "1(%2)")"\n\t" \ 1630593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 1640593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 165eeb53895SMarkos Chandras "3:"type##_lbu("$1", "2(%2)")"\n\t" \ 1660593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 1670593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 168eeb53895SMarkos Chandras "4:"type##_lbu("$1", "3(%2)")"\n\t" \ 1690593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 1700593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 1710593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 1720593a44cSLeonid Yegoshin ".set\tpop\n" \ 1730593a44cSLeonid Yegoshin "10:\n\t" \ 1740593a44cSLeonid Yegoshin ".insn\n\t" \ 1750593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 1760593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 1770593a44cSLeonid Yegoshin "j\t10b\n\t" \ 1780593a44cSLeonid Yegoshin ".previous\n\t" \ 1790593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 1800593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 1810593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 1820593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 1830593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 1840593a44cSLeonid Yegoshin ".previous" \ 1850593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 1863563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 1873563c32dSMarkos Chandras } while(0) 1883563c32dSMarkos Chandras 189932afdeeSYasha Cherikovsky #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 19034c2f668SLeonid Yegoshin 191eeb53895SMarkos Chandras #define _LoadHWU(addr, value, res, type) \ 1923563c32dSMarkos Chandras do { \ 19334c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 19434c2f668SLeonid Yegoshin ".set\tnoat\n" \ 195eeb53895SMarkos Chandras "1:\t"type##_lbu("%0", "0(%2)")"\n" \ 196eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "1(%2)")"\n\t"\ 19734c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 19834c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 19934c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 20034c2f668SLeonid Yegoshin "3:\n\t" \ 20134c2f668SLeonid Yegoshin ".insn\n\t" \ 20234c2f668SLeonid Yegoshin ".set\tat\n\t" \ 20334c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 20434c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 20534c2f668SLeonid Yegoshin "j\t3b\n\t" \ 20634c2f668SLeonid Yegoshin ".previous\n\t" \ 20734c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 20834c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 20934c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 21034c2f668SLeonid Yegoshin ".previous" \ 21134c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 2123563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 2133563c32dSMarkos Chandras } while(0) 21434c2f668SLeonid Yegoshin 215932afdeeSYasha Cherikovsky #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR 216eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 2173563c32dSMarkos Chandras do { \ 21834c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 219eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "(%2)")"\n" \ 220eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "3(%2)")"\n\t"\ 22134c2f668SLeonid Yegoshin "dsll\t%0, %0, 32\n\t" \ 22234c2f668SLeonid Yegoshin "dsrl\t%0, %0, 32\n\t" \ 22334c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 22434c2f668SLeonid Yegoshin "3:\n\t" \ 22534c2f668SLeonid Yegoshin ".insn\n\t" \ 22634c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 22734c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 22834c2f668SLeonid Yegoshin "j\t3b\n\t" \ 22934c2f668SLeonid Yegoshin ".previous\n\t" \ 23034c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 23134c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 23234c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 23334c2f668SLeonid Yegoshin ".previous" \ 23434c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 2353563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 2363563c32dSMarkos Chandras } while(0) 23734c2f668SLeonid Yegoshin 238eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 2393563c32dSMarkos Chandras do { \ 24034c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 24134c2f668SLeonid Yegoshin "1:\tldl\t%0, (%2)\n" \ 24234c2f668SLeonid Yegoshin "2:\tldr\t%0, 7(%2)\n\t" \ 24334c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 24434c2f668SLeonid Yegoshin "3:\n\t" \ 24534c2f668SLeonid Yegoshin ".insn\n\t" \ 24634c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 24734c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 24834c2f668SLeonid Yegoshin "j\t3b\n\t" \ 24934c2f668SLeonid Yegoshin ".previous\n\t" \ 25034c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 25134c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 25234c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 25334c2f668SLeonid Yegoshin ".previous" \ 25434c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 2553563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 2563563c32dSMarkos Chandras } while(0) 2573563c32dSMarkos Chandras 258932afdeeSYasha Cherikovsky #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 259932afdeeSYasha Cherikovsky /* For CPUs without lwl and ldl instructions */ 260eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 2613563c32dSMarkos Chandras do { \ 2620593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 2630593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 2640593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 265eeb53895SMarkos Chandras "1:"type##_lbu("%0", "0(%2)")"\n\t" \ 266eeb53895SMarkos Chandras "2:"type##_lbu("$1", "1(%2)")"\n\t" \ 2670593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 2680593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 269eeb53895SMarkos Chandras "3:"type##_lbu("$1", "2(%2)")"\n\t" \ 2700593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 2710593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 272eeb53895SMarkos Chandras "4:"type##_lbu("$1", "3(%2)")"\n\t" \ 2730593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 2740593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2750593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 2760593a44cSLeonid Yegoshin ".set\tpop\n" \ 2770593a44cSLeonid Yegoshin "10:\n\t" \ 2780593a44cSLeonid Yegoshin ".insn\n\t" \ 2790593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 2800593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 2810593a44cSLeonid Yegoshin "j\t10b\n\t" \ 2820593a44cSLeonid Yegoshin ".previous\n\t" \ 2830593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 2840593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 2850593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 2860593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 2870593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 2880593a44cSLeonid Yegoshin ".previous" \ 2890593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 2903563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 2913563c32dSMarkos Chandras } while(0) 2920593a44cSLeonid Yegoshin 293eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 2943563c32dSMarkos Chandras do { \ 2950593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 2960593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 2970593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 2980593a44cSLeonid Yegoshin "1:lb\t%0, 0(%2)\n\t" \ 2990593a44cSLeonid Yegoshin "2:lbu\t $1, 1(%2)\n\t" \ 3000593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3010593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3020593a44cSLeonid Yegoshin "3:lbu\t$1, 2(%2)\n\t" \ 3030593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3040593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3050593a44cSLeonid Yegoshin "4:lbu\t$1, 3(%2)\n\t" \ 3060593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3070593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3080593a44cSLeonid Yegoshin "5:lbu\t$1, 4(%2)\n\t" \ 3090593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3100593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3110593a44cSLeonid Yegoshin "6:lbu\t$1, 5(%2)\n\t" \ 3120593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3130593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3140593a44cSLeonid Yegoshin "7:lbu\t$1, 6(%2)\n\t" \ 3150593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3160593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3170593a44cSLeonid Yegoshin "8:lbu\t$1, 7(%2)\n\t" \ 3180593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3190593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3200593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 3210593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 3220593a44cSLeonid Yegoshin "10:\n\t" \ 3230593a44cSLeonid Yegoshin ".insn\n\t" \ 3240593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 3250593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 3260593a44cSLeonid Yegoshin "j\t10b\n\t" \ 3270593a44cSLeonid Yegoshin ".previous\n\t" \ 3280593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 3290593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 3300593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 3310593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 3320593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 3330593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 3340593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 3350593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 3360593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 3370593a44cSLeonid Yegoshin ".previous" \ 3380593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 3393563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 3403563c32dSMarkos Chandras } while(0) 3413563c32dSMarkos Chandras 342932afdeeSYasha Cherikovsky #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 3430593a44cSLeonid Yegoshin 34434c2f668SLeonid Yegoshin 345eeb53895SMarkos Chandras #define _StoreHW(addr, value, res, type) \ 3463563c32dSMarkos Chandras do { \ 34734c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 34834c2f668SLeonid Yegoshin ".set\tnoat\n" \ 349eeb53895SMarkos Chandras "1:\t"type##_sb("%1", "1(%2)")"\n" \ 35034c2f668SLeonid Yegoshin "srl\t$1, %1, 0x8\n" \ 351eeb53895SMarkos Chandras "2:\t"type##_sb("$1", "0(%2)")"\n" \ 35234c2f668SLeonid Yegoshin ".set\tat\n\t" \ 35334c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 35434c2f668SLeonid Yegoshin "3:\n\t" \ 35534c2f668SLeonid Yegoshin ".insn\n\t" \ 35634c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 35734c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 35834c2f668SLeonid Yegoshin "j\t3b\n\t" \ 35934c2f668SLeonid Yegoshin ".previous\n\t" \ 36034c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 36134c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 36234c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 36334c2f668SLeonid Yegoshin ".previous" \ 36434c2f668SLeonid Yegoshin : "=r" (res) \ 3653563c32dSMarkos Chandras : "r" (value), "r" (addr), "i" (-EFAULT));\ 3663563c32dSMarkos Chandras } while(0) 36734c2f668SLeonid Yegoshin 368932afdeeSYasha Cherikovsky #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR 369eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 3703563c32dSMarkos Chandras do { \ 37134c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 372eeb53895SMarkos Chandras "1:\t"type##_swl("%1", "(%2)")"\n" \ 373eeb53895SMarkos Chandras "2:\t"type##_swr("%1", "3(%2)")"\n\t"\ 37434c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 37534c2f668SLeonid Yegoshin "3:\n\t" \ 37634c2f668SLeonid Yegoshin ".insn\n\t" \ 37734c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 37834c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 37934c2f668SLeonid Yegoshin "j\t3b\n\t" \ 38034c2f668SLeonid Yegoshin ".previous\n\t" \ 38134c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 38234c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 38334c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 38434c2f668SLeonid Yegoshin ".previous" \ 38534c2f668SLeonid Yegoshin : "=r" (res) \ 3863563c32dSMarkos Chandras : "r" (value), "r" (addr), "i" (-EFAULT)); \ 3873563c32dSMarkos Chandras } while(0) 38834c2f668SLeonid Yegoshin 389eeb53895SMarkos Chandras #define _StoreDW(addr, value, res) \ 3903563c32dSMarkos Chandras do { \ 39134c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 39234c2f668SLeonid Yegoshin "1:\tsdl\t%1,(%2)\n" \ 39334c2f668SLeonid Yegoshin "2:\tsdr\t%1, 7(%2)\n\t" \ 39434c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 39534c2f668SLeonid Yegoshin "3:\n\t" \ 39634c2f668SLeonid Yegoshin ".insn\n\t" \ 39734c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 39834c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 39934c2f668SLeonid Yegoshin "j\t3b\n\t" \ 40034c2f668SLeonid Yegoshin ".previous\n\t" \ 40134c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 40234c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 40334c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 40434c2f668SLeonid Yegoshin ".previous" \ 40534c2f668SLeonid Yegoshin : "=r" (res) \ 4063563c32dSMarkos Chandras : "r" (value), "r" (addr), "i" (-EFAULT)); \ 4073563c32dSMarkos Chandras } while(0) 4083563c32dSMarkos Chandras 409932afdeeSYasha Cherikovsky #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 410eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 4113563c32dSMarkos Chandras do { \ 4120593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 4130593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 4140593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 415eeb53895SMarkos Chandras "1:"type##_sb("%1", "3(%2)")"\n\t" \ 4160593a44cSLeonid Yegoshin "srl\t$1, %1, 0x8\n\t" \ 417eeb53895SMarkos Chandras "2:"type##_sb("$1", "2(%2)")"\n\t" \ 4180593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 419eeb53895SMarkos Chandras "3:"type##_sb("$1", "1(%2)")"\n\t" \ 4200593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 421eeb53895SMarkos Chandras "4:"type##_sb("$1", "0(%2)")"\n\t" \ 4220593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 4230593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 4240593a44cSLeonid Yegoshin "10:\n\t" \ 4250593a44cSLeonid Yegoshin ".insn\n\t" \ 4260593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 4270593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 4280593a44cSLeonid Yegoshin "j\t10b\n\t" \ 4290593a44cSLeonid Yegoshin ".previous\n\t" \ 4300593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 4310593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 4320593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 4330593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 4340593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 4350593a44cSLeonid Yegoshin ".previous" \ 4360593a44cSLeonid Yegoshin : "=&r" (res) \ 4370593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 4383563c32dSMarkos Chandras : "memory"); \ 4393563c32dSMarkos Chandras } while(0) 44034c2f668SLeonid Yegoshin 441531a6d59SJames Cowgill #define _StoreDW(addr, value, res) \ 4423563c32dSMarkos Chandras do { \ 4430593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 4440593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 4450593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 4460593a44cSLeonid Yegoshin "1:sb\t%1, 7(%2)\n\t" \ 4470593a44cSLeonid Yegoshin "dsrl\t$1, %1, 0x8\n\t" \ 4480593a44cSLeonid Yegoshin "2:sb\t$1, 6(%2)\n\t" \ 4490593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4500593a44cSLeonid Yegoshin "3:sb\t$1, 5(%2)\n\t" \ 4510593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4520593a44cSLeonid Yegoshin "4:sb\t$1, 4(%2)\n\t" \ 4530593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4540593a44cSLeonid Yegoshin "5:sb\t$1, 3(%2)\n\t" \ 4550593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4560593a44cSLeonid Yegoshin "6:sb\t$1, 2(%2)\n\t" \ 4570593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4580593a44cSLeonid Yegoshin "7:sb\t$1, 1(%2)\n\t" \ 4590593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4600593a44cSLeonid Yegoshin "8:sb\t$1, 0(%2)\n\t" \ 4610593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4620593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 4630593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 4640593a44cSLeonid Yegoshin "10:\n\t" \ 4650593a44cSLeonid Yegoshin ".insn\n\t" \ 4660593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 4670593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 4680593a44cSLeonid Yegoshin "j\t10b\n\t" \ 4690593a44cSLeonid Yegoshin ".previous\n\t" \ 4700593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 4710593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 4720593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 4730593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 4740593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 4750593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 4760593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 4770593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 4780593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 4790593a44cSLeonid Yegoshin ".previous" \ 4800593a44cSLeonid Yegoshin : "=&r" (res) \ 4810593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 4823563c32dSMarkos Chandras : "memory"); \ 4833563c32dSMarkos Chandras } while(0) 4843563c32dSMarkos Chandras 485932afdeeSYasha Cherikovsky #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 4860593a44cSLeonid Yegoshin 4870593a44cSLeonid Yegoshin #else /* __BIG_ENDIAN */ 4880593a44cSLeonid Yegoshin 489eeb53895SMarkos Chandras #define _LoadHW(addr, value, res, type) \ 4903563c32dSMarkos Chandras do { \ 49134c2f668SLeonid Yegoshin __asm__ __volatile__ (".set\tnoat\n" \ 492eeb53895SMarkos Chandras "1:\t"type##_lb("%0", "1(%2)")"\n" \ 493eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "0(%2)")"\n\t"\ 49434c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 49534c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 49634c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 49734c2f668SLeonid Yegoshin "3:\t.set\tat\n\t" \ 49834c2f668SLeonid Yegoshin ".insn\n\t" \ 49934c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 50034c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 50134c2f668SLeonid Yegoshin "j\t3b\n\t" \ 50234c2f668SLeonid Yegoshin ".previous\n\t" \ 50334c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 50434c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 50534c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 50634c2f668SLeonid Yegoshin ".previous" \ 50734c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 5083563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 5093563c32dSMarkos Chandras } while(0) 51034c2f668SLeonid Yegoshin 511932afdeeSYasha Cherikovsky #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR 512eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 5133563c32dSMarkos Chandras do { \ 51434c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 515eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "3(%2)")"\n" \ 516eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "(%2)")"\n\t"\ 51734c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 51834c2f668SLeonid Yegoshin "3:\n\t" \ 51934c2f668SLeonid Yegoshin ".insn\n\t" \ 52034c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 52134c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 52234c2f668SLeonid Yegoshin "j\t3b\n\t" \ 52334c2f668SLeonid Yegoshin ".previous\n\t" \ 52434c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 52534c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 52634c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 52734c2f668SLeonid Yegoshin ".previous" \ 52834c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 5293563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 5303563c32dSMarkos Chandras } while(0) 5313563c32dSMarkos Chandras 532932afdeeSYasha Cherikovsky #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 533932afdeeSYasha Cherikovsky /* For CPUs without lwl instruction */ 534eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 5353563c32dSMarkos Chandras do { \ 5360593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 5370593a44cSLeonid Yegoshin ".set\tpush\n" \ 5380593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 539eeb53895SMarkos Chandras "1:"type##_lb("%0", "3(%2)")"\n\t" \ 540eeb53895SMarkos Chandras "2:"type##_lbu("$1", "2(%2)")"\n\t" \ 5410593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 5420593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 543eeb53895SMarkos Chandras "3:"type##_lbu("$1", "1(%2)")"\n\t" \ 5440593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 5450593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 546eeb53895SMarkos Chandras "4:"type##_lbu("$1", "0(%2)")"\n\t" \ 5470593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 5480593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 5490593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 5500593a44cSLeonid Yegoshin ".set\tpop\n" \ 5510593a44cSLeonid Yegoshin "10:\n\t" \ 5520593a44cSLeonid Yegoshin ".insn\n\t" \ 5530593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 5540593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 5550593a44cSLeonid Yegoshin "j\t10b\n\t" \ 5560593a44cSLeonid Yegoshin ".previous\n\t" \ 5570593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 5580593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 5590593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 5600593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 5610593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 5620593a44cSLeonid Yegoshin ".previous" \ 5630593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 5643563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 5653563c32dSMarkos Chandras } while(0) 5663563c32dSMarkos Chandras 567932afdeeSYasha Cherikovsky #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 5680593a44cSLeonid Yegoshin 56934c2f668SLeonid Yegoshin 570eeb53895SMarkos Chandras #define _LoadHWU(addr, value, res, type) \ 5713563c32dSMarkos Chandras do { \ 57234c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 57334c2f668SLeonid Yegoshin ".set\tnoat\n" \ 574eeb53895SMarkos Chandras "1:\t"type##_lbu("%0", "1(%2)")"\n" \ 575eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "0(%2)")"\n\t"\ 57634c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 57734c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 57834c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 57934c2f668SLeonid Yegoshin "3:\n\t" \ 58034c2f668SLeonid Yegoshin ".insn\n\t" \ 58134c2f668SLeonid Yegoshin ".set\tat\n\t" \ 58234c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 58334c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 58434c2f668SLeonid Yegoshin "j\t3b\n\t" \ 58534c2f668SLeonid Yegoshin ".previous\n\t" \ 58634c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 58734c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 58834c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 58934c2f668SLeonid Yegoshin ".previous" \ 59034c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 5913563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 5923563c32dSMarkos Chandras } while(0) 59334c2f668SLeonid Yegoshin 594932afdeeSYasha Cherikovsky #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR 595eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 5963563c32dSMarkos Chandras do { \ 59734c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 598eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "3(%2)")"\n" \ 599eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "(%2)")"\n\t"\ 60034c2f668SLeonid Yegoshin "dsll\t%0, %0, 32\n\t" \ 60134c2f668SLeonid Yegoshin "dsrl\t%0, %0, 32\n\t" \ 60234c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 60334c2f668SLeonid Yegoshin "3:\n\t" \ 60434c2f668SLeonid Yegoshin ".insn\n\t" \ 60534c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 60634c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 60734c2f668SLeonid Yegoshin "j\t3b\n\t" \ 60834c2f668SLeonid Yegoshin ".previous\n\t" \ 60934c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 61034c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 61134c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 61234c2f668SLeonid Yegoshin ".previous" \ 61334c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 6143563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 6153563c32dSMarkos Chandras } while(0) 61634c2f668SLeonid Yegoshin 617eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 6183563c32dSMarkos Chandras do { \ 61934c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 62034c2f668SLeonid Yegoshin "1:\tldl\t%0, 7(%2)\n" \ 62134c2f668SLeonid Yegoshin "2:\tldr\t%0, (%2)\n\t" \ 62234c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 62334c2f668SLeonid Yegoshin "3:\n\t" \ 62434c2f668SLeonid Yegoshin ".insn\n\t" \ 62534c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 62634c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 62734c2f668SLeonid Yegoshin "j\t3b\n\t" \ 62834c2f668SLeonid Yegoshin ".previous\n\t" \ 62934c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 63034c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 63134c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 63234c2f668SLeonid Yegoshin ".previous" \ 63334c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 6343563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 6353563c32dSMarkos Chandras } while(0) 6363563c32dSMarkos Chandras 637932afdeeSYasha Cherikovsky #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 638932afdeeSYasha Cherikovsky /* For CPUs without lwl and ldl instructions */ 639eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 6403563c32dSMarkos Chandras do { \ 6410593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 6420593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 6430593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 644eeb53895SMarkos Chandras "1:"type##_lbu("%0", "3(%2)")"\n\t" \ 645eeb53895SMarkos Chandras "2:"type##_lbu("$1", "2(%2)")"\n\t" \ 6460593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 6470593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 648eeb53895SMarkos Chandras "3:"type##_lbu("$1", "1(%2)")"\n\t" \ 6490593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 6500593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 651eeb53895SMarkos Chandras "4:"type##_lbu("$1", "0(%2)")"\n\t" \ 6520593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 6530593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6540593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 6550593a44cSLeonid Yegoshin ".set\tpop\n" \ 6560593a44cSLeonid Yegoshin "10:\n\t" \ 6570593a44cSLeonid Yegoshin ".insn\n\t" \ 6580593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 6590593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 6600593a44cSLeonid Yegoshin "j\t10b\n\t" \ 6610593a44cSLeonid Yegoshin ".previous\n\t" \ 6620593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 6630593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 6640593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 6650593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 6660593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 6670593a44cSLeonid Yegoshin ".previous" \ 6680593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 6693563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 6703563c32dSMarkos Chandras } while(0) 6710593a44cSLeonid Yegoshin 672eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 6733563c32dSMarkos Chandras do { \ 6740593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 6750593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 6760593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 6770593a44cSLeonid Yegoshin "1:lb\t%0, 7(%2)\n\t" \ 6780593a44cSLeonid Yegoshin "2:lbu\t$1, 6(%2)\n\t" \ 6790593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6800593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6810593a44cSLeonid Yegoshin "3:lbu\t$1, 5(%2)\n\t" \ 6820593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6830593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6840593a44cSLeonid Yegoshin "4:lbu\t$1, 4(%2)\n\t" \ 6850593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6860593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6870593a44cSLeonid Yegoshin "5:lbu\t$1, 3(%2)\n\t" \ 6880593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6890593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6900593a44cSLeonid Yegoshin "6:lbu\t$1, 2(%2)\n\t" \ 6910593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6920593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6930593a44cSLeonid Yegoshin "7:lbu\t$1, 1(%2)\n\t" \ 6940593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6950593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6960593a44cSLeonid Yegoshin "8:lbu\t$1, 0(%2)\n\t" \ 6970593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6980593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6990593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 7000593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 7010593a44cSLeonid Yegoshin "10:\n\t" \ 7020593a44cSLeonid Yegoshin ".insn\n\t" \ 7030593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 7040593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 7050593a44cSLeonid Yegoshin "j\t10b\n\t" \ 7060593a44cSLeonid Yegoshin ".previous\n\t" \ 7070593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 7080593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 7090593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 7100593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 7110593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 7120593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 7130593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 7140593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 7150593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 7160593a44cSLeonid Yegoshin ".previous" \ 7170593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 7183563c32dSMarkos Chandras : "r" (addr), "i" (-EFAULT)); \ 7193563c32dSMarkos Chandras } while(0) 720932afdeeSYasha Cherikovsky #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 72134c2f668SLeonid Yegoshin 722eeb53895SMarkos Chandras #define _StoreHW(addr, value, res, type) \ 7233563c32dSMarkos Chandras do { \ 72434c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 72534c2f668SLeonid Yegoshin ".set\tnoat\n" \ 726eeb53895SMarkos Chandras "1:\t"type##_sb("%1", "0(%2)")"\n" \ 72734c2f668SLeonid Yegoshin "srl\t$1,%1, 0x8\n" \ 728eeb53895SMarkos Chandras "2:\t"type##_sb("$1", "1(%2)")"\n" \ 72934c2f668SLeonid Yegoshin ".set\tat\n\t" \ 73034c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 73134c2f668SLeonid Yegoshin "3:\n\t" \ 73234c2f668SLeonid Yegoshin ".insn\n\t" \ 73334c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 73434c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 73534c2f668SLeonid Yegoshin "j\t3b\n\t" \ 73634c2f668SLeonid Yegoshin ".previous\n\t" \ 73734c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 73834c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 73934c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 74034c2f668SLeonid Yegoshin ".previous" \ 74134c2f668SLeonid Yegoshin : "=r" (res) \ 7423563c32dSMarkos Chandras : "r" (value), "r" (addr), "i" (-EFAULT));\ 7433563c32dSMarkos Chandras } while(0) 7443563c32dSMarkos Chandras 745932afdeeSYasha Cherikovsky #ifdef CONFIG_CPU_HAS_LOAD_STORE_LR 746eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 7473563c32dSMarkos Chandras do { \ 74834c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 749eeb53895SMarkos Chandras "1:\t"type##_swl("%1", "3(%2)")"\n" \ 750eeb53895SMarkos Chandras "2:\t"type##_swr("%1", "(%2)")"\n\t"\ 75134c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 75234c2f668SLeonid Yegoshin "3:\n\t" \ 75334c2f668SLeonid Yegoshin ".insn\n\t" \ 75434c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 75534c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 75634c2f668SLeonid Yegoshin "j\t3b\n\t" \ 75734c2f668SLeonid Yegoshin ".previous\n\t" \ 75834c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 75934c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 76034c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 76134c2f668SLeonid Yegoshin ".previous" \ 76234c2f668SLeonid Yegoshin : "=r" (res) \ 7633563c32dSMarkos Chandras : "r" (value), "r" (addr), "i" (-EFAULT)); \ 7643563c32dSMarkos Chandras } while(0) 76534c2f668SLeonid Yegoshin 766eeb53895SMarkos Chandras #define _StoreDW(addr, value, res) \ 7673563c32dSMarkos Chandras do { \ 76834c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 76934c2f668SLeonid Yegoshin "1:\tsdl\t%1, 7(%2)\n" \ 77034c2f668SLeonid Yegoshin "2:\tsdr\t%1, (%2)\n\t" \ 77134c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 77234c2f668SLeonid Yegoshin "3:\n\t" \ 77334c2f668SLeonid Yegoshin ".insn\n\t" \ 77434c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 77534c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 77634c2f668SLeonid Yegoshin "j\t3b\n\t" \ 77734c2f668SLeonid Yegoshin ".previous\n\t" \ 77834c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 77934c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 78034c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 78134c2f668SLeonid Yegoshin ".previous" \ 78234c2f668SLeonid Yegoshin : "=r" (res) \ 7833563c32dSMarkos Chandras : "r" (value), "r" (addr), "i" (-EFAULT)); \ 7843563c32dSMarkos Chandras } while(0) 7853563c32dSMarkos Chandras 786932afdeeSYasha Cherikovsky #else /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 787932afdeeSYasha Cherikovsky /* For CPUs without swl and sdl instructions */ 788eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 7893563c32dSMarkos Chandras do { \ 7900593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 7910593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 7920593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 793eeb53895SMarkos Chandras "1:"type##_sb("%1", "0(%2)")"\n\t" \ 7940593a44cSLeonid Yegoshin "srl\t$1, %1, 0x8\n\t" \ 795eeb53895SMarkos Chandras "2:"type##_sb("$1", "1(%2)")"\n\t" \ 7960593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 797eeb53895SMarkos Chandras "3:"type##_sb("$1", "2(%2)")"\n\t" \ 7980593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 799eeb53895SMarkos Chandras "4:"type##_sb("$1", "3(%2)")"\n\t" \ 8000593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 8010593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 8020593a44cSLeonid Yegoshin "10:\n\t" \ 8030593a44cSLeonid Yegoshin ".insn\n\t" \ 8040593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 8050593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 8060593a44cSLeonid Yegoshin "j\t10b\n\t" \ 8070593a44cSLeonid Yegoshin ".previous\n\t" \ 8080593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 8090593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 8100593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 8110593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 8120593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 8130593a44cSLeonid Yegoshin ".previous" \ 8140593a44cSLeonid Yegoshin : "=&r" (res) \ 8150593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 8163563c32dSMarkos Chandras : "memory"); \ 8173563c32dSMarkos Chandras } while(0) 8180593a44cSLeonid Yegoshin 819eeb53895SMarkos Chandras #define _StoreDW(addr, value, res) \ 8203563c32dSMarkos Chandras do { \ 8210593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 8220593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 8230593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 8240593a44cSLeonid Yegoshin "1:sb\t%1, 0(%2)\n\t" \ 8250593a44cSLeonid Yegoshin "dsrl\t$1, %1, 0x8\n\t" \ 8260593a44cSLeonid Yegoshin "2:sb\t$1, 1(%2)\n\t" \ 8270593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8280593a44cSLeonid Yegoshin "3:sb\t$1, 2(%2)\n\t" \ 8290593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8300593a44cSLeonid Yegoshin "4:sb\t$1, 3(%2)\n\t" \ 8310593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8320593a44cSLeonid Yegoshin "5:sb\t$1, 4(%2)\n\t" \ 8330593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8340593a44cSLeonid Yegoshin "6:sb\t$1, 5(%2)\n\t" \ 8350593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8360593a44cSLeonid Yegoshin "7:sb\t$1, 6(%2)\n\t" \ 8370593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8380593a44cSLeonid Yegoshin "8:sb\t$1, 7(%2)\n\t" \ 8390593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 8400593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 8410593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 8420593a44cSLeonid Yegoshin "10:\n\t" \ 8430593a44cSLeonid Yegoshin ".insn\n\t" \ 8440593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 8450593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 8460593a44cSLeonid Yegoshin "j\t10b\n\t" \ 8470593a44cSLeonid Yegoshin ".previous\n\t" \ 8480593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 8490593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 8500593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 8510593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 8520593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 8530593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 8540593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 8550593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 8560593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 8570593a44cSLeonid Yegoshin ".previous" \ 8580593a44cSLeonid Yegoshin : "=&r" (res) \ 8590593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 8603563c32dSMarkos Chandras : "memory"); \ 8613563c32dSMarkos Chandras } while(0) 8623563c32dSMarkos Chandras 863932afdeeSYasha Cherikovsky #endif /* !CONFIG_CPU_HAS_LOAD_STORE_LR */ 86434c2f668SLeonid Yegoshin #endif 86534c2f668SLeonid Yegoshin 866eeb53895SMarkos Chandras #define LoadHWU(addr, value, res) _LoadHWU(addr, value, res, kernel) 867eeb53895SMarkos Chandras #define LoadHWUE(addr, value, res) _LoadHWU(addr, value, res, user) 868eeb53895SMarkos Chandras #define LoadWU(addr, value, res) _LoadWU(addr, value, res, kernel) 869eeb53895SMarkos Chandras #define LoadWUE(addr, value, res) _LoadWU(addr, value, res, user) 870eeb53895SMarkos Chandras #define LoadHW(addr, value, res) _LoadHW(addr, value, res, kernel) 871eeb53895SMarkos Chandras #define LoadHWE(addr, value, res) _LoadHW(addr, value, res, user) 872eeb53895SMarkos Chandras #define LoadW(addr, value, res) _LoadW(addr, value, res, kernel) 873eeb53895SMarkos Chandras #define LoadWE(addr, value, res) _LoadW(addr, value, res, user) 874eeb53895SMarkos Chandras #define LoadDW(addr, value, res) _LoadDW(addr, value, res) 875eeb53895SMarkos Chandras 876eeb53895SMarkos Chandras #define StoreHW(addr, value, res) _StoreHW(addr, value, res, kernel) 877eeb53895SMarkos Chandras #define StoreHWE(addr, value, res) _StoreHW(addr, value, res, user) 878eeb53895SMarkos Chandras #define StoreW(addr, value, res) _StoreW(addr, value, res, kernel) 879eeb53895SMarkos Chandras #define StoreWE(addr, value, res) _StoreW(addr, value, res, user) 880eeb53895SMarkos Chandras #define StoreDW(addr, value, res) _StoreDW(addr, value, res) 881eeb53895SMarkos Chandras 8827f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs, 8837f18f151SRalf Baechle void __user *addr, unsigned int __user *pc) 8841da177e4SLinus Torvalds { 885*85164fd8SPaul Burton unsigned long origpc, orig31, value; 8861da177e4SLinus Torvalds union mips_instruction insn; 887*85164fd8SPaul Burton unsigned int res; 888c1771216SLeonid Yegoshin #ifdef CONFIG_EVA 889c1771216SLeonid Yegoshin mm_segment_t seg; 890c1771216SLeonid Yegoshin #endif 89134c2f668SLeonid Yegoshin origpc = (unsigned long)pc; 89234c2f668SLeonid Yegoshin orig31 = regs->regs[31]; 89334c2f668SLeonid Yegoshin 894a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); 8957f788d2dSDeng-Cheng Zhu 8961da177e4SLinus Torvalds /* 8971da177e4SLinus Torvalds * This load never faults. 8981da177e4SLinus Torvalds */ 899fe00f943SRalf Baechle __get_user(insn.word, pc); 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds switch (insn.i_format.opcode) { 9021da177e4SLinus Torvalds /* 9031da177e4SLinus Torvalds * These are instructions that a compiler doesn't generate. We 9041da177e4SLinus Torvalds * can assume therefore that the code is MIPS-aware and 9051da177e4SLinus Torvalds * really buggy. Emulating these instructions would break the 9061da177e4SLinus Torvalds * semantics anyway. 9071da177e4SLinus Torvalds */ 9081da177e4SLinus Torvalds case ll_op: 9091da177e4SLinus Torvalds case lld_op: 9101da177e4SLinus Torvalds case sc_op: 9111da177e4SLinus Torvalds case scd_op: 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds /* 9141da177e4SLinus Torvalds * For these instructions the only way to create an address 9151da177e4SLinus Torvalds * error is an attempted access to kernel/supervisor address 9161da177e4SLinus Torvalds * space. 9171da177e4SLinus Torvalds */ 9181da177e4SLinus Torvalds case ldl_op: 9191da177e4SLinus Torvalds case ldr_op: 9201da177e4SLinus Torvalds case lwl_op: 9211da177e4SLinus Torvalds case lwr_op: 9221da177e4SLinus Torvalds case sdl_op: 9231da177e4SLinus Torvalds case sdr_op: 9241da177e4SLinus Torvalds case swl_op: 9251da177e4SLinus Torvalds case swr_op: 9261da177e4SLinus Torvalds case lb_op: 9271da177e4SLinus Torvalds case lbu_op: 9281da177e4SLinus Torvalds case sb_op: 9291da177e4SLinus Torvalds goto sigbus; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds /* 93234c2f668SLeonid Yegoshin * The remaining opcodes are the ones that are really of 93334c2f668SLeonid Yegoshin * interest. 9341da177e4SLinus Torvalds */ 935c1771216SLeonid Yegoshin case spec3_op: 9363f88ec63SMiodrag Dinic if (insn.dsp_format.func == lx_op) { 9373f88ec63SMiodrag Dinic switch (insn.dsp_format.op) { 9383f88ec63SMiodrag Dinic case lwx_op: 9393f88ec63SMiodrag Dinic if (!access_ok(VERIFY_READ, addr, 4)) 9403f88ec63SMiodrag Dinic goto sigbus; 9413f88ec63SMiodrag Dinic LoadW(addr, value, res); 9423f88ec63SMiodrag Dinic if (res) 9433f88ec63SMiodrag Dinic goto fault; 9443f88ec63SMiodrag Dinic compute_return_epc(regs); 9453f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value; 9463f88ec63SMiodrag Dinic break; 9473f88ec63SMiodrag Dinic case lhx_op: 9483f88ec63SMiodrag Dinic if (!access_ok(VERIFY_READ, addr, 2)) 9493f88ec63SMiodrag Dinic goto sigbus; 9503f88ec63SMiodrag Dinic LoadHW(addr, value, res); 9513f88ec63SMiodrag Dinic if (res) 9523f88ec63SMiodrag Dinic goto fault; 9533f88ec63SMiodrag Dinic compute_return_epc(regs); 9543f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value; 9553f88ec63SMiodrag Dinic break; 9563f88ec63SMiodrag Dinic default: 9573f88ec63SMiodrag Dinic goto sigill; 9583f88ec63SMiodrag Dinic } 9593f88ec63SMiodrag Dinic } 9603f88ec63SMiodrag Dinic #ifdef CONFIG_EVA 9613f88ec63SMiodrag Dinic else { 962c1771216SLeonid Yegoshin /* 9633f88ec63SMiodrag Dinic * we can land here only from kernel accessing user 9643f88ec63SMiodrag Dinic * memory, so we need to "switch" the address limit to 9653f88ec63SMiodrag Dinic * user space, so that address check can work properly. 966c1771216SLeonid Yegoshin */ 967c1771216SLeonid Yegoshin seg = get_fs(); 968c1771216SLeonid Yegoshin set_fs(USER_DS); 969c1771216SLeonid Yegoshin switch (insn.spec3_format.func) { 970c1771216SLeonid Yegoshin case lhe_op: 971c1771216SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) { 972c1771216SLeonid Yegoshin set_fs(seg); 973c1771216SLeonid Yegoshin goto sigbus; 974c1771216SLeonid Yegoshin } 975eeb53895SMarkos Chandras LoadHWE(addr, value, res); 976c1771216SLeonid Yegoshin if (res) { 977c1771216SLeonid Yegoshin set_fs(seg); 978c1771216SLeonid Yegoshin goto fault; 979c1771216SLeonid Yegoshin } 980c1771216SLeonid Yegoshin compute_return_epc(regs); 981c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 982c1771216SLeonid Yegoshin break; 983c1771216SLeonid Yegoshin case lwe_op: 984c1771216SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4)) { 985c1771216SLeonid Yegoshin set_fs(seg); 986c1771216SLeonid Yegoshin goto sigbus; 987c1771216SLeonid Yegoshin } 988eeb53895SMarkos Chandras LoadWE(addr, value, res); 989c1771216SLeonid Yegoshin if (res) { 990c1771216SLeonid Yegoshin set_fs(seg); 991c1771216SLeonid Yegoshin goto fault; 992c1771216SLeonid Yegoshin } 993c1771216SLeonid Yegoshin compute_return_epc(regs); 994c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 995c1771216SLeonid Yegoshin break; 996c1771216SLeonid Yegoshin case lhue_op: 997c1771216SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) { 998c1771216SLeonid Yegoshin set_fs(seg); 999c1771216SLeonid Yegoshin goto sigbus; 1000c1771216SLeonid Yegoshin } 1001eeb53895SMarkos Chandras LoadHWUE(addr, value, res); 1002c1771216SLeonid Yegoshin if (res) { 1003c1771216SLeonid Yegoshin set_fs(seg); 1004c1771216SLeonid Yegoshin goto fault; 1005c1771216SLeonid Yegoshin } 1006c1771216SLeonid Yegoshin compute_return_epc(regs); 1007c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 1008c1771216SLeonid Yegoshin break; 1009c1771216SLeonid Yegoshin case she_op: 1010c1771216SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 2)) { 1011c1771216SLeonid Yegoshin set_fs(seg); 1012c1771216SLeonid Yegoshin goto sigbus; 1013c1771216SLeonid Yegoshin } 1014c1771216SLeonid Yegoshin compute_return_epc(regs); 1015c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt]; 1016eeb53895SMarkos Chandras StoreHWE(addr, value, res); 1017c1771216SLeonid Yegoshin if (res) { 1018c1771216SLeonid Yegoshin set_fs(seg); 1019c1771216SLeonid Yegoshin goto fault; 1020c1771216SLeonid Yegoshin } 1021c1771216SLeonid Yegoshin break; 1022c1771216SLeonid Yegoshin case swe_op: 1023c1771216SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4)) { 1024c1771216SLeonid Yegoshin set_fs(seg); 1025c1771216SLeonid Yegoshin goto sigbus; 1026c1771216SLeonid Yegoshin } 1027c1771216SLeonid Yegoshin compute_return_epc(regs); 1028c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt]; 1029eeb53895SMarkos Chandras StoreWE(addr, value, res); 1030c1771216SLeonid Yegoshin if (res) { 1031c1771216SLeonid Yegoshin set_fs(seg); 1032c1771216SLeonid Yegoshin goto fault; 1033c1771216SLeonid Yegoshin } 1034c1771216SLeonid Yegoshin break; 1035c1771216SLeonid Yegoshin default: 1036c1771216SLeonid Yegoshin set_fs(seg); 1037c1771216SLeonid Yegoshin goto sigill; 1038c1771216SLeonid Yegoshin } 1039c1771216SLeonid Yegoshin set_fs(seg); 10403f88ec63SMiodrag Dinic } 1041c1771216SLeonid Yegoshin #endif 10423f88ec63SMiodrag Dinic break; 10431da177e4SLinus Torvalds case lh_op: 10441da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 10451da177e4SLinus Torvalds goto sigbus; 10461da177e4SLinus Torvalds 104797f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) { 1048db68ce10SAl Viro if (uaccess_kernel()) 104934c2f668SLeonid Yegoshin LoadHW(addr, value, res); 10506eae3548SMarkos Chandras else 10516eae3548SMarkos Chandras LoadHWE(addr, value, res); 10526eae3548SMarkos Chandras } else { 10536eae3548SMarkos Chandras LoadHW(addr, value, res); 10546eae3548SMarkos Chandras } 10556eae3548SMarkos Chandras 10561da177e4SLinus Torvalds if (res) 10571da177e4SLinus Torvalds goto fault; 10587f18f151SRalf Baechle compute_return_epc(regs); 10597f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 10601da177e4SLinus Torvalds break; 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds case lw_op: 10631da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 10641da177e4SLinus Torvalds goto sigbus; 10651da177e4SLinus Torvalds 106697f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) { 1067db68ce10SAl Viro if (uaccess_kernel()) 106834c2f668SLeonid Yegoshin LoadW(addr, value, res); 10696eae3548SMarkos Chandras else 10706eae3548SMarkos Chandras LoadWE(addr, value, res); 10716eae3548SMarkos Chandras } else { 10726eae3548SMarkos Chandras LoadW(addr, value, res); 10736eae3548SMarkos Chandras } 10746eae3548SMarkos Chandras 10751da177e4SLinus Torvalds if (res) 10761da177e4SLinus Torvalds goto fault; 10777f18f151SRalf Baechle compute_return_epc(regs); 10787f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 10791da177e4SLinus Torvalds break; 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds case lhu_op: 10821da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 10831da177e4SLinus Torvalds goto sigbus; 10841da177e4SLinus Torvalds 108597f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) { 1086db68ce10SAl Viro if (uaccess_kernel()) 108734c2f668SLeonid Yegoshin LoadHWU(addr, value, res); 10886eae3548SMarkos Chandras else 10896eae3548SMarkos Chandras LoadHWUE(addr, value, res); 10906eae3548SMarkos Chandras } else { 10916eae3548SMarkos Chandras LoadHWU(addr, value, res); 10926eae3548SMarkos Chandras } 10936eae3548SMarkos Chandras 10941da177e4SLinus Torvalds if (res) 10951da177e4SLinus Torvalds goto fault; 10967f18f151SRalf Baechle compute_return_epc(regs); 10977f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 10981da177e4SLinus Torvalds break; 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds case lwu_op: 1101875d43e7SRalf Baechle #ifdef CONFIG_64BIT 11021da177e4SLinus Torvalds /* 11031da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 11041da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 11051da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 11061da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 11071da177e4SLinus Torvalds * instructions on 32-bit kernels. 11081da177e4SLinus Torvalds */ 11091da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 11101da177e4SLinus Torvalds goto sigbus; 11111da177e4SLinus Torvalds 111234c2f668SLeonid Yegoshin LoadWU(addr, value, res); 11131da177e4SLinus Torvalds if (res) 11141da177e4SLinus Torvalds goto fault; 11157f18f151SRalf Baechle compute_return_epc(regs); 11167f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 11171da177e4SLinus Torvalds break; 1118875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 11211da177e4SLinus Torvalds goto sigill; 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds case ld_op: 1124875d43e7SRalf Baechle #ifdef CONFIG_64BIT 11251da177e4SLinus Torvalds /* 11261da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 11271da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 11281da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 11291da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 11301da177e4SLinus Torvalds * instructions on 32-bit kernels. 11311da177e4SLinus Torvalds */ 11321da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 8)) 11331da177e4SLinus Torvalds goto sigbus; 11341da177e4SLinus Torvalds 113534c2f668SLeonid Yegoshin LoadDW(addr, value, res); 11361da177e4SLinus Torvalds if (res) 11371da177e4SLinus Torvalds goto fault; 11387f18f151SRalf Baechle compute_return_epc(regs); 11397f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 11401da177e4SLinus Torvalds break; 1141875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 11441da177e4SLinus Torvalds goto sigill; 11451da177e4SLinus Torvalds 11461da177e4SLinus Torvalds case sh_op: 11471da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 2)) 11481da177e4SLinus Torvalds goto sigbus; 11491da177e4SLinus Torvalds 115034c2f668SLeonid Yegoshin compute_return_epc(regs); 11511da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 11526eae3548SMarkos Chandras 115397f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) { 1154db68ce10SAl Viro if (uaccess_kernel()) 115534c2f668SLeonid Yegoshin StoreHW(addr, value, res); 11566eae3548SMarkos Chandras else 11576eae3548SMarkos Chandras StoreHWE(addr, value, res); 11586eae3548SMarkos Chandras } else { 11596eae3548SMarkos Chandras StoreHW(addr, value, res); 11606eae3548SMarkos Chandras } 11616eae3548SMarkos Chandras 11621da177e4SLinus Torvalds if (res) 11631da177e4SLinus Torvalds goto fault; 11641da177e4SLinus Torvalds break; 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds case sw_op: 11671da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 4)) 11681da177e4SLinus Torvalds goto sigbus; 11691da177e4SLinus Torvalds 117034c2f668SLeonid Yegoshin compute_return_epc(regs); 11711da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 11726eae3548SMarkos Chandras 117397f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) { 1174db68ce10SAl Viro if (uaccess_kernel()) 117534c2f668SLeonid Yegoshin StoreW(addr, value, res); 11766eae3548SMarkos Chandras else 11776eae3548SMarkos Chandras StoreWE(addr, value, res); 11786eae3548SMarkos Chandras } else { 11796eae3548SMarkos Chandras StoreW(addr, value, res); 11806eae3548SMarkos Chandras } 11816eae3548SMarkos Chandras 11821da177e4SLinus Torvalds if (res) 11831da177e4SLinus Torvalds goto fault; 11841da177e4SLinus Torvalds break; 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds case sd_op: 1187875d43e7SRalf Baechle #ifdef CONFIG_64BIT 11881da177e4SLinus Torvalds /* 11891da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 11901da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 11911da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 11921da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 11931da177e4SLinus Torvalds * instructions on 32-bit kernels. 11941da177e4SLinus Torvalds */ 11951da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 8)) 11961da177e4SLinus Torvalds goto sigbus; 11971da177e4SLinus Torvalds 119834c2f668SLeonid Yegoshin compute_return_epc(regs); 11991da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 120034c2f668SLeonid Yegoshin StoreDW(addr, value, res); 12011da177e4SLinus Torvalds if (res) 12021da177e4SLinus Torvalds goto fault; 12031da177e4SLinus Torvalds break; 1204875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 12071da177e4SLinus Torvalds goto sigill; 12081da177e4SLinus Torvalds 1209*85164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT 1210*85164fd8SPaul Burton 12111da177e4SLinus Torvalds case lwc1_op: 12121da177e4SLinus Torvalds case ldc1_op: 12131da177e4SLinus Torvalds case swc1_op: 12141da177e4SLinus Torvalds case sdc1_op: 1215*85164fd8SPaul Burton case cop1x_op: { 1216*85164fd8SPaul Burton void __user *fault_addr = NULL; 1217*85164fd8SPaul Burton 1218102cedc3SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs); 1219102cedc3SLeonid Yegoshin BUG_ON(!used_math()); 1220102cedc3SLeonid Yegoshin 1221102cedc3SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, 1222102cedc3SLeonid Yegoshin &fault_addr); 1223102cedc3SLeonid Yegoshin own_fpu(1); /* Restore FPU state. */ 1224102cedc3SLeonid Yegoshin 1225102cedc3SLeonid Yegoshin /* Signal if something went wrong. */ 1226304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0); 1227102cedc3SLeonid Yegoshin 1228102cedc3SLeonid Yegoshin if (res == 0) 1229102cedc3SLeonid Yegoshin break; 1230102cedc3SLeonid Yegoshin return; 1231*85164fd8SPaul Burton } 1232*85164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */ 12331da177e4SLinus Torvalds 1234*85164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA 1235*85164fd8SPaul Burton 1236*85164fd8SPaul Burton case msa_op: { 1237*85164fd8SPaul Burton unsigned int wd, preempted; 1238*85164fd8SPaul Burton enum msa_2b_fmt df; 1239*85164fd8SPaul Burton union fpureg *fpr; 1240*85164fd8SPaul Burton 1241e4aa1f15SLeonid Yegoshin if (!cpu_has_msa) 1242e4aa1f15SLeonid Yegoshin goto sigill; 1243e4aa1f15SLeonid Yegoshin 1244e4aa1f15SLeonid Yegoshin /* 1245e4aa1f15SLeonid Yegoshin * If we've reached this point then userland should have taken 1246e4aa1f15SLeonid Yegoshin * the MSA disabled exception & initialised vector context at 1247e4aa1f15SLeonid Yegoshin * some point in the past. 1248e4aa1f15SLeonid Yegoshin */ 1249e4aa1f15SLeonid Yegoshin BUG_ON(!thread_msa_context_live()); 1250e4aa1f15SLeonid Yegoshin 1251e4aa1f15SLeonid Yegoshin df = insn.msa_mi10_format.df; 1252e4aa1f15SLeonid Yegoshin wd = insn.msa_mi10_format.wd; 1253e4aa1f15SLeonid Yegoshin fpr = ¤t->thread.fpu.fpr[wd]; 1254e4aa1f15SLeonid Yegoshin 1255e4aa1f15SLeonid Yegoshin switch (insn.msa_mi10_format.func) { 1256e4aa1f15SLeonid Yegoshin case msa_ld_op: 1257e4aa1f15SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, sizeof(*fpr))) 1258e4aa1f15SLeonid Yegoshin goto sigbus; 1259e4aa1f15SLeonid Yegoshin 1260fa8ff601SPaul Burton do { 1261e4aa1f15SLeonid Yegoshin /* 1262fa8ff601SPaul Burton * If we have live MSA context keep track of 1263fa8ff601SPaul Burton * whether we get preempted in order to avoid 1264fa8ff601SPaul Burton * the register context we load being clobbered 1265fa8ff601SPaul Burton * by the live context as it's saved during 1266fa8ff601SPaul Burton * preemption. If we don't have live context 1267fa8ff601SPaul Burton * then it can't be saved to clobber the value 1268fa8ff601SPaul Burton * we load. 1269e4aa1f15SLeonid Yegoshin */ 1270fa8ff601SPaul Burton preempted = test_thread_flag(TIF_USEDMSA); 1271e4aa1f15SLeonid Yegoshin 1272e4aa1f15SLeonid Yegoshin res = __copy_from_user_inatomic(fpr, addr, 1273e4aa1f15SLeonid Yegoshin sizeof(*fpr)); 1274e4aa1f15SLeonid Yegoshin if (res) 1275e4aa1f15SLeonid Yegoshin goto fault; 1276e4aa1f15SLeonid Yegoshin 1277e4aa1f15SLeonid Yegoshin /* 1278fa8ff601SPaul Burton * Update the hardware register if it is in use 1279fa8ff601SPaul Burton * by the task in this quantum, in order to 1280fa8ff601SPaul Burton * avoid having to save & restore the whole 1281fa8ff601SPaul Burton * vector context. 1282e4aa1f15SLeonid Yegoshin */ 1283fa8ff601SPaul Burton preempt_disable(); 1284fa8ff601SPaul Burton if (test_thread_flag(TIF_USEDMSA)) { 1285e4aa1f15SLeonid Yegoshin write_msa_wr(wd, fpr, df); 1286fa8ff601SPaul Burton preempted = 0; 1287fa8ff601SPaul Burton } 1288e4aa1f15SLeonid Yegoshin preempt_enable(); 1289fa8ff601SPaul Burton } while (preempted); 1290e4aa1f15SLeonid Yegoshin break; 1291e4aa1f15SLeonid Yegoshin 1292e4aa1f15SLeonid Yegoshin case msa_st_op: 1293e4aa1f15SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, sizeof(*fpr))) 1294e4aa1f15SLeonid Yegoshin goto sigbus; 1295e4aa1f15SLeonid Yegoshin 1296e4aa1f15SLeonid Yegoshin /* 1297e4aa1f15SLeonid Yegoshin * Update from the hardware register if it is in use by 1298e4aa1f15SLeonid Yegoshin * the task in this quantum, in order to avoid having to 1299e4aa1f15SLeonid Yegoshin * save & restore the whole vector context. 1300e4aa1f15SLeonid Yegoshin */ 1301e4aa1f15SLeonid Yegoshin preempt_disable(); 1302e4aa1f15SLeonid Yegoshin if (test_thread_flag(TIF_USEDMSA)) 1303e4aa1f15SLeonid Yegoshin read_msa_wr(wd, fpr, df); 1304e4aa1f15SLeonid Yegoshin preempt_enable(); 1305e4aa1f15SLeonid Yegoshin 1306e4aa1f15SLeonid Yegoshin res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr)); 1307e4aa1f15SLeonid Yegoshin if (res) 1308e4aa1f15SLeonid Yegoshin goto fault; 1309e4aa1f15SLeonid Yegoshin break; 1310e4aa1f15SLeonid Yegoshin 1311e4aa1f15SLeonid Yegoshin default: 1312e4aa1f15SLeonid Yegoshin goto sigbus; 1313e4aa1f15SLeonid Yegoshin } 1314e4aa1f15SLeonid Yegoshin 1315e4aa1f15SLeonid Yegoshin compute_return_epc(regs); 1316e4aa1f15SLeonid Yegoshin break; 1317*85164fd8SPaul Burton } 1318*85164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */ 1319e4aa1f15SLeonid Yegoshin 13200593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 13211da177e4SLinus Torvalds /* 132269f3a7deSRalf Baechle * COP2 is available to implementor for application specific use. 132369f3a7deSRalf Baechle * It's up to applications to register a notifier chain and do 132469f3a7deSRalf Baechle * whatever they have to do, including possible sending of signals. 13250593a44cSLeonid Yegoshin * 13260593a44cSLeonid Yegoshin * This instruction has been reallocated in Release 6 13271da177e4SLinus Torvalds */ 132869f3a7deSRalf Baechle case lwc2_op: 132969f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LWC2_OP, regs); 133069f3a7deSRalf Baechle break; 133169f3a7deSRalf Baechle 133269f3a7deSRalf Baechle case ldc2_op: 133369f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LDC2_OP, regs); 133469f3a7deSRalf Baechle break; 133569f3a7deSRalf Baechle 133669f3a7deSRalf Baechle case swc2_op: 133769f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SWC2_OP, regs); 133869f3a7deSRalf Baechle break; 133969f3a7deSRalf Baechle 134069f3a7deSRalf Baechle case sdc2_op: 134169f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SDC2_OP, regs); 134269f3a7deSRalf Baechle break; 13430593a44cSLeonid Yegoshin #endif 13441da177e4SLinus Torvalds default: 13451da177e4SLinus Torvalds /* 13461da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or 13471da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ... 13481da177e4SLinus Torvalds */ 13491da177e4SLinus Torvalds goto sigill; 13501da177e4SLinus Torvalds } 13511da177e4SLinus Torvalds 13526312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 13531da177e4SLinus Torvalds unaligned_instructions++; 13541da177e4SLinus Torvalds #endif 13551da177e4SLinus Torvalds 13567f18f151SRalf Baechle return; 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds fault: 135934c2f668SLeonid Yegoshin /* roll back jump/branch */ 136034c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 136134c2f668SLeonid Yegoshin regs->regs[31] = orig31; 13621da177e4SLinus Torvalds /* Did we have an exception handler installed? */ 13631da177e4SLinus Torvalds if (fixup_exception(regs)) 13647f18f151SRalf Baechle return; 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 1367a6d5ff04SDavid Daney force_sig(SIGSEGV, current); 13681da177e4SLinus Torvalds 13697f18f151SRalf Baechle return; 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds sigbus: 13721da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 1373a6d5ff04SDavid Daney force_sig(SIGBUS, current); 13741da177e4SLinus Torvalds 13757f18f151SRalf Baechle return; 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds sigill: 137834c2f668SLeonid Yegoshin die_if_kernel 137934c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs); 138034c2f668SLeonid Yegoshin force_sig(SIGILL, current); 138134c2f668SLeonid Yegoshin } 138234c2f668SLeonid Yegoshin 138334c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */ 138434c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; 138534c2f668SLeonid Yegoshin 138634c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */ 1387b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; 138834c2f668SLeonid Yegoshin 138974338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs, 139074338805SDavid Daney void __user *addr) 139134c2f668SLeonid Yegoshin { 139234c2f668SLeonid Yegoshin unsigned long value; 139334c2f668SLeonid Yegoshin unsigned int res; 139434c2f668SLeonid Yegoshin int i; 139534c2f668SLeonid Yegoshin unsigned int reg = 0, rvar; 139634c2f668SLeonid Yegoshin unsigned long orig31; 139734c2f668SLeonid Yegoshin u16 __user *pc16; 139834c2f668SLeonid Yegoshin u16 halfword; 139934c2f668SLeonid Yegoshin unsigned int word; 140034c2f668SLeonid Yegoshin unsigned long origpc, contpc; 140134c2f668SLeonid Yegoshin union mips_instruction insn; 140234c2f668SLeonid Yegoshin struct mm_decoded_insn mminsn; 140334c2f668SLeonid Yegoshin 140434c2f668SLeonid Yegoshin origpc = regs->cp0_epc; 140534c2f668SLeonid Yegoshin orig31 = regs->regs[31]; 140634c2f668SLeonid Yegoshin 140734c2f668SLeonid Yegoshin mminsn.micro_mips_mode = 1; 140834c2f668SLeonid Yegoshin 140934c2f668SLeonid Yegoshin /* 141034c2f668SLeonid Yegoshin * This load never faults. 141134c2f668SLeonid Yegoshin */ 141234c2f668SLeonid Yegoshin pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc); 141334c2f668SLeonid Yegoshin __get_user(halfword, pc16); 141434c2f668SLeonid Yegoshin pc16++; 141534c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 2; 141634c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16); 141734c2f668SLeonid Yegoshin mminsn.pc_inc = 2; 141834c2f668SLeonid Yegoshin 141934c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) { 142034c2f668SLeonid Yegoshin __get_user(halfword, pc16); 142134c2f668SLeonid Yegoshin pc16++; 142234c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 4; 142334c2f668SLeonid Yegoshin mminsn.pc_inc = 4; 142434c2f668SLeonid Yegoshin word |= halfword; 142534c2f668SLeonid Yegoshin } 142634c2f668SLeonid Yegoshin mminsn.insn = word; 142734c2f668SLeonid Yegoshin 142834c2f668SLeonid Yegoshin if (get_user(halfword, pc16)) 142934c2f668SLeonid Yegoshin goto fault; 143034c2f668SLeonid Yegoshin mminsn.next_pc_inc = 2; 143134c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16); 143234c2f668SLeonid Yegoshin 143334c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) { 143434c2f668SLeonid Yegoshin pc16++; 143534c2f668SLeonid Yegoshin if (get_user(halfword, pc16)) 143634c2f668SLeonid Yegoshin goto fault; 143734c2f668SLeonid Yegoshin mminsn.next_pc_inc = 4; 143834c2f668SLeonid Yegoshin word |= halfword; 143934c2f668SLeonid Yegoshin } 144034c2f668SLeonid Yegoshin mminsn.next_insn = word; 144134c2f668SLeonid Yegoshin 144234c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.insn); 144334c2f668SLeonid Yegoshin if (mm_isBranchInstr(regs, mminsn, &contpc)) 144434c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.next_insn); 144534c2f668SLeonid Yegoshin 144634c2f668SLeonid Yegoshin /* Parse instruction to find what to do */ 144734c2f668SLeonid Yegoshin 144834c2f668SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 144934c2f668SLeonid Yegoshin 145034c2f668SLeonid Yegoshin case mm_pool32a_op: 145134c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) { 145234c2f668SLeonid Yegoshin case mm_lwxs_op: 145334c2f668SLeonid Yegoshin reg = insn.mm_x_format.rd; 145434c2f668SLeonid Yegoshin goto loadW; 145534c2f668SLeonid Yegoshin } 145634c2f668SLeonid Yegoshin 145734c2f668SLeonid Yegoshin goto sigbus; 145834c2f668SLeonid Yegoshin 145934c2f668SLeonid Yegoshin case mm_pool32b_op: 146034c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) { 146134c2f668SLeonid Yegoshin case mm_lwp_func: 146234c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 146334c2f668SLeonid Yegoshin if (reg == 31) 146434c2f668SLeonid Yegoshin goto sigbus; 146534c2f668SLeonid Yegoshin 146634c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 8)) 146734c2f668SLeonid Yegoshin goto sigbus; 146834c2f668SLeonid Yegoshin 146934c2f668SLeonid Yegoshin LoadW(addr, value, res); 147034c2f668SLeonid Yegoshin if (res) 147134c2f668SLeonid Yegoshin goto fault; 147234c2f668SLeonid Yegoshin regs->regs[reg] = value; 147334c2f668SLeonid Yegoshin addr += 4; 147434c2f668SLeonid Yegoshin LoadW(addr, value, res); 147534c2f668SLeonid Yegoshin if (res) 147634c2f668SLeonid Yegoshin goto fault; 147734c2f668SLeonid Yegoshin regs->regs[reg + 1] = value; 147834c2f668SLeonid Yegoshin goto success; 147934c2f668SLeonid Yegoshin 148034c2f668SLeonid Yegoshin case mm_swp_func: 148134c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 148234c2f668SLeonid Yegoshin if (reg == 31) 148334c2f668SLeonid Yegoshin goto sigbus; 148434c2f668SLeonid Yegoshin 148534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 8)) 148634c2f668SLeonid Yegoshin goto sigbus; 148734c2f668SLeonid Yegoshin 148834c2f668SLeonid Yegoshin value = regs->regs[reg]; 148934c2f668SLeonid Yegoshin StoreW(addr, value, res); 149034c2f668SLeonid Yegoshin if (res) 149134c2f668SLeonid Yegoshin goto fault; 149234c2f668SLeonid Yegoshin addr += 4; 149334c2f668SLeonid Yegoshin value = regs->regs[reg + 1]; 149434c2f668SLeonid Yegoshin StoreW(addr, value, res); 149534c2f668SLeonid Yegoshin if (res) 149634c2f668SLeonid Yegoshin goto fault; 149734c2f668SLeonid Yegoshin goto success; 149834c2f668SLeonid Yegoshin 149934c2f668SLeonid Yegoshin case mm_ldp_func: 150034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 150134c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 150234c2f668SLeonid Yegoshin if (reg == 31) 150334c2f668SLeonid Yegoshin goto sigbus; 150434c2f668SLeonid Yegoshin 150534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 16)) 150634c2f668SLeonid Yegoshin goto sigbus; 150734c2f668SLeonid Yegoshin 150834c2f668SLeonid Yegoshin LoadDW(addr, value, res); 150934c2f668SLeonid Yegoshin if (res) 151034c2f668SLeonid Yegoshin goto fault; 151134c2f668SLeonid Yegoshin regs->regs[reg] = value; 151234c2f668SLeonid Yegoshin addr += 8; 151334c2f668SLeonid Yegoshin LoadDW(addr, value, res); 151434c2f668SLeonid Yegoshin if (res) 151534c2f668SLeonid Yegoshin goto fault; 151634c2f668SLeonid Yegoshin regs->regs[reg + 1] = value; 151734c2f668SLeonid Yegoshin goto success; 151834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 151934c2f668SLeonid Yegoshin 152034c2f668SLeonid Yegoshin goto sigill; 152134c2f668SLeonid Yegoshin 152234c2f668SLeonid Yegoshin case mm_sdp_func: 152334c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 152434c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 152534c2f668SLeonid Yegoshin if (reg == 31) 152634c2f668SLeonid Yegoshin goto sigbus; 152734c2f668SLeonid Yegoshin 152834c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 16)) 152934c2f668SLeonid Yegoshin goto sigbus; 153034c2f668SLeonid Yegoshin 153134c2f668SLeonid Yegoshin value = regs->regs[reg]; 153234c2f668SLeonid Yegoshin StoreDW(addr, value, res); 153334c2f668SLeonid Yegoshin if (res) 153434c2f668SLeonid Yegoshin goto fault; 153534c2f668SLeonid Yegoshin addr += 8; 153634c2f668SLeonid Yegoshin value = regs->regs[reg + 1]; 153734c2f668SLeonid Yegoshin StoreDW(addr, value, res); 153834c2f668SLeonid Yegoshin if (res) 153934c2f668SLeonid Yegoshin goto fault; 154034c2f668SLeonid Yegoshin goto success; 154134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 154234c2f668SLeonid Yegoshin 154334c2f668SLeonid Yegoshin goto sigill; 154434c2f668SLeonid Yegoshin 154534c2f668SLeonid Yegoshin case mm_lwm32_func: 154634c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 154734c2f668SLeonid Yegoshin rvar = reg & 0xf; 154834c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 154934c2f668SLeonid Yegoshin goto sigill; 155034c2f668SLeonid Yegoshin if (reg & 0x10) { 155134c2f668SLeonid Yegoshin if (!access_ok 155234c2f668SLeonid Yegoshin (VERIFY_READ, addr, 4 * (rvar + 1))) 155334c2f668SLeonid Yegoshin goto sigbus; 155434c2f668SLeonid Yegoshin } else { 155534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4 * rvar)) 155634c2f668SLeonid Yegoshin goto sigbus; 155734c2f668SLeonid Yegoshin } 155834c2f668SLeonid Yegoshin if (rvar == 9) 155934c2f668SLeonid Yegoshin rvar = 8; 156034c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 156134c2f668SLeonid Yegoshin LoadW(addr, value, res); 156234c2f668SLeonid Yegoshin if (res) 156334c2f668SLeonid Yegoshin goto fault; 156434c2f668SLeonid Yegoshin addr += 4; 156534c2f668SLeonid Yegoshin regs->regs[i] = value; 156634c2f668SLeonid Yegoshin } 156734c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 156834c2f668SLeonid Yegoshin LoadW(addr, value, res); 156934c2f668SLeonid Yegoshin if (res) 157034c2f668SLeonid Yegoshin goto fault; 157134c2f668SLeonid Yegoshin addr += 4; 157234c2f668SLeonid Yegoshin regs->regs[30] = value; 157334c2f668SLeonid Yegoshin } 157434c2f668SLeonid Yegoshin if (reg & 0x10) { 157534c2f668SLeonid Yegoshin LoadW(addr, value, res); 157634c2f668SLeonid Yegoshin if (res) 157734c2f668SLeonid Yegoshin goto fault; 157834c2f668SLeonid Yegoshin regs->regs[31] = value; 157934c2f668SLeonid Yegoshin } 158034c2f668SLeonid Yegoshin goto success; 158134c2f668SLeonid Yegoshin 158234c2f668SLeonid Yegoshin case mm_swm32_func: 158334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 158434c2f668SLeonid Yegoshin rvar = reg & 0xf; 158534c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 158634c2f668SLeonid Yegoshin goto sigill; 158734c2f668SLeonid Yegoshin if (reg & 0x10) { 158834c2f668SLeonid Yegoshin if (!access_ok 158934c2f668SLeonid Yegoshin (VERIFY_WRITE, addr, 4 * (rvar + 1))) 159034c2f668SLeonid Yegoshin goto sigbus; 159134c2f668SLeonid Yegoshin } else { 159234c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4 * rvar)) 159334c2f668SLeonid Yegoshin goto sigbus; 159434c2f668SLeonid Yegoshin } 159534c2f668SLeonid Yegoshin if (rvar == 9) 159634c2f668SLeonid Yegoshin rvar = 8; 159734c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 159834c2f668SLeonid Yegoshin value = regs->regs[i]; 159934c2f668SLeonid Yegoshin StoreW(addr, value, res); 160034c2f668SLeonid Yegoshin if (res) 160134c2f668SLeonid Yegoshin goto fault; 160234c2f668SLeonid Yegoshin addr += 4; 160334c2f668SLeonid Yegoshin } 160434c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 160534c2f668SLeonid Yegoshin value = regs->regs[30]; 160634c2f668SLeonid Yegoshin StoreW(addr, value, res); 160734c2f668SLeonid Yegoshin if (res) 160834c2f668SLeonid Yegoshin goto fault; 160934c2f668SLeonid Yegoshin addr += 4; 161034c2f668SLeonid Yegoshin } 161134c2f668SLeonid Yegoshin if (reg & 0x10) { 161234c2f668SLeonid Yegoshin value = regs->regs[31]; 161334c2f668SLeonid Yegoshin StoreW(addr, value, res); 161434c2f668SLeonid Yegoshin if (res) 161534c2f668SLeonid Yegoshin goto fault; 161634c2f668SLeonid Yegoshin } 161734c2f668SLeonid Yegoshin goto success; 161834c2f668SLeonid Yegoshin 161934c2f668SLeonid Yegoshin case mm_ldm_func: 162034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 162134c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 162234c2f668SLeonid Yegoshin rvar = reg & 0xf; 162334c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 162434c2f668SLeonid Yegoshin goto sigill; 162534c2f668SLeonid Yegoshin if (reg & 0x10) { 162634c2f668SLeonid Yegoshin if (!access_ok 162734c2f668SLeonid Yegoshin (VERIFY_READ, addr, 8 * (rvar + 1))) 162834c2f668SLeonid Yegoshin goto sigbus; 162934c2f668SLeonid Yegoshin } else { 163034c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 8 * rvar)) 163134c2f668SLeonid Yegoshin goto sigbus; 163234c2f668SLeonid Yegoshin } 163334c2f668SLeonid Yegoshin if (rvar == 9) 163434c2f668SLeonid Yegoshin rvar = 8; 163534c2f668SLeonid Yegoshin 163634c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 163734c2f668SLeonid Yegoshin LoadDW(addr, value, res); 163834c2f668SLeonid Yegoshin if (res) 163934c2f668SLeonid Yegoshin goto fault; 164034c2f668SLeonid Yegoshin addr += 4; 164134c2f668SLeonid Yegoshin regs->regs[i] = value; 164234c2f668SLeonid Yegoshin } 164334c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 164434c2f668SLeonid Yegoshin LoadDW(addr, value, res); 164534c2f668SLeonid Yegoshin if (res) 164634c2f668SLeonid Yegoshin goto fault; 164734c2f668SLeonid Yegoshin addr += 8; 164834c2f668SLeonid Yegoshin regs->regs[30] = value; 164934c2f668SLeonid Yegoshin } 165034c2f668SLeonid Yegoshin if (reg & 0x10) { 165134c2f668SLeonid Yegoshin LoadDW(addr, value, res); 165234c2f668SLeonid Yegoshin if (res) 165334c2f668SLeonid Yegoshin goto fault; 165434c2f668SLeonid Yegoshin regs->regs[31] = value; 165534c2f668SLeonid Yegoshin } 165634c2f668SLeonid Yegoshin goto success; 165734c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 165834c2f668SLeonid Yegoshin 165934c2f668SLeonid Yegoshin goto sigill; 166034c2f668SLeonid Yegoshin 166134c2f668SLeonid Yegoshin case mm_sdm_func: 166234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 166334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 166434c2f668SLeonid Yegoshin rvar = reg & 0xf; 166534c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 166634c2f668SLeonid Yegoshin goto sigill; 166734c2f668SLeonid Yegoshin if (reg & 0x10) { 166834c2f668SLeonid Yegoshin if (!access_ok 166934c2f668SLeonid Yegoshin (VERIFY_WRITE, addr, 8 * (rvar + 1))) 167034c2f668SLeonid Yegoshin goto sigbus; 167134c2f668SLeonid Yegoshin } else { 167234c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 8 * rvar)) 167334c2f668SLeonid Yegoshin goto sigbus; 167434c2f668SLeonid Yegoshin } 167534c2f668SLeonid Yegoshin if (rvar == 9) 167634c2f668SLeonid Yegoshin rvar = 8; 167734c2f668SLeonid Yegoshin 167834c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 167934c2f668SLeonid Yegoshin value = regs->regs[i]; 168034c2f668SLeonid Yegoshin StoreDW(addr, value, res); 168134c2f668SLeonid Yegoshin if (res) 168234c2f668SLeonid Yegoshin goto fault; 168334c2f668SLeonid Yegoshin addr += 8; 168434c2f668SLeonid Yegoshin } 168534c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 168634c2f668SLeonid Yegoshin value = regs->regs[30]; 168734c2f668SLeonid Yegoshin StoreDW(addr, value, res); 168834c2f668SLeonid Yegoshin if (res) 168934c2f668SLeonid Yegoshin goto fault; 169034c2f668SLeonid Yegoshin addr += 8; 169134c2f668SLeonid Yegoshin } 169234c2f668SLeonid Yegoshin if (reg & 0x10) { 169334c2f668SLeonid Yegoshin value = regs->regs[31]; 169434c2f668SLeonid Yegoshin StoreDW(addr, value, res); 169534c2f668SLeonid Yegoshin if (res) 169634c2f668SLeonid Yegoshin goto fault; 169734c2f668SLeonid Yegoshin } 169834c2f668SLeonid Yegoshin goto success; 169934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 170034c2f668SLeonid Yegoshin 170134c2f668SLeonid Yegoshin goto sigill; 170234c2f668SLeonid Yegoshin 170334c2f668SLeonid Yegoshin /* LWC2, SWC2, LDC2, SDC2 are not serviced */ 170434c2f668SLeonid Yegoshin } 170534c2f668SLeonid Yegoshin 170634c2f668SLeonid Yegoshin goto sigbus; 170734c2f668SLeonid Yegoshin 170834c2f668SLeonid Yegoshin case mm_pool32c_op: 170934c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) { 171034c2f668SLeonid Yegoshin case mm_lwu_func: 171134c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 171234c2f668SLeonid Yegoshin goto loadWU; 171334c2f668SLeonid Yegoshin } 171434c2f668SLeonid Yegoshin 171534c2f668SLeonid Yegoshin /* LL,SC,LLD,SCD are not serviced */ 171634c2f668SLeonid Yegoshin goto sigbus; 171734c2f668SLeonid Yegoshin 1718*85164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT 171934c2f668SLeonid Yegoshin case mm_pool32f_op: 172034c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) { 172134c2f668SLeonid Yegoshin case mm_lwxc1_func: 172234c2f668SLeonid Yegoshin case mm_swxc1_func: 172334c2f668SLeonid Yegoshin case mm_ldxc1_func: 172434c2f668SLeonid Yegoshin case mm_sdxc1_func: 172534c2f668SLeonid Yegoshin goto fpu_emul; 172634c2f668SLeonid Yegoshin } 172734c2f668SLeonid Yegoshin 172834c2f668SLeonid Yegoshin goto sigbus; 172934c2f668SLeonid Yegoshin 173034c2f668SLeonid Yegoshin case mm_ldc132_op: 173134c2f668SLeonid Yegoshin case mm_sdc132_op: 173234c2f668SLeonid Yegoshin case mm_lwc132_op: 1733*85164fd8SPaul Burton case mm_swc132_op: { 1734*85164fd8SPaul Burton void __user *fault_addr = NULL; 1735*85164fd8SPaul Burton 173634c2f668SLeonid Yegoshin fpu_emul: 173734c2f668SLeonid Yegoshin /* roll back jump/branch */ 173834c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 173934c2f668SLeonid Yegoshin regs->regs[31] = orig31; 174034c2f668SLeonid Yegoshin 174134c2f668SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs); 174234c2f668SLeonid Yegoshin BUG_ON(!used_math()); 174334c2f668SLeonid Yegoshin BUG_ON(!is_fpu_owner()); 174434c2f668SLeonid Yegoshin 174534c2f668SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, 174634c2f668SLeonid Yegoshin &fault_addr); 174734c2f668SLeonid Yegoshin own_fpu(1); /* restore FPU state */ 174834c2f668SLeonid Yegoshin 174934c2f668SLeonid Yegoshin /* If something went wrong, signal */ 1750304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0); 175134c2f668SLeonid Yegoshin 175234c2f668SLeonid Yegoshin if (res == 0) 175334c2f668SLeonid Yegoshin goto success; 175434c2f668SLeonid Yegoshin return; 1755*85164fd8SPaul Burton } 1756*85164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */ 175734c2f668SLeonid Yegoshin 175834c2f668SLeonid Yegoshin case mm_lh32_op: 175934c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 176034c2f668SLeonid Yegoshin goto loadHW; 176134c2f668SLeonid Yegoshin 176234c2f668SLeonid Yegoshin case mm_lhu32_op: 176334c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 176434c2f668SLeonid Yegoshin goto loadHWU; 176534c2f668SLeonid Yegoshin 176634c2f668SLeonid Yegoshin case mm_lw32_op: 176734c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 176834c2f668SLeonid Yegoshin goto loadW; 176934c2f668SLeonid Yegoshin 177034c2f668SLeonid Yegoshin case mm_sh32_op: 177134c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 177234c2f668SLeonid Yegoshin goto storeHW; 177334c2f668SLeonid Yegoshin 177434c2f668SLeonid Yegoshin case mm_sw32_op: 177534c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 177634c2f668SLeonid Yegoshin goto storeW; 177734c2f668SLeonid Yegoshin 177834c2f668SLeonid Yegoshin case mm_ld32_op: 177934c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 178034c2f668SLeonid Yegoshin goto loadDW; 178134c2f668SLeonid Yegoshin 178234c2f668SLeonid Yegoshin case mm_sd32_op: 178334c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 178434c2f668SLeonid Yegoshin goto storeDW; 178534c2f668SLeonid Yegoshin 178634c2f668SLeonid Yegoshin case mm_pool16c_op: 178734c2f668SLeonid Yegoshin switch (insn.mm16_m_format.func) { 178834c2f668SLeonid Yegoshin case mm_lwm16_op: 178934c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist; 179034c2f668SLeonid Yegoshin rvar = reg + 1; 179134c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4 * rvar)) 179234c2f668SLeonid Yegoshin goto sigbus; 179334c2f668SLeonid Yegoshin 179434c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 179534c2f668SLeonid Yegoshin LoadW(addr, value, res); 179634c2f668SLeonid Yegoshin if (res) 179734c2f668SLeonid Yegoshin goto fault; 179834c2f668SLeonid Yegoshin addr += 4; 179934c2f668SLeonid Yegoshin regs->regs[i] = value; 180034c2f668SLeonid Yegoshin } 180134c2f668SLeonid Yegoshin LoadW(addr, value, res); 180234c2f668SLeonid Yegoshin if (res) 180334c2f668SLeonid Yegoshin goto fault; 180434c2f668SLeonid Yegoshin regs->regs[31] = value; 180534c2f668SLeonid Yegoshin 180634c2f668SLeonid Yegoshin goto success; 180734c2f668SLeonid Yegoshin 180834c2f668SLeonid Yegoshin case mm_swm16_op: 180934c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist; 181034c2f668SLeonid Yegoshin rvar = reg + 1; 181134c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4 * rvar)) 181234c2f668SLeonid Yegoshin goto sigbus; 181334c2f668SLeonid Yegoshin 181434c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 181534c2f668SLeonid Yegoshin value = regs->regs[i]; 181634c2f668SLeonid Yegoshin StoreW(addr, value, res); 181734c2f668SLeonid Yegoshin if (res) 181834c2f668SLeonid Yegoshin goto fault; 181934c2f668SLeonid Yegoshin addr += 4; 182034c2f668SLeonid Yegoshin } 182134c2f668SLeonid Yegoshin value = regs->regs[31]; 182234c2f668SLeonid Yegoshin StoreW(addr, value, res); 182334c2f668SLeonid Yegoshin if (res) 182434c2f668SLeonid Yegoshin goto fault; 182534c2f668SLeonid Yegoshin 182634c2f668SLeonid Yegoshin goto success; 182734c2f668SLeonid Yegoshin 182834c2f668SLeonid Yegoshin } 182934c2f668SLeonid Yegoshin 183034c2f668SLeonid Yegoshin goto sigbus; 183134c2f668SLeonid Yegoshin 183234c2f668SLeonid Yegoshin case mm_lhu16_op: 183334c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt]; 183434c2f668SLeonid Yegoshin goto loadHWU; 183534c2f668SLeonid Yegoshin 183634c2f668SLeonid Yegoshin case mm_lw16_op: 183734c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt]; 183834c2f668SLeonid Yegoshin goto loadW; 183934c2f668SLeonid Yegoshin 184034c2f668SLeonid Yegoshin case mm_sh16_op: 184134c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt]; 184234c2f668SLeonid Yegoshin goto storeHW; 184334c2f668SLeonid Yegoshin 184434c2f668SLeonid Yegoshin case mm_sw16_op: 184534c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt]; 184634c2f668SLeonid Yegoshin goto storeW; 184734c2f668SLeonid Yegoshin 184834c2f668SLeonid Yegoshin case mm_lwsp16_op: 184934c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt; 185034c2f668SLeonid Yegoshin goto loadW; 185134c2f668SLeonid Yegoshin 185234c2f668SLeonid Yegoshin case mm_swsp16_op: 185334c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt; 185434c2f668SLeonid Yegoshin goto storeW; 185534c2f668SLeonid Yegoshin 185634c2f668SLeonid Yegoshin case mm_lwgp16_op: 185734c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_r3_format.rt]; 185834c2f668SLeonid Yegoshin goto loadW; 185934c2f668SLeonid Yegoshin 186034c2f668SLeonid Yegoshin default: 186134c2f668SLeonid Yegoshin goto sigill; 186234c2f668SLeonid Yegoshin } 186334c2f668SLeonid Yegoshin 186434c2f668SLeonid Yegoshin loadHW: 186534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) 186634c2f668SLeonid Yegoshin goto sigbus; 186734c2f668SLeonid Yegoshin 186834c2f668SLeonid Yegoshin LoadHW(addr, value, res); 186934c2f668SLeonid Yegoshin if (res) 187034c2f668SLeonid Yegoshin goto fault; 187134c2f668SLeonid Yegoshin regs->regs[reg] = value; 187234c2f668SLeonid Yegoshin goto success; 187334c2f668SLeonid Yegoshin 187434c2f668SLeonid Yegoshin loadHWU: 187534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) 187634c2f668SLeonid Yegoshin goto sigbus; 187734c2f668SLeonid Yegoshin 187834c2f668SLeonid Yegoshin LoadHWU(addr, value, res); 187934c2f668SLeonid Yegoshin if (res) 188034c2f668SLeonid Yegoshin goto fault; 188134c2f668SLeonid Yegoshin regs->regs[reg] = value; 188234c2f668SLeonid Yegoshin goto success; 188334c2f668SLeonid Yegoshin 188434c2f668SLeonid Yegoshin loadW: 188534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4)) 188634c2f668SLeonid Yegoshin goto sigbus; 188734c2f668SLeonid Yegoshin 188834c2f668SLeonid Yegoshin LoadW(addr, value, res); 188934c2f668SLeonid Yegoshin if (res) 189034c2f668SLeonid Yegoshin goto fault; 189134c2f668SLeonid Yegoshin regs->regs[reg] = value; 189234c2f668SLeonid Yegoshin goto success; 189334c2f668SLeonid Yegoshin 189434c2f668SLeonid Yegoshin loadWU: 189534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 189634c2f668SLeonid Yegoshin /* 189734c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 189834c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 189934c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 190034c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 190134c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 190234c2f668SLeonid Yegoshin */ 190334c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4)) 190434c2f668SLeonid Yegoshin goto sigbus; 190534c2f668SLeonid Yegoshin 190634c2f668SLeonid Yegoshin LoadWU(addr, value, res); 190734c2f668SLeonid Yegoshin if (res) 190834c2f668SLeonid Yegoshin goto fault; 190934c2f668SLeonid Yegoshin regs->regs[reg] = value; 191034c2f668SLeonid Yegoshin goto success; 191134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 191234c2f668SLeonid Yegoshin 191334c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 191434c2f668SLeonid Yegoshin goto sigill; 191534c2f668SLeonid Yegoshin 191634c2f668SLeonid Yegoshin loadDW: 191734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 191834c2f668SLeonid Yegoshin /* 191934c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 192034c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 192134c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 192234c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 192334c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 192434c2f668SLeonid Yegoshin */ 192534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 8)) 192634c2f668SLeonid Yegoshin goto sigbus; 192734c2f668SLeonid Yegoshin 192834c2f668SLeonid Yegoshin LoadDW(addr, value, res); 192934c2f668SLeonid Yegoshin if (res) 193034c2f668SLeonid Yegoshin goto fault; 193134c2f668SLeonid Yegoshin regs->regs[reg] = value; 193234c2f668SLeonid Yegoshin goto success; 193334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 193434c2f668SLeonid Yegoshin 193534c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 193634c2f668SLeonid Yegoshin goto sigill; 193734c2f668SLeonid Yegoshin 193834c2f668SLeonid Yegoshin storeHW: 193934c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 2)) 194034c2f668SLeonid Yegoshin goto sigbus; 194134c2f668SLeonid Yegoshin 194234c2f668SLeonid Yegoshin value = regs->regs[reg]; 194334c2f668SLeonid Yegoshin StoreHW(addr, value, res); 194434c2f668SLeonid Yegoshin if (res) 194534c2f668SLeonid Yegoshin goto fault; 194634c2f668SLeonid Yegoshin goto success; 194734c2f668SLeonid Yegoshin 194834c2f668SLeonid Yegoshin storeW: 194934c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4)) 195034c2f668SLeonid Yegoshin goto sigbus; 195134c2f668SLeonid Yegoshin 195234c2f668SLeonid Yegoshin value = regs->regs[reg]; 195334c2f668SLeonid Yegoshin StoreW(addr, value, res); 195434c2f668SLeonid Yegoshin if (res) 195534c2f668SLeonid Yegoshin goto fault; 195634c2f668SLeonid Yegoshin goto success; 195734c2f668SLeonid Yegoshin 195834c2f668SLeonid Yegoshin storeDW: 195934c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 196034c2f668SLeonid Yegoshin /* 196134c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 196234c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 196334c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 196434c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 196534c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 196634c2f668SLeonid Yegoshin */ 196734c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 8)) 196834c2f668SLeonid Yegoshin goto sigbus; 196934c2f668SLeonid Yegoshin 197034c2f668SLeonid Yegoshin value = regs->regs[reg]; 197134c2f668SLeonid Yegoshin StoreDW(addr, value, res); 197234c2f668SLeonid Yegoshin if (res) 197334c2f668SLeonid Yegoshin goto fault; 197434c2f668SLeonid Yegoshin goto success; 197534c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 197634c2f668SLeonid Yegoshin 197734c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 197834c2f668SLeonid Yegoshin goto sigill; 197934c2f668SLeonid Yegoshin 198034c2f668SLeonid Yegoshin success: 198134c2f668SLeonid Yegoshin regs->cp0_epc = contpc; /* advance or branch */ 198234c2f668SLeonid Yegoshin 198334c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS 198434c2f668SLeonid Yegoshin unaligned_instructions++; 198534c2f668SLeonid Yegoshin #endif 198634c2f668SLeonid Yegoshin return; 198734c2f668SLeonid Yegoshin 198834c2f668SLeonid Yegoshin fault: 198934c2f668SLeonid Yegoshin /* roll back jump/branch */ 199034c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 199134c2f668SLeonid Yegoshin regs->regs[31] = orig31; 199234c2f668SLeonid Yegoshin /* Did we have an exception handler installed? */ 199334c2f668SLeonid Yegoshin if (fixup_exception(regs)) 199434c2f668SLeonid Yegoshin return; 199534c2f668SLeonid Yegoshin 199634c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs); 199734c2f668SLeonid Yegoshin force_sig(SIGSEGV, current); 199834c2f668SLeonid Yegoshin 199934c2f668SLeonid Yegoshin return; 200034c2f668SLeonid Yegoshin 200134c2f668SLeonid Yegoshin sigbus: 200234c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs); 200334c2f668SLeonid Yegoshin force_sig(SIGBUS, current); 200434c2f668SLeonid Yegoshin 200534c2f668SLeonid Yegoshin return; 200634c2f668SLeonid Yegoshin 200734c2f668SLeonid Yegoshin sigill: 200834c2f668SLeonid Yegoshin die_if_kernel 200934c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs); 2010a6d5ff04SDavid Daney force_sig(SIGILL, current); 20111da177e4SLinus Torvalds } 20121da177e4SLinus Torvalds 2013451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr) 2014451b001bSSteven J. Hill { 2015451b001bSSteven J. Hill unsigned long value; 2016451b001bSSteven J. Hill unsigned int res; 2017451b001bSSteven J. Hill int reg; 2018451b001bSSteven J. Hill unsigned long orig31; 2019451b001bSSteven J. Hill u16 __user *pc16; 2020451b001bSSteven J. Hill unsigned long origpc; 2021451b001bSSteven J. Hill union mips16e_instruction mips16inst, oldinst; 2022f3235d32SMaciej W. Rozycki unsigned int opcode; 2023f3235d32SMaciej W. Rozycki int extended = 0; 2024451b001bSSteven J. Hill 2025451b001bSSteven J. Hill origpc = regs->cp0_epc; 2026451b001bSSteven J. Hill orig31 = regs->regs[31]; 2027451b001bSSteven J. Hill pc16 = (unsigned short __user *)msk_isa16_mode(origpc); 2028451b001bSSteven J. Hill /* 2029451b001bSSteven J. Hill * This load never faults. 2030451b001bSSteven J. Hill */ 2031451b001bSSteven J. Hill __get_user(mips16inst.full, pc16); 2032451b001bSSteven J. Hill oldinst = mips16inst; 2033451b001bSSteven J. Hill 2034451b001bSSteven J. Hill /* skip EXTEND instruction */ 2035451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_extend_op) { 2036f3235d32SMaciej W. Rozycki extended = 1; 2037451b001bSSteven J. Hill pc16++; 2038451b001bSSteven J. Hill __get_user(mips16inst.full, pc16); 2039451b001bSSteven J. Hill } else if (delay_slot(regs)) { 2040451b001bSSteven J. Hill /* skip jump instructions */ 2041451b001bSSteven J. Hill /* JAL/JALX are 32 bits but have OPCODE in first short int */ 2042451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_jal_op) 2043451b001bSSteven J. Hill pc16++; 2044451b001bSSteven J. Hill pc16++; 2045451b001bSSteven J. Hill if (get_user(mips16inst.full, pc16)) 2046451b001bSSteven J. Hill goto sigbus; 2047451b001bSSteven J. Hill } 2048451b001bSSteven J. Hill 2049f3235d32SMaciej W. Rozycki opcode = mips16inst.ri.opcode; 2050f3235d32SMaciej W. Rozycki switch (opcode) { 2051451b001bSSteven J. Hill case MIPS16e_i64_op: /* I64 or RI64 instruction */ 2052451b001bSSteven J. Hill switch (mips16inst.i64.func) { /* I64/RI64 func field check */ 2053451b001bSSteven J. Hill case MIPS16e_ldpc_func: 2054451b001bSSteven J. Hill case MIPS16e_ldsp_func: 2055451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry]; 2056451b001bSSteven J. Hill goto loadDW; 2057451b001bSSteven J. Hill 2058451b001bSSteven J. Hill case MIPS16e_sdsp_func: 2059451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry]; 2060451b001bSSteven J. Hill goto writeDW; 2061451b001bSSteven J. Hill 2062451b001bSSteven J. Hill case MIPS16e_sdrasp_func: 2063451b001bSSteven J. Hill reg = 29; /* GPRSP */ 2064451b001bSSteven J. Hill goto writeDW; 2065451b001bSSteven J. Hill } 2066451b001bSSteven J. Hill 2067451b001bSSteven J. Hill goto sigbus; 2068451b001bSSteven J. Hill 2069451b001bSSteven J. Hill case MIPS16e_swsp_op: 2070f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx]; 2071f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2) 2072f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) { 2073f3235d32SMaciej W. Rozycki case 0: /* SWSP */ 2074f3235d32SMaciej W. Rozycki case 1: /* SWGP */ 2075f3235d32SMaciej W. Rozycki break; 2076f3235d32SMaciej W. Rozycki case 2: /* SHGP */ 2077f3235d32SMaciej W. Rozycki opcode = MIPS16e_sh_op; 2078f3235d32SMaciej W. Rozycki break; 2079f3235d32SMaciej W. Rozycki default: 2080f3235d32SMaciej W. Rozycki goto sigbus; 2081f3235d32SMaciej W. Rozycki } 2082f3235d32SMaciej W. Rozycki break; 2083f3235d32SMaciej W. Rozycki 2084451b001bSSteven J. Hill case MIPS16e_lwpc_op: 2085f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx]; 2086f3235d32SMaciej W. Rozycki break; 2087f3235d32SMaciej W. Rozycki 2088451b001bSSteven J. Hill case MIPS16e_lwsp_op: 2089451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri.rx]; 2090f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2) 2091f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) { 2092f3235d32SMaciej W. Rozycki case 0: /* LWSP */ 2093f3235d32SMaciej W. Rozycki case 1: /* LWGP */ 2094f3235d32SMaciej W. Rozycki break; 2095f3235d32SMaciej W. Rozycki case 2: /* LHGP */ 2096f3235d32SMaciej W. Rozycki opcode = MIPS16e_lh_op; 2097f3235d32SMaciej W. Rozycki break; 2098f3235d32SMaciej W. Rozycki case 4: /* LHUGP */ 2099f3235d32SMaciej W. Rozycki opcode = MIPS16e_lhu_op; 2100f3235d32SMaciej W. Rozycki break; 2101f3235d32SMaciej W. Rozycki default: 2102f3235d32SMaciej W. Rozycki goto sigbus; 2103f3235d32SMaciej W. Rozycki } 2104451b001bSSteven J. Hill break; 2105451b001bSSteven J. Hill 2106451b001bSSteven J. Hill case MIPS16e_i8_op: 2107451b001bSSteven J. Hill if (mips16inst.i8.func != MIPS16e_swrasp_func) 2108451b001bSSteven J. Hill goto sigbus; 2109451b001bSSteven J. Hill reg = 29; /* GPRSP */ 2110451b001bSSteven J. Hill break; 2111451b001bSSteven J. Hill 2112451b001bSSteven J. Hill default: 2113451b001bSSteven J. Hill reg = reg16to32[mips16inst.rri.ry]; 2114451b001bSSteven J. Hill break; 2115451b001bSSteven J. Hill } 2116451b001bSSteven J. Hill 2117f3235d32SMaciej W. Rozycki switch (opcode) { 2118451b001bSSteven J. Hill 2119451b001bSSteven J. Hill case MIPS16e_lb_op: 2120451b001bSSteven J. Hill case MIPS16e_lbu_op: 2121451b001bSSteven J. Hill case MIPS16e_sb_op: 2122451b001bSSteven J. Hill goto sigbus; 2123451b001bSSteven J. Hill 2124451b001bSSteven J. Hill case MIPS16e_lh_op: 2125451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 2)) 2126451b001bSSteven J. Hill goto sigbus; 2127451b001bSSteven J. Hill 2128451b001bSSteven J. Hill LoadHW(addr, value, res); 2129451b001bSSteven J. Hill if (res) 2130451b001bSSteven J. Hill goto fault; 2131451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2132451b001bSSteven J. Hill regs->regs[reg] = value; 2133451b001bSSteven J. Hill break; 2134451b001bSSteven J. Hill 2135451b001bSSteven J. Hill case MIPS16e_lhu_op: 2136451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 2)) 2137451b001bSSteven J. Hill goto sigbus; 2138451b001bSSteven J. Hill 2139451b001bSSteven J. Hill LoadHWU(addr, value, res); 2140451b001bSSteven J. Hill if (res) 2141451b001bSSteven J. Hill goto fault; 2142451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2143451b001bSSteven J. Hill regs->regs[reg] = value; 2144451b001bSSteven J. Hill break; 2145451b001bSSteven J. Hill 2146451b001bSSteven J. Hill case MIPS16e_lw_op: 2147451b001bSSteven J. Hill case MIPS16e_lwpc_op: 2148451b001bSSteven J. Hill case MIPS16e_lwsp_op: 2149451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 4)) 2150451b001bSSteven J. Hill goto sigbus; 2151451b001bSSteven J. Hill 2152451b001bSSteven J. Hill LoadW(addr, value, res); 2153451b001bSSteven J. Hill if (res) 2154451b001bSSteven J. Hill goto fault; 2155451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2156451b001bSSteven J. Hill regs->regs[reg] = value; 2157451b001bSSteven J. Hill break; 2158451b001bSSteven J. Hill 2159451b001bSSteven J. Hill case MIPS16e_lwu_op: 2160451b001bSSteven J. Hill #ifdef CONFIG_64BIT 2161451b001bSSteven J. Hill /* 2162451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 2163451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 2164451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 2165451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 2166451b001bSSteven J. Hill * instructions on 32-bit kernels. 2167451b001bSSteven J. Hill */ 2168451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 4)) 2169451b001bSSteven J. Hill goto sigbus; 2170451b001bSSteven J. Hill 2171451b001bSSteven J. Hill LoadWU(addr, value, res); 2172451b001bSSteven J. Hill if (res) 2173451b001bSSteven J. Hill goto fault; 2174451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2175451b001bSSteven J. Hill regs->regs[reg] = value; 2176451b001bSSteven J. Hill break; 2177451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 2178451b001bSSteven J. Hill 2179451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 2180451b001bSSteven J. Hill goto sigill; 2181451b001bSSteven J. Hill 2182451b001bSSteven J. Hill case MIPS16e_ld_op: 2183451b001bSSteven J. Hill loadDW: 2184451b001bSSteven J. Hill #ifdef CONFIG_64BIT 2185451b001bSSteven J. Hill /* 2186451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 2187451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 2188451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 2189451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 2190451b001bSSteven J. Hill * instructions on 32-bit kernels. 2191451b001bSSteven J. Hill */ 2192451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 8)) 2193451b001bSSteven J. Hill goto sigbus; 2194451b001bSSteven J. Hill 2195451b001bSSteven J. Hill LoadDW(addr, value, res); 2196451b001bSSteven J. Hill if (res) 2197451b001bSSteven J. Hill goto fault; 2198451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2199451b001bSSteven J. Hill regs->regs[reg] = value; 2200451b001bSSteven J. Hill break; 2201451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 2202451b001bSSteven J. Hill 2203451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 2204451b001bSSteven J. Hill goto sigill; 2205451b001bSSteven J. Hill 2206451b001bSSteven J. Hill case MIPS16e_sh_op: 2207451b001bSSteven J. Hill if (!access_ok(VERIFY_WRITE, addr, 2)) 2208451b001bSSteven J. Hill goto sigbus; 2209451b001bSSteven J. Hill 2210451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2211451b001bSSteven J. Hill value = regs->regs[reg]; 2212451b001bSSteven J. Hill StoreHW(addr, value, res); 2213451b001bSSteven J. Hill if (res) 2214451b001bSSteven J. Hill goto fault; 2215451b001bSSteven J. Hill break; 2216451b001bSSteven J. Hill 2217451b001bSSteven J. Hill case MIPS16e_sw_op: 2218451b001bSSteven J. Hill case MIPS16e_swsp_op: 2219451b001bSSteven J. Hill case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */ 2220451b001bSSteven J. Hill if (!access_ok(VERIFY_WRITE, addr, 4)) 2221451b001bSSteven J. Hill goto sigbus; 2222451b001bSSteven J. Hill 2223451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2224451b001bSSteven J. Hill value = regs->regs[reg]; 2225451b001bSSteven J. Hill StoreW(addr, value, res); 2226451b001bSSteven J. Hill if (res) 2227451b001bSSteven J. Hill goto fault; 2228451b001bSSteven J. Hill break; 2229451b001bSSteven J. Hill 2230451b001bSSteven J. Hill case MIPS16e_sd_op: 2231451b001bSSteven J. Hill writeDW: 2232451b001bSSteven J. Hill #ifdef CONFIG_64BIT 2233451b001bSSteven J. Hill /* 2234451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 2235451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 2236451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 2237451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 2238451b001bSSteven J. Hill * instructions on 32-bit kernels. 2239451b001bSSteven J. Hill */ 2240451b001bSSteven J. Hill if (!access_ok(VERIFY_WRITE, addr, 8)) 2241451b001bSSteven J. Hill goto sigbus; 2242451b001bSSteven J. Hill 2243451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 2244451b001bSSteven J. Hill value = regs->regs[reg]; 2245451b001bSSteven J. Hill StoreDW(addr, value, res); 2246451b001bSSteven J. Hill if (res) 2247451b001bSSteven J. Hill goto fault; 2248451b001bSSteven J. Hill break; 2249451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 2250451b001bSSteven J. Hill 2251451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 2252451b001bSSteven J. Hill goto sigill; 2253451b001bSSteven J. Hill 2254451b001bSSteven J. Hill default: 2255451b001bSSteven J. Hill /* 2256451b001bSSteven J. Hill * Pheeee... We encountered an yet unknown instruction or 2257451b001bSSteven J. Hill * cache coherence problem. Die sucker, die ... 2258451b001bSSteven J. Hill */ 2259451b001bSSteven J. Hill goto sigill; 2260451b001bSSteven J. Hill } 2261451b001bSSteven J. Hill 2262451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS 2263451b001bSSteven J. Hill unaligned_instructions++; 2264451b001bSSteven J. Hill #endif 2265451b001bSSteven J. Hill 2266451b001bSSteven J. Hill return; 2267451b001bSSteven J. Hill 2268451b001bSSteven J. Hill fault: 2269451b001bSSteven J. Hill /* roll back jump/branch */ 2270451b001bSSteven J. Hill regs->cp0_epc = origpc; 2271451b001bSSteven J. Hill regs->regs[31] = orig31; 2272451b001bSSteven J. Hill /* Did we have an exception handler installed? */ 2273451b001bSSteven J. Hill if (fixup_exception(regs)) 2274451b001bSSteven J. Hill return; 2275451b001bSSteven J. Hill 2276451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs); 2277451b001bSSteven J. Hill force_sig(SIGSEGV, current); 2278451b001bSSteven J. Hill 2279451b001bSSteven J. Hill return; 2280451b001bSSteven J. Hill 2281451b001bSSteven J. Hill sigbus: 2282451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs); 2283451b001bSSteven J. Hill force_sig(SIGBUS, current); 2284451b001bSSteven J. Hill 2285451b001bSSteven J. Hill return; 2286451b001bSSteven J. Hill 2287451b001bSSteven J. Hill sigill: 2288451b001bSSteven J. Hill die_if_kernel 2289451b001bSSteven J. Hill ("Unhandled kernel unaligned access or invalid instruction", regs); 2290451b001bSSteven J. Hill force_sig(SIGILL, current); 2291451b001bSSteven J. Hill } 2292fc192e50STony Wu 22931da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs) 22941da177e4SLinus Torvalds { 2295c3fc5cd5SRalf Baechle enum ctx_state prev_state; 2296fe00f943SRalf Baechle unsigned int __user *pc; 22971da177e4SLinus Torvalds mm_segment_t seg; 22981da177e4SLinus Torvalds 2299c3fc5cd5SRalf Baechle prev_state = exception_enter(); 23007f788d2dSDeng-Cheng Zhu perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 2301a8b0ca17SPeter Zijlstra 1, regs, regs->cp0_badvaddr); 23021da177e4SLinus Torvalds /* 23031da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction? 23041da177e4SLinus Torvalds */ 230534c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == regs->cp0_epc) 23061da177e4SLinus Torvalds goto sigbus; 23071da177e4SLinus Torvalds 2308293c5bd1SRalf Baechle if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) 23091da177e4SLinus Torvalds goto sigbus; 23106312e0eeSAtsushi Nemoto if (unaligned_action == UNALIGNED_ACTION_SIGNAL) 23116312e0eeSAtsushi Nemoto goto sigbus; 23121da177e4SLinus Torvalds 23131da177e4SLinus Torvalds /* 23141da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception. 23151da177e4SLinus Torvalds * This is all so but ugly ... 23161da177e4SLinus Torvalds */ 231734c2f668SLeonid Yegoshin 231834c2f668SLeonid Yegoshin /* 231934c2f668SLeonid Yegoshin * Are we running in microMIPS mode? 232034c2f668SLeonid Yegoshin */ 232134c2f668SLeonid Yegoshin if (get_isa16_mode(regs->cp0_epc)) { 232234c2f668SLeonid Yegoshin /* 232334c2f668SLeonid Yegoshin * Did we catch a fault trying to load an instruction in 232434c2f668SLeonid Yegoshin * 16-bit mode? 232534c2f668SLeonid Yegoshin */ 232634c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc)) 232734c2f668SLeonid Yegoshin goto sigbus; 232834c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW) 232934c2f668SLeonid Yegoshin show_registers(regs); 233034c2f668SLeonid Yegoshin 233134c2f668SLeonid Yegoshin if (cpu_has_mmips) { 233234c2f668SLeonid Yegoshin seg = get_fs(); 233334c2f668SLeonid Yegoshin if (!user_mode(regs)) 233434c2f668SLeonid Yegoshin set_fs(KERNEL_DS); 233534c2f668SLeonid Yegoshin emulate_load_store_microMIPS(regs, 233634c2f668SLeonid Yegoshin (void __user *)regs->cp0_badvaddr); 233734c2f668SLeonid Yegoshin set_fs(seg); 233834c2f668SLeonid Yegoshin 233934c2f668SLeonid Yegoshin return; 234034c2f668SLeonid Yegoshin } 234134c2f668SLeonid Yegoshin 2342451b001bSSteven J. Hill if (cpu_has_mips16) { 2343451b001bSSteven J. Hill seg = get_fs(); 2344451b001bSSteven J. Hill if (!user_mode(regs)) 2345451b001bSSteven J. Hill set_fs(KERNEL_DS); 2346451b001bSSteven J. Hill emulate_load_store_MIPS16e(regs, 2347451b001bSSteven J. Hill (void __user *)regs->cp0_badvaddr); 2348451b001bSSteven J. Hill set_fs(seg); 2349451b001bSSteven J. Hill 2350451b001bSSteven J. Hill return; 2351451b001bSSteven J. Hill } 2352451b001bSSteven J. Hill 235334c2f668SLeonid Yegoshin goto sigbus; 235434c2f668SLeonid Yegoshin } 235534c2f668SLeonid Yegoshin 235634c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW) 235734c2f668SLeonid Yegoshin show_registers(regs); 235834c2f668SLeonid Yegoshin pc = (unsigned int __user *)exception_epc(regs); 235934c2f668SLeonid Yegoshin 23601da177e4SLinus Torvalds seg = get_fs(); 23611da177e4SLinus Torvalds if (!user_mode(regs)) 23621da177e4SLinus Torvalds set_fs(KERNEL_DS); 23637f18f151SRalf Baechle emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); 23641da177e4SLinus Torvalds set_fs(seg); 23651da177e4SLinus Torvalds 23661da177e4SLinus Torvalds return; 23671da177e4SLinus Torvalds 23681da177e4SLinus Torvalds sigbus: 23691da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs); 23701da177e4SLinus Torvalds force_sig(SIGBUS, current); 23711da177e4SLinus Torvalds 23721da177e4SLinus Torvalds /* 23731da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc 23741da177e4SLinus Torvalds */ 2375c3fc5cd5SRalf Baechle exception_exit(prev_state); 23761da177e4SLinus Torvalds } 23776312e0eeSAtsushi Nemoto 23786312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 23796312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void) 23806312e0eeSAtsushi Nemoto { 23816312e0eeSAtsushi Nemoto struct dentry *d; 23826312e0eeSAtsushi Nemoto 23836312e0eeSAtsushi Nemoto if (!mips_debugfs_dir) 23846312e0eeSAtsushi Nemoto return -ENODEV; 23856312e0eeSAtsushi Nemoto d = debugfs_create_u32("unaligned_instructions", S_IRUGO, 23866312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_instructions); 2387b517531cSZhaolei if (!d) 2388b517531cSZhaolei return -ENOMEM; 23896312e0eeSAtsushi Nemoto d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, 23906312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_action); 2391b517531cSZhaolei if (!d) 2392b517531cSZhaolei return -ENOMEM; 23936312e0eeSAtsushi Nemoto return 0; 23946312e0eeSAtsushi Nemoto } 23958d6b591cSRalf Baechle arch_initcall(debugfs_unaligned); 23966312e0eeSAtsushi Nemoto #endif 2397