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> 88102cedc3SLeonid Yegoshin #include <asm/fpu.h> 89102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h> 901da177e4SLinus Torvalds #include <asm/inst.h> 911da177e4SLinus Torvalds #include <asm/uaccess.h> 9234c2f668SLeonid Yegoshin #include <asm/fpu.h> 9334c2f668SLeonid Yegoshin #include <asm/fpu_emulator.h> 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds #define STR(x) __STR(x) 961da177e4SLinus Torvalds #define __STR(x) #x 971da177e4SLinus Torvalds 986312e0eeSAtsushi Nemoto enum { 996312e0eeSAtsushi Nemoto UNALIGNED_ACTION_QUIET, 1006312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SIGNAL, 1016312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SHOW, 1026312e0eeSAtsushi Nemoto }; 1036312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 1046312e0eeSAtsushi Nemoto static u32 unaligned_instructions; 1056312e0eeSAtsushi Nemoto static u32 unaligned_action; 1066312e0eeSAtsushi Nemoto #else 1076312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET 1081da177e4SLinus Torvalds #endif 1096312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs); 1101da177e4SLinus Torvalds 11134c2f668SLeonid Yegoshin #ifdef __BIG_ENDIAN 112*eeb53895SMarkos Chandras #define _LoadHW(addr, value, res, type) \ 11334c2f668SLeonid Yegoshin __asm__ __volatile__ (".set\tnoat\n" \ 114*eeb53895SMarkos Chandras "1:\t"type##_lb("%0", "0(%2)")"\n" \ 115*eeb53895SMarkos 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) \ 13034c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 13134c2f668SLeonid Yegoshin 1320593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 133*eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 13434c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 135*eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "(%2)")"\n" \ 136*eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "3(%2)")"\n\t"\ 13734c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 13834c2f668SLeonid Yegoshin "3:\n\t" \ 13934c2f668SLeonid Yegoshin ".insn\n\t" \ 14034c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 14134c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 14234c2f668SLeonid Yegoshin "j\t3b\n\t" \ 14334c2f668SLeonid Yegoshin ".previous\n\t" \ 14434c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 14534c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 14634c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 14734c2f668SLeonid Yegoshin ".previous" \ 14834c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 14934c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 1500593a44cSLeonid Yegoshin #else 1510593a44cSLeonid Yegoshin /* MIPSR6 has no lwl instruction */ 152*eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 1530593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 1540593a44cSLeonid Yegoshin ".set\tpush\n" \ 1550593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 156*eeb53895SMarkos Chandras "1:"type##_lb("%0", "0(%2)")"\n\t" \ 157*eeb53895SMarkos Chandras "2:"type##_lbu("$1", "1(%2)")"\n\t" \ 1580593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 1590593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 160*eeb53895SMarkos Chandras "3:"type##_lbu("$1", "2(%2)")"\n\t" \ 1610593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 1620593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 163*eeb53895SMarkos Chandras "4:"type##_lbu("$1", "3(%2)")"\n\t" \ 1640593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 1650593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 1660593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 1670593a44cSLeonid Yegoshin ".set\tpop\n" \ 1680593a44cSLeonid Yegoshin "10:\n\t" \ 1690593a44cSLeonid Yegoshin ".insn\n\t" \ 1700593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 1710593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 1720593a44cSLeonid Yegoshin "j\t10b\n\t" \ 1730593a44cSLeonid Yegoshin ".previous\n\t" \ 1740593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 1750593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 1760593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 1770593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 1780593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 1790593a44cSLeonid Yegoshin ".previous" \ 1800593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 1810593a44cSLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 1820593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */ 18334c2f668SLeonid Yegoshin 184*eeb53895SMarkos Chandras #define _LoadHWU(addr, value, res, type) \ 18534c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 18634c2f668SLeonid Yegoshin ".set\tnoat\n" \ 187*eeb53895SMarkos Chandras "1:\t"type##_lbu("%0", "0(%2)")"\n" \ 188*eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "1(%2)")"\n\t"\ 18934c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 19034c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 19134c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 19234c2f668SLeonid Yegoshin "3:\n\t" \ 19334c2f668SLeonid Yegoshin ".insn\n\t" \ 19434c2f668SLeonid Yegoshin ".set\tat\n\t" \ 19534c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 19634c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 19734c2f668SLeonid Yegoshin "j\t3b\n\t" \ 19834c2f668SLeonid Yegoshin ".previous\n\t" \ 19934c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 20034c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 20134c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 20234c2f668SLeonid Yegoshin ".previous" \ 20334c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 20434c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 20534c2f668SLeonid Yegoshin 2060593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 207*eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 20834c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 209*eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "(%2)")"\n" \ 210*eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "3(%2)")"\n\t"\ 21134c2f668SLeonid Yegoshin "dsll\t%0, %0, 32\n\t" \ 21234c2f668SLeonid Yegoshin "dsrl\t%0, %0, 32\n\t" \ 21334c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 21434c2f668SLeonid Yegoshin "3:\n\t" \ 21534c2f668SLeonid Yegoshin ".insn\n\t" \ 21634c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 21734c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 21834c2f668SLeonid Yegoshin "j\t3b\n\t" \ 21934c2f668SLeonid Yegoshin ".previous\n\t" \ 22034c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 22134c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 22234c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 22334c2f668SLeonid Yegoshin ".previous" \ 22434c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 22534c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 22634c2f668SLeonid Yegoshin 227*eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 22834c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 22934c2f668SLeonid Yegoshin "1:\tldl\t%0, (%2)\n" \ 23034c2f668SLeonid Yegoshin "2:\tldr\t%0, 7(%2)\n\t" \ 23134c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 23234c2f668SLeonid Yegoshin "3:\n\t" \ 23334c2f668SLeonid Yegoshin ".insn\n\t" \ 23434c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 23534c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 23634c2f668SLeonid Yegoshin "j\t3b\n\t" \ 23734c2f668SLeonid Yegoshin ".previous\n\t" \ 23834c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 23934c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 24034c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 24134c2f668SLeonid Yegoshin ".previous" \ 24234c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 24334c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 2440593a44cSLeonid Yegoshin #else 2450593a44cSLeonid Yegoshin /* MIPSR6 has not lwl and ldl instructions */ 246*eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 2470593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 2480593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 2490593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 250*eeb53895SMarkos Chandras "1:"type##_lbu("%0", "0(%2)")"\n\t" \ 251*eeb53895SMarkos Chandras "2:"type##_lbu("$1", "1(%2)")"\n\t" \ 2520593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 2530593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 254*eeb53895SMarkos Chandras "3:"type##_lbu("$1", "2(%2)")"\n\t" \ 2550593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 2560593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 257*eeb53895SMarkos Chandras "4:"type##_lbu("$1", "3(%2)")"\n\t" \ 2580593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 2590593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2600593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 2610593a44cSLeonid Yegoshin ".set\tpop\n" \ 2620593a44cSLeonid Yegoshin "10:\n\t" \ 2630593a44cSLeonid Yegoshin ".insn\n\t" \ 2640593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 2650593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 2660593a44cSLeonid Yegoshin "j\t10b\n\t" \ 2670593a44cSLeonid Yegoshin ".previous\n\t" \ 2680593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 2690593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 2700593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 2710593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 2720593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 2730593a44cSLeonid Yegoshin ".previous" \ 2740593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 2750593a44cSLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 2760593a44cSLeonid Yegoshin 277*eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 2780593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 2790593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 2800593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 2810593a44cSLeonid Yegoshin "1:lb\t%0, 0(%2)\n\t" \ 2820593a44cSLeonid Yegoshin "2:lbu\t $1, 1(%2)\n\t" \ 2830593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 2840593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2850593a44cSLeonid Yegoshin "3:lbu\t$1, 2(%2)\n\t" \ 2860593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 2870593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2880593a44cSLeonid Yegoshin "4:lbu\t$1, 3(%2)\n\t" \ 2890593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 2900593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2910593a44cSLeonid Yegoshin "5:lbu\t$1, 4(%2)\n\t" \ 2920593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 2930593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2940593a44cSLeonid Yegoshin "6:lbu\t$1, 5(%2)\n\t" \ 2950593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 2960593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 2970593a44cSLeonid Yegoshin "7:lbu\t$1, 6(%2)\n\t" \ 2980593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 2990593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3000593a44cSLeonid Yegoshin "8:lbu\t$1, 7(%2)\n\t" \ 3010593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 3020593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 3030593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 3040593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 3050593a44cSLeonid Yegoshin "10:\n\t" \ 3060593a44cSLeonid Yegoshin ".insn\n\t" \ 3070593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 3080593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 3090593a44cSLeonid Yegoshin "j\t10b\n\t" \ 3100593a44cSLeonid Yegoshin ".previous\n\t" \ 3110593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 3120593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 3130593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 3140593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 3150593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 3160593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 3170593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 3180593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 3190593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 3200593a44cSLeonid Yegoshin ".previous" \ 3210593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 3220593a44cSLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 3230593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */ 3240593a44cSLeonid Yegoshin 32534c2f668SLeonid Yegoshin 326*eeb53895SMarkos Chandras #define _StoreHW(addr, value, res, type) \ 32734c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 32834c2f668SLeonid Yegoshin ".set\tnoat\n" \ 329*eeb53895SMarkos Chandras "1:\t"type##_sb("%1", "1(%2)")"\n" \ 33034c2f668SLeonid Yegoshin "srl\t$1, %1, 0x8\n" \ 331*eeb53895SMarkos Chandras "2:\t"type##_sb("$1", "0(%2)")"\n" \ 33234c2f668SLeonid Yegoshin ".set\tat\n\t" \ 33334c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 33434c2f668SLeonid Yegoshin "3:\n\t" \ 33534c2f668SLeonid Yegoshin ".insn\n\t" \ 33634c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 33734c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 33834c2f668SLeonid Yegoshin "j\t3b\n\t" \ 33934c2f668SLeonid Yegoshin ".previous\n\t" \ 34034c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 34134c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 34234c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 34334c2f668SLeonid Yegoshin ".previous" \ 34434c2f668SLeonid Yegoshin : "=r" (res) \ 34534c2f668SLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT)); 34634c2f668SLeonid Yegoshin 3470593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 348*eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 34934c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 350*eeb53895SMarkos Chandras "1:\t"type##_swl("%1", "(%2)")"\n" \ 351*eeb53895SMarkos Chandras "2:\t"type##_swr("%1", "3(%2)")"\n\t"\ 35234c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 35334c2f668SLeonid Yegoshin "3:\n\t" \ 35434c2f668SLeonid Yegoshin ".insn\n\t" \ 35534c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 35634c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 35734c2f668SLeonid Yegoshin "j\t3b\n\t" \ 35834c2f668SLeonid Yegoshin ".previous\n\t" \ 35934c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 36034c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 36134c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 36234c2f668SLeonid Yegoshin ".previous" \ 36334c2f668SLeonid Yegoshin : "=r" (res) \ 36434c2f668SLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT)); 36534c2f668SLeonid Yegoshin 366*eeb53895SMarkos Chandras #define _StoreDW(addr, value, res) \ 36734c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 36834c2f668SLeonid Yegoshin "1:\tsdl\t%1,(%2)\n" \ 36934c2f668SLeonid Yegoshin "2:\tsdr\t%1, 7(%2)\n\t" \ 37034c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 37134c2f668SLeonid Yegoshin "3:\n\t" \ 37234c2f668SLeonid Yegoshin ".insn\n\t" \ 37334c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 37434c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 37534c2f668SLeonid Yegoshin "j\t3b\n\t" \ 37634c2f668SLeonid Yegoshin ".previous\n\t" \ 37734c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 37834c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 37934c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 38034c2f668SLeonid Yegoshin ".previous" \ 38134c2f668SLeonid Yegoshin : "=r" (res) \ 38234c2f668SLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT)); 3830593a44cSLeonid Yegoshin #else 3840593a44cSLeonid Yegoshin /* MIPSR6 has no swl and sdl instructions */ 385*eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 3860593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 3870593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 3880593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 389*eeb53895SMarkos Chandras "1:"type##_sb("%1", "3(%2)")"\n\t" \ 3900593a44cSLeonid Yegoshin "srl\t$1, %1, 0x8\n\t" \ 391*eeb53895SMarkos Chandras "2:"type##_sb("$1", "2(%2)")"\n\t" \ 3920593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 393*eeb53895SMarkos Chandras "3:"type##_sb("$1", "1(%2)")"\n\t" \ 3940593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 395*eeb53895SMarkos Chandras "4:"type##_sb("$1", "0(%2)")"\n\t" \ 3960593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 3970593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 3980593a44cSLeonid Yegoshin "10:\n\t" \ 3990593a44cSLeonid Yegoshin ".insn\n\t" \ 4000593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 4010593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 4020593a44cSLeonid Yegoshin "j\t10b\n\t" \ 4030593a44cSLeonid Yegoshin ".previous\n\t" \ 4040593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 4050593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 4060593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 4070593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 4080593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 4090593a44cSLeonid Yegoshin ".previous" \ 4100593a44cSLeonid Yegoshin : "=&r" (res) \ 4110593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 4120593a44cSLeonid Yegoshin : "memory"); 41334c2f668SLeonid Yegoshin 4140593a44cSLeonid Yegoshin #define StoreDW(addr, value, res) \ 4150593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 4160593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 4170593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 4180593a44cSLeonid Yegoshin "1:sb\t%1, 7(%2)\n\t" \ 4190593a44cSLeonid Yegoshin "dsrl\t$1, %1, 0x8\n\t" \ 4200593a44cSLeonid Yegoshin "2:sb\t$1, 6(%2)\n\t" \ 4210593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4220593a44cSLeonid Yegoshin "3:sb\t$1, 5(%2)\n\t" \ 4230593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4240593a44cSLeonid Yegoshin "4:sb\t$1, 4(%2)\n\t" \ 4250593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4260593a44cSLeonid Yegoshin "5:sb\t$1, 3(%2)\n\t" \ 4270593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4280593a44cSLeonid Yegoshin "6:sb\t$1, 2(%2)\n\t" \ 4290593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4300593a44cSLeonid Yegoshin "7:sb\t$1, 1(%2)\n\t" \ 4310593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4320593a44cSLeonid Yegoshin "8:sb\t$1, 0(%2)\n\t" \ 4330593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 4340593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 4350593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 4360593a44cSLeonid Yegoshin "10:\n\t" \ 4370593a44cSLeonid Yegoshin ".insn\n\t" \ 4380593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 4390593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 4400593a44cSLeonid Yegoshin "j\t10b\n\t" \ 4410593a44cSLeonid Yegoshin ".previous\n\t" \ 4420593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 4430593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 4440593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 4450593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 4460593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 4470593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 4480593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 4490593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 4500593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 4510593a44cSLeonid Yegoshin ".previous" \ 4520593a44cSLeonid Yegoshin : "=&r" (res) \ 4530593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 4540593a44cSLeonid Yegoshin : "memory"); 4550593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */ 4560593a44cSLeonid Yegoshin 4570593a44cSLeonid Yegoshin #else /* __BIG_ENDIAN */ 4580593a44cSLeonid Yegoshin 459*eeb53895SMarkos Chandras #define _LoadHW(addr, value, res, type) \ 46034c2f668SLeonid Yegoshin __asm__ __volatile__ (".set\tnoat\n" \ 461*eeb53895SMarkos Chandras "1:\t"type##_lb("%0", "1(%2)")"\n" \ 462*eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "0(%2)")"\n\t"\ 46334c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 46434c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 46534c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 46634c2f668SLeonid Yegoshin "3:\t.set\tat\n\t" \ 46734c2f668SLeonid Yegoshin ".insn\n\t" \ 46834c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 46934c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 47034c2f668SLeonid Yegoshin "j\t3b\n\t" \ 47134c2f668SLeonid Yegoshin ".previous\n\t" \ 47234c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 47334c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 47434c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 47534c2f668SLeonid Yegoshin ".previous" \ 47634c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 47734c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 47834c2f668SLeonid Yegoshin 4790593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 480*eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 48134c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 482*eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "3(%2)")"\n" \ 483*eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "(%2)")"\n\t"\ 48434c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 48534c2f668SLeonid Yegoshin "3:\n\t" \ 48634c2f668SLeonid Yegoshin ".insn\n\t" \ 48734c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 48834c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 48934c2f668SLeonid Yegoshin "j\t3b\n\t" \ 49034c2f668SLeonid Yegoshin ".previous\n\t" \ 49134c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 49234c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 49334c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 49434c2f668SLeonid Yegoshin ".previous" \ 49534c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 49634c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 4970593a44cSLeonid Yegoshin #else 4980593a44cSLeonid Yegoshin /* MIPSR6 has no lwl instruction */ 499*eeb53895SMarkos Chandras #define _LoadW(addr, value, res, type) \ 5000593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 5010593a44cSLeonid Yegoshin ".set\tpush\n" \ 5020593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 503*eeb53895SMarkos Chandras "1:"type##_lb("%0", "3(%2)")"\n\t" \ 504*eeb53895SMarkos Chandras "2:"type##_lbu("$1", "2(%2)")"\n\t" \ 5050593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 5060593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 507*eeb53895SMarkos Chandras "3:"type##_lbu("$1", "1(%2)")"\n\t" \ 5080593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 5090593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 510*eeb53895SMarkos Chandras "4:"type##_lbu("$1", "0(%2)")"\n\t" \ 5110593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 5120593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 5130593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 5140593a44cSLeonid Yegoshin ".set\tpop\n" \ 5150593a44cSLeonid Yegoshin "10:\n\t" \ 5160593a44cSLeonid Yegoshin ".insn\n\t" \ 5170593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 5180593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 5190593a44cSLeonid Yegoshin "j\t10b\n\t" \ 5200593a44cSLeonid Yegoshin ".previous\n\t" \ 5210593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 5220593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 5230593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 5240593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 5250593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 5260593a44cSLeonid Yegoshin ".previous" \ 5270593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 5280593a44cSLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 5290593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */ 5300593a44cSLeonid Yegoshin 53134c2f668SLeonid Yegoshin 532*eeb53895SMarkos Chandras #define _LoadHWU(addr, value, res, type) \ 53334c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 53434c2f668SLeonid Yegoshin ".set\tnoat\n" \ 535*eeb53895SMarkos Chandras "1:\t"type##_lbu("%0", "1(%2)")"\n" \ 536*eeb53895SMarkos Chandras "2:\t"type##_lbu("$1", "0(%2)")"\n\t"\ 53734c2f668SLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 53834c2f668SLeonid Yegoshin "or\t%0, $1\n\t" \ 53934c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 54034c2f668SLeonid Yegoshin "3:\n\t" \ 54134c2f668SLeonid Yegoshin ".insn\n\t" \ 54234c2f668SLeonid Yegoshin ".set\tat\n\t" \ 54334c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 54434c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 54534c2f668SLeonid Yegoshin "j\t3b\n\t" \ 54634c2f668SLeonid Yegoshin ".previous\n\t" \ 54734c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 54834c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 54934c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 55034c2f668SLeonid Yegoshin ".previous" \ 55134c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 55234c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 55334c2f668SLeonid Yegoshin 5540593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 555*eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 55634c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 557*eeb53895SMarkos Chandras "1:\t"type##_lwl("%0", "3(%2)")"\n" \ 558*eeb53895SMarkos Chandras "2:\t"type##_lwr("%0", "(%2)")"\n\t"\ 55934c2f668SLeonid Yegoshin "dsll\t%0, %0, 32\n\t" \ 56034c2f668SLeonid Yegoshin "dsrl\t%0, %0, 32\n\t" \ 56134c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 56234c2f668SLeonid Yegoshin "3:\n\t" \ 56334c2f668SLeonid Yegoshin ".insn\n\t" \ 56434c2f668SLeonid Yegoshin "\t.section\t.fixup,\"ax\"\n\t" \ 56534c2f668SLeonid Yegoshin "4:\tli\t%1, %3\n\t" \ 56634c2f668SLeonid Yegoshin "j\t3b\n\t" \ 56734c2f668SLeonid Yegoshin ".previous\n\t" \ 56834c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 56934c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 57034c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 57134c2f668SLeonid Yegoshin ".previous" \ 57234c2f668SLeonid Yegoshin : "=&r" (value), "=r" (res) \ 57334c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 57434c2f668SLeonid Yegoshin 575*eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 57634c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 57734c2f668SLeonid Yegoshin "1:\tldl\t%0, 7(%2)\n" \ 57834c2f668SLeonid Yegoshin "2:\tldr\t%0, (%2)\n\t" \ 57934c2f668SLeonid Yegoshin "li\t%1, 0\n" \ 58034c2f668SLeonid Yegoshin "3:\n\t" \ 58134c2f668SLeonid Yegoshin ".insn\n\t" \ 58234c2f668SLeonid Yegoshin "\t.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) \ 59134c2f668SLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 5920593a44cSLeonid Yegoshin #else 5930593a44cSLeonid Yegoshin /* MIPSR6 has not lwl and ldl instructions */ 594*eeb53895SMarkos Chandras #define _LoadWU(addr, value, res, type) \ 5950593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 5960593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 5970593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 598*eeb53895SMarkos Chandras "1:"type##_lbu("%0", "3(%2)")"\n\t" \ 599*eeb53895SMarkos Chandras "2:"type##_lbu("$1", "2(%2)")"\n\t" \ 6000593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 6010593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 602*eeb53895SMarkos Chandras "3:"type##_lbu("$1", "1(%2)")"\n\t" \ 6030593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 6040593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 605*eeb53895SMarkos Chandras "4:"type##_lbu("$1", "0(%2)")"\n\t" \ 6060593a44cSLeonid Yegoshin "sll\t%0, 0x8\n\t" \ 6070593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6080593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 6090593a44cSLeonid Yegoshin ".set\tpop\n" \ 6100593a44cSLeonid Yegoshin "10:\n\t" \ 6110593a44cSLeonid Yegoshin ".insn\n\t" \ 6120593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 6130593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 6140593a44cSLeonid Yegoshin "j\t10b\n\t" \ 6150593a44cSLeonid Yegoshin ".previous\n\t" \ 6160593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 6170593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 6180593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 6190593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 6200593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 6210593a44cSLeonid Yegoshin ".previous" \ 6220593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 6230593a44cSLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 6240593a44cSLeonid Yegoshin 625*eeb53895SMarkos Chandras #define _LoadDW(addr, value, res) \ 6260593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 6270593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 6280593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 6290593a44cSLeonid Yegoshin "1:lb\t%0, 7(%2)\n\t" \ 6300593a44cSLeonid Yegoshin "2:lbu\t$1, 6(%2)\n\t" \ 6310593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6320593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6330593a44cSLeonid Yegoshin "3:lbu\t$1, 5(%2)\n\t" \ 6340593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6350593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6360593a44cSLeonid Yegoshin "4:lbu\t$1, 4(%2)\n\t" \ 6370593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6380593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6390593a44cSLeonid Yegoshin "5:lbu\t$1, 3(%2)\n\t" \ 6400593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6410593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6420593a44cSLeonid Yegoshin "6:lbu\t$1, 2(%2)\n\t" \ 6430593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6440593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6450593a44cSLeonid Yegoshin "7:lbu\t$1, 1(%2)\n\t" \ 6460593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6470593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6480593a44cSLeonid Yegoshin "8:lbu\t$1, 0(%2)\n\t" \ 6490593a44cSLeonid Yegoshin "dsll\t%0, 0x8\n\t" \ 6500593a44cSLeonid Yegoshin "or\t%0, $1\n\t" \ 6510593a44cSLeonid Yegoshin "li\t%1, 0\n" \ 6520593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 6530593a44cSLeonid Yegoshin "10:\n\t" \ 6540593a44cSLeonid Yegoshin ".insn\n\t" \ 6550593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 6560593a44cSLeonid Yegoshin "11:\tli\t%1, %3\n\t" \ 6570593a44cSLeonid Yegoshin "j\t10b\n\t" \ 6580593a44cSLeonid Yegoshin ".previous\n\t" \ 6590593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 6600593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 6610593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 6620593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 6630593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 6640593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 6650593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 6660593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 6670593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 6680593a44cSLeonid Yegoshin ".previous" \ 6690593a44cSLeonid Yegoshin : "=&r" (value), "=r" (res) \ 6700593a44cSLeonid Yegoshin : "r" (addr), "i" (-EFAULT)); 6710593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */ 67234c2f668SLeonid Yegoshin 673*eeb53895SMarkos Chandras #define _StoreHW(addr, value, res, type) \ 67434c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 67534c2f668SLeonid Yegoshin ".set\tnoat\n" \ 676*eeb53895SMarkos Chandras "1:\t"type##_sb("%1", "0(%2)")"\n" \ 67734c2f668SLeonid Yegoshin "srl\t$1,%1, 0x8\n" \ 678*eeb53895SMarkos Chandras "2:\t"type##_sb("$1", "1(%2)")"\n" \ 67934c2f668SLeonid Yegoshin ".set\tat\n\t" \ 68034c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 68134c2f668SLeonid Yegoshin "3:\n\t" \ 68234c2f668SLeonid Yegoshin ".insn\n\t" \ 68334c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 68434c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 68534c2f668SLeonid Yegoshin "j\t3b\n\t" \ 68634c2f668SLeonid Yegoshin ".previous\n\t" \ 68734c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 68834c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 68934c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 69034c2f668SLeonid Yegoshin ".previous" \ 69134c2f668SLeonid Yegoshin : "=r" (res) \ 69234c2f668SLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT)); 6930593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 694*eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 69534c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 696*eeb53895SMarkos Chandras "1:\t"type##_swl("%1", "3(%2)")"\n" \ 697*eeb53895SMarkos Chandras "2:\t"type##_swr("%1", "(%2)")"\n\t"\ 69834c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 69934c2f668SLeonid Yegoshin "3:\n\t" \ 70034c2f668SLeonid Yegoshin ".insn\n\t" \ 70134c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 70234c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 70334c2f668SLeonid Yegoshin "j\t3b\n\t" \ 70434c2f668SLeonid Yegoshin ".previous\n\t" \ 70534c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 70634c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 70734c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 70834c2f668SLeonid Yegoshin ".previous" \ 70934c2f668SLeonid Yegoshin : "=r" (res) \ 71034c2f668SLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT)); 71134c2f668SLeonid Yegoshin 712*eeb53895SMarkos Chandras #define _StoreDW(addr, value, res) \ 71334c2f668SLeonid Yegoshin __asm__ __volatile__ ( \ 71434c2f668SLeonid Yegoshin "1:\tsdl\t%1, 7(%2)\n" \ 71534c2f668SLeonid Yegoshin "2:\tsdr\t%1, (%2)\n\t" \ 71634c2f668SLeonid Yegoshin "li\t%0, 0\n" \ 71734c2f668SLeonid Yegoshin "3:\n\t" \ 71834c2f668SLeonid Yegoshin ".insn\n\t" \ 71934c2f668SLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 72034c2f668SLeonid Yegoshin "4:\tli\t%0, %3\n\t" \ 72134c2f668SLeonid Yegoshin "j\t3b\n\t" \ 72234c2f668SLeonid Yegoshin ".previous\n\t" \ 72334c2f668SLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 72434c2f668SLeonid Yegoshin STR(PTR)"\t1b, 4b\n\t" \ 72534c2f668SLeonid Yegoshin STR(PTR)"\t2b, 4b\n\t" \ 72634c2f668SLeonid Yegoshin ".previous" \ 72734c2f668SLeonid Yegoshin : "=r" (res) \ 72834c2f668SLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT)); 7290593a44cSLeonid Yegoshin #else 7300593a44cSLeonid Yegoshin /* MIPSR6 has no swl and sdl instructions */ 731*eeb53895SMarkos Chandras #define _StoreW(addr, value, res, type) \ 7320593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 7330593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 7340593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 735*eeb53895SMarkos Chandras "1:"type##_sb("%1", "0(%2)")"\n\t" \ 7360593a44cSLeonid Yegoshin "srl\t$1, %1, 0x8\n\t" \ 737*eeb53895SMarkos Chandras "2:"type##_sb("$1", "1(%2)")"\n\t" \ 7380593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 739*eeb53895SMarkos Chandras "3:"type##_sb("$1", "2(%2)")"\n\t" \ 7400593a44cSLeonid Yegoshin "srl\t$1, $1, 0x8\n\t" \ 741*eeb53895SMarkos Chandras "4:"type##_sb("$1", "3(%2)")"\n\t" \ 7420593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 7430593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 7440593a44cSLeonid Yegoshin "10:\n\t" \ 7450593a44cSLeonid Yegoshin ".insn\n\t" \ 7460593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 7470593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 7480593a44cSLeonid Yegoshin "j\t10b\n\t" \ 7490593a44cSLeonid Yegoshin ".previous\n\t" \ 7500593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 7510593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 7520593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 7530593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 7540593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 7550593a44cSLeonid Yegoshin ".previous" \ 7560593a44cSLeonid Yegoshin : "=&r" (res) \ 7570593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 7580593a44cSLeonid Yegoshin : "memory"); 7590593a44cSLeonid Yegoshin 760*eeb53895SMarkos Chandras #define _StoreDW(addr, value, res) \ 7610593a44cSLeonid Yegoshin __asm__ __volatile__ ( \ 7620593a44cSLeonid Yegoshin ".set\tpush\n\t" \ 7630593a44cSLeonid Yegoshin ".set\tnoat\n\t" \ 7640593a44cSLeonid Yegoshin "1:sb\t%1, 0(%2)\n\t" \ 7650593a44cSLeonid Yegoshin "dsrl\t$1, %1, 0x8\n\t" \ 7660593a44cSLeonid Yegoshin "2:sb\t$1, 1(%2)\n\t" \ 7670593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7680593a44cSLeonid Yegoshin "3:sb\t$1, 2(%2)\n\t" \ 7690593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7700593a44cSLeonid Yegoshin "4:sb\t$1, 3(%2)\n\t" \ 7710593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7720593a44cSLeonid Yegoshin "5:sb\t$1, 4(%2)\n\t" \ 7730593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7740593a44cSLeonid Yegoshin "6:sb\t$1, 5(%2)\n\t" \ 7750593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7760593a44cSLeonid Yegoshin "7:sb\t$1, 6(%2)\n\t" \ 7770593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7780593a44cSLeonid Yegoshin "8:sb\t$1, 7(%2)\n\t" \ 7790593a44cSLeonid Yegoshin "dsrl\t$1, $1, 0x8\n\t" \ 7800593a44cSLeonid Yegoshin ".set\tpop\n\t" \ 7810593a44cSLeonid Yegoshin "li\t%0, 0\n" \ 7820593a44cSLeonid Yegoshin "10:\n\t" \ 7830593a44cSLeonid Yegoshin ".insn\n\t" \ 7840593a44cSLeonid Yegoshin ".section\t.fixup,\"ax\"\n\t" \ 7850593a44cSLeonid Yegoshin "11:\tli\t%0, %3\n\t" \ 7860593a44cSLeonid Yegoshin "j\t10b\n\t" \ 7870593a44cSLeonid Yegoshin ".previous\n\t" \ 7880593a44cSLeonid Yegoshin ".section\t__ex_table,\"a\"\n\t" \ 7890593a44cSLeonid Yegoshin STR(PTR)"\t1b, 11b\n\t" \ 7900593a44cSLeonid Yegoshin STR(PTR)"\t2b, 11b\n\t" \ 7910593a44cSLeonid Yegoshin STR(PTR)"\t3b, 11b\n\t" \ 7920593a44cSLeonid Yegoshin STR(PTR)"\t4b, 11b\n\t" \ 7930593a44cSLeonid Yegoshin STR(PTR)"\t5b, 11b\n\t" \ 7940593a44cSLeonid Yegoshin STR(PTR)"\t6b, 11b\n\t" \ 7950593a44cSLeonid Yegoshin STR(PTR)"\t7b, 11b\n\t" \ 7960593a44cSLeonid Yegoshin STR(PTR)"\t8b, 11b\n\t" \ 7970593a44cSLeonid Yegoshin ".previous" \ 7980593a44cSLeonid Yegoshin : "=&r" (res) \ 7990593a44cSLeonid Yegoshin : "r" (value), "r" (addr), "i" (-EFAULT) \ 8000593a44cSLeonid Yegoshin : "memory"); 8010593a44cSLeonid Yegoshin #endif /* CONFIG_CPU_MIPSR6 */ 80234c2f668SLeonid Yegoshin #endif 80334c2f668SLeonid Yegoshin 804*eeb53895SMarkos Chandras #define LoadHWU(addr, value, res) _LoadHWU(addr, value, res, kernel) 805*eeb53895SMarkos Chandras #define LoadHWUE(addr, value, res) _LoadHWU(addr, value, res, user) 806*eeb53895SMarkos Chandras #define LoadWU(addr, value, res) _LoadWU(addr, value, res, kernel) 807*eeb53895SMarkos Chandras #define LoadWUE(addr, value, res) _LoadWU(addr, value, res, user) 808*eeb53895SMarkos Chandras #define LoadHW(addr, value, res) _LoadHW(addr, value, res, kernel) 809*eeb53895SMarkos Chandras #define LoadHWE(addr, value, res) _LoadHW(addr, value, res, user) 810*eeb53895SMarkos Chandras #define LoadW(addr, value, res) _LoadW(addr, value, res, kernel) 811*eeb53895SMarkos Chandras #define LoadWE(addr, value, res) _LoadW(addr, value, res, user) 812*eeb53895SMarkos Chandras #define LoadDW(addr, value, res) _LoadDW(addr, value, res) 813*eeb53895SMarkos Chandras 814*eeb53895SMarkos Chandras #define StoreHW(addr, value, res) _StoreHW(addr, value, res, kernel) 815*eeb53895SMarkos Chandras #define StoreHWE(addr, value, res) _StoreHW(addr, value, res, user) 816*eeb53895SMarkos Chandras #define StoreW(addr, value, res) _StoreW(addr, value, res, kernel) 817*eeb53895SMarkos Chandras #define StoreWE(addr, value, res) _StoreW(addr, value, res, user) 818*eeb53895SMarkos Chandras #define StoreDW(addr, value, res) _StoreDW(addr, value, res) 819*eeb53895SMarkos Chandras 8207f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs, 8217f18f151SRalf Baechle void __user *addr, unsigned int __user *pc) 8221da177e4SLinus Torvalds { 8231da177e4SLinus Torvalds union mips_instruction insn; 8241da177e4SLinus Torvalds unsigned long value; 8251da177e4SLinus Torvalds unsigned int res; 82634c2f668SLeonid Yegoshin unsigned long origpc; 82734c2f668SLeonid Yegoshin unsigned long orig31; 828102cedc3SLeonid Yegoshin void __user *fault_addr = NULL; 829c1771216SLeonid Yegoshin #ifdef CONFIG_EVA 830c1771216SLeonid Yegoshin mm_segment_t seg; 831c1771216SLeonid Yegoshin #endif 83234c2f668SLeonid Yegoshin origpc = (unsigned long)pc; 83334c2f668SLeonid Yegoshin orig31 = regs->regs[31]; 83434c2f668SLeonid Yegoshin 835a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); 8367f788d2dSDeng-Cheng Zhu 8371da177e4SLinus Torvalds /* 8381da177e4SLinus Torvalds * This load never faults. 8391da177e4SLinus Torvalds */ 840fe00f943SRalf Baechle __get_user(insn.word, pc); 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds switch (insn.i_format.opcode) { 8431da177e4SLinus Torvalds /* 8441da177e4SLinus Torvalds * These are instructions that a compiler doesn't generate. We 8451da177e4SLinus Torvalds * can assume therefore that the code is MIPS-aware and 8461da177e4SLinus Torvalds * really buggy. Emulating these instructions would break the 8471da177e4SLinus Torvalds * semantics anyway. 8481da177e4SLinus Torvalds */ 8491da177e4SLinus Torvalds case ll_op: 8501da177e4SLinus Torvalds case lld_op: 8511da177e4SLinus Torvalds case sc_op: 8521da177e4SLinus Torvalds case scd_op: 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds /* 8551da177e4SLinus Torvalds * For these instructions the only way to create an address 8561da177e4SLinus Torvalds * error is an attempted access to kernel/supervisor address 8571da177e4SLinus Torvalds * space. 8581da177e4SLinus Torvalds */ 8591da177e4SLinus Torvalds case ldl_op: 8601da177e4SLinus Torvalds case ldr_op: 8611da177e4SLinus Torvalds case lwl_op: 8621da177e4SLinus Torvalds case lwr_op: 8631da177e4SLinus Torvalds case sdl_op: 8641da177e4SLinus Torvalds case sdr_op: 8651da177e4SLinus Torvalds case swl_op: 8661da177e4SLinus Torvalds case swr_op: 8671da177e4SLinus Torvalds case lb_op: 8681da177e4SLinus Torvalds case lbu_op: 8691da177e4SLinus Torvalds case sb_op: 8701da177e4SLinus Torvalds goto sigbus; 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds /* 87334c2f668SLeonid Yegoshin * The remaining opcodes are the ones that are really of 87434c2f668SLeonid Yegoshin * interest. 8751da177e4SLinus Torvalds */ 876c1771216SLeonid Yegoshin #ifdef CONFIG_EVA 877c1771216SLeonid Yegoshin case spec3_op: 878c1771216SLeonid Yegoshin /* 879c1771216SLeonid Yegoshin * we can land here only from kernel accessing user memory, 880c1771216SLeonid Yegoshin * so we need to "switch" the address limit to user space, so 881c1771216SLeonid Yegoshin * address check can work properly. 882c1771216SLeonid Yegoshin */ 883c1771216SLeonid Yegoshin seg = get_fs(); 884c1771216SLeonid Yegoshin set_fs(USER_DS); 885c1771216SLeonid Yegoshin switch (insn.spec3_format.func) { 886c1771216SLeonid Yegoshin case lhe_op: 887c1771216SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) { 888c1771216SLeonid Yegoshin set_fs(seg); 889c1771216SLeonid Yegoshin goto sigbus; 890c1771216SLeonid Yegoshin } 891*eeb53895SMarkos Chandras LoadHWE(addr, value, res); 892c1771216SLeonid Yegoshin if (res) { 893c1771216SLeonid Yegoshin set_fs(seg); 894c1771216SLeonid Yegoshin goto fault; 895c1771216SLeonid Yegoshin } 896c1771216SLeonid Yegoshin compute_return_epc(regs); 897c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 898c1771216SLeonid Yegoshin break; 899c1771216SLeonid Yegoshin case lwe_op: 900c1771216SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4)) { 901c1771216SLeonid Yegoshin set_fs(seg); 902c1771216SLeonid Yegoshin goto sigbus; 903c1771216SLeonid Yegoshin } 904*eeb53895SMarkos Chandras LoadWE(addr, value, res); 905c1771216SLeonid Yegoshin if (res) { 906c1771216SLeonid Yegoshin set_fs(seg); 907c1771216SLeonid Yegoshin goto fault; 908c1771216SLeonid Yegoshin } 909c1771216SLeonid Yegoshin compute_return_epc(regs); 910c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 911c1771216SLeonid Yegoshin break; 912c1771216SLeonid Yegoshin case lhue_op: 913c1771216SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) { 914c1771216SLeonid Yegoshin set_fs(seg); 915c1771216SLeonid Yegoshin goto sigbus; 916c1771216SLeonid Yegoshin } 917*eeb53895SMarkos Chandras LoadHWUE(addr, value, res); 918c1771216SLeonid Yegoshin if (res) { 919c1771216SLeonid Yegoshin set_fs(seg); 920c1771216SLeonid Yegoshin goto fault; 921c1771216SLeonid Yegoshin } 922c1771216SLeonid Yegoshin compute_return_epc(regs); 923c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 924c1771216SLeonid Yegoshin break; 925c1771216SLeonid Yegoshin case she_op: 926c1771216SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 2)) { 927c1771216SLeonid Yegoshin set_fs(seg); 928c1771216SLeonid Yegoshin goto sigbus; 929c1771216SLeonid Yegoshin } 930c1771216SLeonid Yegoshin compute_return_epc(regs); 931c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt]; 932*eeb53895SMarkos Chandras StoreHWE(addr, value, res); 933c1771216SLeonid Yegoshin if (res) { 934c1771216SLeonid Yegoshin set_fs(seg); 935c1771216SLeonid Yegoshin goto fault; 936c1771216SLeonid Yegoshin } 937c1771216SLeonid Yegoshin break; 938c1771216SLeonid Yegoshin case swe_op: 939c1771216SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4)) { 940c1771216SLeonid Yegoshin set_fs(seg); 941c1771216SLeonid Yegoshin goto sigbus; 942c1771216SLeonid Yegoshin } 943c1771216SLeonid Yegoshin compute_return_epc(regs); 944c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt]; 945*eeb53895SMarkos Chandras StoreWE(addr, value, res); 946c1771216SLeonid Yegoshin if (res) { 947c1771216SLeonid Yegoshin set_fs(seg); 948c1771216SLeonid Yegoshin goto fault; 949c1771216SLeonid Yegoshin } 950c1771216SLeonid Yegoshin break; 951c1771216SLeonid Yegoshin default: 952c1771216SLeonid Yegoshin set_fs(seg); 953c1771216SLeonid Yegoshin goto sigill; 954c1771216SLeonid Yegoshin } 955c1771216SLeonid Yegoshin set_fs(seg); 956c1771216SLeonid Yegoshin break; 957c1771216SLeonid Yegoshin #endif 9581da177e4SLinus Torvalds case lh_op: 9591da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 9601da177e4SLinus Torvalds goto sigbus; 9611da177e4SLinus Torvalds 96234c2f668SLeonid Yegoshin LoadHW(addr, value, res); 9631da177e4SLinus Torvalds if (res) 9641da177e4SLinus Torvalds goto fault; 9657f18f151SRalf Baechle compute_return_epc(regs); 9667f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 9671da177e4SLinus Torvalds break; 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds case lw_op: 9701da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 9711da177e4SLinus Torvalds goto sigbus; 9721da177e4SLinus Torvalds 97334c2f668SLeonid Yegoshin LoadW(addr, value, res); 9741da177e4SLinus Torvalds if (res) 9751da177e4SLinus Torvalds goto fault; 9767f18f151SRalf Baechle compute_return_epc(regs); 9777f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 9781da177e4SLinus Torvalds break; 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds case lhu_op: 9811da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 9821da177e4SLinus Torvalds goto sigbus; 9831da177e4SLinus Torvalds 98434c2f668SLeonid Yegoshin LoadHWU(addr, value, res); 9851da177e4SLinus Torvalds if (res) 9861da177e4SLinus Torvalds goto fault; 9877f18f151SRalf Baechle compute_return_epc(regs); 9887f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 9891da177e4SLinus Torvalds break; 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds case lwu_op: 992875d43e7SRalf Baechle #ifdef CONFIG_64BIT 9931da177e4SLinus Torvalds /* 9941da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 9951da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 9961da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 9971da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 9981da177e4SLinus Torvalds * instructions on 32-bit kernels. 9991da177e4SLinus Torvalds */ 10001da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 10011da177e4SLinus Torvalds goto sigbus; 10021da177e4SLinus Torvalds 100334c2f668SLeonid Yegoshin LoadWU(addr, value, res); 10041da177e4SLinus Torvalds if (res) 10051da177e4SLinus Torvalds goto fault; 10067f18f151SRalf Baechle compute_return_epc(regs); 10077f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 10081da177e4SLinus Torvalds break; 1009875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 10121da177e4SLinus Torvalds goto sigill; 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds case ld_op: 1015875d43e7SRalf Baechle #ifdef CONFIG_64BIT 10161da177e4SLinus Torvalds /* 10171da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 10181da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 10191da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 10201da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 10211da177e4SLinus Torvalds * instructions on 32-bit kernels. 10221da177e4SLinus Torvalds */ 10231da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 8)) 10241da177e4SLinus Torvalds goto sigbus; 10251da177e4SLinus Torvalds 102634c2f668SLeonid Yegoshin LoadDW(addr, value, res); 10271da177e4SLinus Torvalds if (res) 10281da177e4SLinus Torvalds goto fault; 10297f18f151SRalf Baechle compute_return_epc(regs); 10307f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 10311da177e4SLinus Torvalds break; 1032875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 10351da177e4SLinus Torvalds goto sigill; 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds case sh_op: 10381da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 2)) 10391da177e4SLinus Torvalds goto sigbus; 10401da177e4SLinus Torvalds 104134c2f668SLeonid Yegoshin compute_return_epc(regs); 10421da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 104334c2f668SLeonid Yegoshin StoreHW(addr, value, res); 10441da177e4SLinus Torvalds if (res) 10451da177e4SLinus Torvalds goto fault; 10461da177e4SLinus Torvalds break; 10471da177e4SLinus Torvalds 10481da177e4SLinus Torvalds case sw_op: 10491da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 4)) 10501da177e4SLinus Torvalds goto sigbus; 10511da177e4SLinus Torvalds 105234c2f668SLeonid Yegoshin compute_return_epc(regs); 10531da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 105434c2f668SLeonid Yegoshin StoreW(addr, value, res); 10551da177e4SLinus Torvalds if (res) 10561da177e4SLinus Torvalds goto fault; 10571da177e4SLinus Torvalds break; 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds case sd_op: 1060875d43e7SRalf Baechle #ifdef CONFIG_64BIT 10611da177e4SLinus Torvalds /* 10621da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 10631da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 10641da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 10651da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 10661da177e4SLinus Torvalds * instructions on 32-bit kernels. 10671da177e4SLinus Torvalds */ 10681da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 8)) 10691da177e4SLinus Torvalds goto sigbus; 10701da177e4SLinus Torvalds 107134c2f668SLeonid Yegoshin compute_return_epc(regs); 10721da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 107334c2f668SLeonid Yegoshin StoreDW(addr, value, res); 10741da177e4SLinus Torvalds if (res) 10751da177e4SLinus Torvalds goto fault; 10761da177e4SLinus Torvalds break; 1077875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 10781da177e4SLinus Torvalds 10791da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 10801da177e4SLinus Torvalds goto sigill; 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds case lwc1_op: 10831da177e4SLinus Torvalds case ldc1_op: 10841da177e4SLinus Torvalds case swc1_op: 10851da177e4SLinus Torvalds case sdc1_op: 1086102cedc3SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs); 1087102cedc3SLeonid Yegoshin BUG_ON(!used_math()); 1088102cedc3SLeonid Yegoshin 1089102cedc3SLeonid Yegoshin lose_fpu(1); /* Save FPU state for the emulator. */ 1090102cedc3SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, 1091102cedc3SLeonid Yegoshin &fault_addr); 1092102cedc3SLeonid Yegoshin own_fpu(1); /* Restore FPU state. */ 1093102cedc3SLeonid Yegoshin 1094102cedc3SLeonid Yegoshin /* Signal if something went wrong. */ 1095102cedc3SLeonid Yegoshin process_fpemu_return(res, fault_addr); 1096102cedc3SLeonid Yegoshin 1097102cedc3SLeonid Yegoshin if (res == 0) 1098102cedc3SLeonid Yegoshin break; 1099102cedc3SLeonid Yegoshin return; 11001da177e4SLinus Torvalds 11010593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 11021da177e4SLinus Torvalds /* 110369f3a7deSRalf Baechle * COP2 is available to implementor for application specific use. 110469f3a7deSRalf Baechle * It's up to applications to register a notifier chain and do 110569f3a7deSRalf Baechle * whatever they have to do, including possible sending of signals. 11060593a44cSLeonid Yegoshin * 11070593a44cSLeonid Yegoshin * This instruction has been reallocated in Release 6 11081da177e4SLinus Torvalds */ 110969f3a7deSRalf Baechle case lwc2_op: 111069f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LWC2_OP, regs); 111169f3a7deSRalf Baechle break; 111269f3a7deSRalf Baechle 111369f3a7deSRalf Baechle case ldc2_op: 111469f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LDC2_OP, regs); 111569f3a7deSRalf Baechle break; 111669f3a7deSRalf Baechle 111769f3a7deSRalf Baechle case swc2_op: 111869f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SWC2_OP, regs); 111969f3a7deSRalf Baechle break; 112069f3a7deSRalf Baechle 112169f3a7deSRalf Baechle case sdc2_op: 112269f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SDC2_OP, regs); 112369f3a7deSRalf Baechle break; 11240593a44cSLeonid Yegoshin #endif 11251da177e4SLinus Torvalds default: 11261da177e4SLinus Torvalds /* 11271da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or 11281da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ... 11291da177e4SLinus Torvalds */ 11301da177e4SLinus Torvalds goto sigill; 11311da177e4SLinus Torvalds } 11321da177e4SLinus Torvalds 11336312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 11341da177e4SLinus Torvalds unaligned_instructions++; 11351da177e4SLinus Torvalds #endif 11361da177e4SLinus Torvalds 11377f18f151SRalf Baechle return; 11381da177e4SLinus Torvalds 11391da177e4SLinus Torvalds fault: 114034c2f668SLeonid Yegoshin /* roll back jump/branch */ 114134c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 114234c2f668SLeonid Yegoshin regs->regs[31] = orig31; 11431da177e4SLinus Torvalds /* Did we have an exception handler installed? */ 11441da177e4SLinus Torvalds if (fixup_exception(regs)) 11457f18f151SRalf Baechle return; 11461da177e4SLinus Torvalds 11471da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 1148a6d5ff04SDavid Daney force_sig(SIGSEGV, current); 11491da177e4SLinus Torvalds 11507f18f151SRalf Baechle return; 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds sigbus: 11531da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 1154a6d5ff04SDavid Daney force_sig(SIGBUS, current); 11551da177e4SLinus Torvalds 11567f18f151SRalf Baechle return; 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds sigill: 115934c2f668SLeonid Yegoshin die_if_kernel 116034c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs); 116134c2f668SLeonid Yegoshin force_sig(SIGILL, current); 116234c2f668SLeonid Yegoshin } 116334c2f668SLeonid Yegoshin 116434c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */ 116534c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; 116634c2f668SLeonid Yegoshin 116734c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */ 116834c2f668SLeonid Yegoshin const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; 116934c2f668SLeonid Yegoshin 117074338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs, 117174338805SDavid Daney void __user *addr) 117234c2f668SLeonid Yegoshin { 117334c2f668SLeonid Yegoshin unsigned long value; 117434c2f668SLeonid Yegoshin unsigned int res; 117534c2f668SLeonid Yegoshin int i; 117634c2f668SLeonid Yegoshin unsigned int reg = 0, rvar; 117734c2f668SLeonid Yegoshin unsigned long orig31; 117834c2f668SLeonid Yegoshin u16 __user *pc16; 117934c2f668SLeonid Yegoshin u16 halfword; 118034c2f668SLeonid Yegoshin unsigned int word; 118134c2f668SLeonid Yegoshin unsigned long origpc, contpc; 118234c2f668SLeonid Yegoshin union mips_instruction insn; 118334c2f668SLeonid Yegoshin struct mm_decoded_insn mminsn; 118434c2f668SLeonid Yegoshin void __user *fault_addr = NULL; 118534c2f668SLeonid Yegoshin 118634c2f668SLeonid Yegoshin origpc = regs->cp0_epc; 118734c2f668SLeonid Yegoshin orig31 = regs->regs[31]; 118834c2f668SLeonid Yegoshin 118934c2f668SLeonid Yegoshin mminsn.micro_mips_mode = 1; 119034c2f668SLeonid Yegoshin 119134c2f668SLeonid Yegoshin /* 119234c2f668SLeonid Yegoshin * This load never faults. 119334c2f668SLeonid Yegoshin */ 119434c2f668SLeonid Yegoshin pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc); 119534c2f668SLeonid Yegoshin __get_user(halfword, pc16); 119634c2f668SLeonid Yegoshin pc16++; 119734c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 2; 119834c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16); 119934c2f668SLeonid Yegoshin mminsn.pc_inc = 2; 120034c2f668SLeonid Yegoshin 120134c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) { 120234c2f668SLeonid Yegoshin __get_user(halfword, pc16); 120334c2f668SLeonid Yegoshin pc16++; 120434c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 4; 120534c2f668SLeonid Yegoshin mminsn.pc_inc = 4; 120634c2f668SLeonid Yegoshin word |= halfword; 120734c2f668SLeonid Yegoshin } 120834c2f668SLeonid Yegoshin mminsn.insn = word; 120934c2f668SLeonid Yegoshin 121034c2f668SLeonid Yegoshin if (get_user(halfword, pc16)) 121134c2f668SLeonid Yegoshin goto fault; 121234c2f668SLeonid Yegoshin mminsn.next_pc_inc = 2; 121334c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16); 121434c2f668SLeonid Yegoshin 121534c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) { 121634c2f668SLeonid Yegoshin pc16++; 121734c2f668SLeonid Yegoshin if (get_user(halfword, pc16)) 121834c2f668SLeonid Yegoshin goto fault; 121934c2f668SLeonid Yegoshin mminsn.next_pc_inc = 4; 122034c2f668SLeonid Yegoshin word |= halfword; 122134c2f668SLeonid Yegoshin } 122234c2f668SLeonid Yegoshin mminsn.next_insn = word; 122334c2f668SLeonid Yegoshin 122434c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.insn); 122534c2f668SLeonid Yegoshin if (mm_isBranchInstr(regs, mminsn, &contpc)) 122634c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.next_insn); 122734c2f668SLeonid Yegoshin 122834c2f668SLeonid Yegoshin /* Parse instruction to find what to do */ 122934c2f668SLeonid Yegoshin 123034c2f668SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 123134c2f668SLeonid Yegoshin 123234c2f668SLeonid Yegoshin case mm_pool32a_op: 123334c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) { 123434c2f668SLeonid Yegoshin case mm_lwxs_op: 123534c2f668SLeonid Yegoshin reg = insn.mm_x_format.rd; 123634c2f668SLeonid Yegoshin goto loadW; 123734c2f668SLeonid Yegoshin } 123834c2f668SLeonid Yegoshin 123934c2f668SLeonid Yegoshin goto sigbus; 124034c2f668SLeonid Yegoshin 124134c2f668SLeonid Yegoshin case mm_pool32b_op: 124234c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) { 124334c2f668SLeonid Yegoshin case mm_lwp_func: 124434c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 124534c2f668SLeonid Yegoshin if (reg == 31) 124634c2f668SLeonid Yegoshin goto sigbus; 124734c2f668SLeonid Yegoshin 124834c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 8)) 124934c2f668SLeonid Yegoshin goto sigbus; 125034c2f668SLeonid Yegoshin 125134c2f668SLeonid Yegoshin LoadW(addr, value, res); 125234c2f668SLeonid Yegoshin if (res) 125334c2f668SLeonid Yegoshin goto fault; 125434c2f668SLeonid Yegoshin regs->regs[reg] = value; 125534c2f668SLeonid Yegoshin addr += 4; 125634c2f668SLeonid Yegoshin LoadW(addr, value, res); 125734c2f668SLeonid Yegoshin if (res) 125834c2f668SLeonid Yegoshin goto fault; 125934c2f668SLeonid Yegoshin regs->regs[reg + 1] = value; 126034c2f668SLeonid Yegoshin goto success; 126134c2f668SLeonid Yegoshin 126234c2f668SLeonid Yegoshin case mm_swp_func: 126334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 126434c2f668SLeonid Yegoshin if (reg == 31) 126534c2f668SLeonid Yegoshin goto sigbus; 126634c2f668SLeonid Yegoshin 126734c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 8)) 126834c2f668SLeonid Yegoshin goto sigbus; 126934c2f668SLeonid Yegoshin 127034c2f668SLeonid Yegoshin value = regs->regs[reg]; 127134c2f668SLeonid Yegoshin StoreW(addr, value, res); 127234c2f668SLeonid Yegoshin if (res) 127334c2f668SLeonid Yegoshin goto fault; 127434c2f668SLeonid Yegoshin addr += 4; 127534c2f668SLeonid Yegoshin value = regs->regs[reg + 1]; 127634c2f668SLeonid Yegoshin StoreW(addr, value, res); 127734c2f668SLeonid Yegoshin if (res) 127834c2f668SLeonid Yegoshin goto fault; 127934c2f668SLeonid Yegoshin goto success; 128034c2f668SLeonid Yegoshin 128134c2f668SLeonid Yegoshin case mm_ldp_func: 128234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 128334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 128434c2f668SLeonid Yegoshin if (reg == 31) 128534c2f668SLeonid Yegoshin goto sigbus; 128634c2f668SLeonid Yegoshin 128734c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 16)) 128834c2f668SLeonid Yegoshin goto sigbus; 128934c2f668SLeonid Yegoshin 129034c2f668SLeonid Yegoshin LoadDW(addr, value, res); 129134c2f668SLeonid Yegoshin if (res) 129234c2f668SLeonid Yegoshin goto fault; 129334c2f668SLeonid Yegoshin regs->regs[reg] = value; 129434c2f668SLeonid Yegoshin addr += 8; 129534c2f668SLeonid Yegoshin LoadDW(addr, value, res); 129634c2f668SLeonid Yegoshin if (res) 129734c2f668SLeonid Yegoshin goto fault; 129834c2f668SLeonid Yegoshin regs->regs[reg + 1] = value; 129934c2f668SLeonid Yegoshin goto success; 130034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 130134c2f668SLeonid Yegoshin 130234c2f668SLeonid Yegoshin goto sigill; 130334c2f668SLeonid Yegoshin 130434c2f668SLeonid Yegoshin case mm_sdp_func: 130534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 130634c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 130734c2f668SLeonid Yegoshin if (reg == 31) 130834c2f668SLeonid Yegoshin goto sigbus; 130934c2f668SLeonid Yegoshin 131034c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 16)) 131134c2f668SLeonid Yegoshin goto sigbus; 131234c2f668SLeonid Yegoshin 131334c2f668SLeonid Yegoshin value = regs->regs[reg]; 131434c2f668SLeonid Yegoshin StoreDW(addr, value, res); 131534c2f668SLeonid Yegoshin if (res) 131634c2f668SLeonid Yegoshin goto fault; 131734c2f668SLeonid Yegoshin addr += 8; 131834c2f668SLeonid Yegoshin value = regs->regs[reg + 1]; 131934c2f668SLeonid Yegoshin StoreDW(addr, value, res); 132034c2f668SLeonid Yegoshin if (res) 132134c2f668SLeonid Yegoshin goto fault; 132234c2f668SLeonid Yegoshin goto success; 132334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 132434c2f668SLeonid Yegoshin 132534c2f668SLeonid Yegoshin goto sigill; 132634c2f668SLeonid Yegoshin 132734c2f668SLeonid Yegoshin case mm_lwm32_func: 132834c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 132934c2f668SLeonid Yegoshin rvar = reg & 0xf; 133034c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 133134c2f668SLeonid Yegoshin goto sigill; 133234c2f668SLeonid Yegoshin if (reg & 0x10) { 133334c2f668SLeonid Yegoshin if (!access_ok 133434c2f668SLeonid Yegoshin (VERIFY_READ, addr, 4 * (rvar + 1))) 133534c2f668SLeonid Yegoshin goto sigbus; 133634c2f668SLeonid Yegoshin } else { 133734c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4 * rvar)) 133834c2f668SLeonid Yegoshin goto sigbus; 133934c2f668SLeonid Yegoshin } 134034c2f668SLeonid Yegoshin if (rvar == 9) 134134c2f668SLeonid Yegoshin rvar = 8; 134234c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 134334c2f668SLeonid Yegoshin LoadW(addr, value, res); 134434c2f668SLeonid Yegoshin if (res) 134534c2f668SLeonid Yegoshin goto fault; 134634c2f668SLeonid Yegoshin addr += 4; 134734c2f668SLeonid Yegoshin regs->regs[i] = value; 134834c2f668SLeonid Yegoshin } 134934c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 135034c2f668SLeonid Yegoshin LoadW(addr, value, res); 135134c2f668SLeonid Yegoshin if (res) 135234c2f668SLeonid Yegoshin goto fault; 135334c2f668SLeonid Yegoshin addr += 4; 135434c2f668SLeonid Yegoshin regs->regs[30] = value; 135534c2f668SLeonid Yegoshin } 135634c2f668SLeonid Yegoshin if (reg & 0x10) { 135734c2f668SLeonid Yegoshin LoadW(addr, value, res); 135834c2f668SLeonid Yegoshin if (res) 135934c2f668SLeonid Yegoshin goto fault; 136034c2f668SLeonid Yegoshin regs->regs[31] = value; 136134c2f668SLeonid Yegoshin } 136234c2f668SLeonid Yegoshin goto success; 136334c2f668SLeonid Yegoshin 136434c2f668SLeonid Yegoshin case mm_swm32_func: 136534c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 136634c2f668SLeonid Yegoshin rvar = reg & 0xf; 136734c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 136834c2f668SLeonid Yegoshin goto sigill; 136934c2f668SLeonid Yegoshin if (reg & 0x10) { 137034c2f668SLeonid Yegoshin if (!access_ok 137134c2f668SLeonid Yegoshin (VERIFY_WRITE, addr, 4 * (rvar + 1))) 137234c2f668SLeonid Yegoshin goto sigbus; 137334c2f668SLeonid Yegoshin } else { 137434c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4 * rvar)) 137534c2f668SLeonid Yegoshin goto sigbus; 137634c2f668SLeonid Yegoshin } 137734c2f668SLeonid Yegoshin if (rvar == 9) 137834c2f668SLeonid Yegoshin rvar = 8; 137934c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 138034c2f668SLeonid Yegoshin value = regs->regs[i]; 138134c2f668SLeonid Yegoshin StoreW(addr, value, res); 138234c2f668SLeonid Yegoshin if (res) 138334c2f668SLeonid Yegoshin goto fault; 138434c2f668SLeonid Yegoshin addr += 4; 138534c2f668SLeonid Yegoshin } 138634c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 138734c2f668SLeonid Yegoshin value = regs->regs[30]; 138834c2f668SLeonid Yegoshin StoreW(addr, value, res); 138934c2f668SLeonid Yegoshin if (res) 139034c2f668SLeonid Yegoshin goto fault; 139134c2f668SLeonid Yegoshin addr += 4; 139234c2f668SLeonid Yegoshin } 139334c2f668SLeonid Yegoshin if (reg & 0x10) { 139434c2f668SLeonid Yegoshin value = regs->regs[31]; 139534c2f668SLeonid Yegoshin StoreW(addr, value, res); 139634c2f668SLeonid Yegoshin if (res) 139734c2f668SLeonid Yegoshin goto fault; 139834c2f668SLeonid Yegoshin } 139934c2f668SLeonid Yegoshin goto success; 140034c2f668SLeonid Yegoshin 140134c2f668SLeonid Yegoshin case mm_ldm_func: 140234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 140334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 140434c2f668SLeonid Yegoshin rvar = reg & 0xf; 140534c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 140634c2f668SLeonid Yegoshin goto sigill; 140734c2f668SLeonid Yegoshin if (reg & 0x10) { 140834c2f668SLeonid Yegoshin if (!access_ok 140934c2f668SLeonid Yegoshin (VERIFY_READ, addr, 8 * (rvar + 1))) 141034c2f668SLeonid Yegoshin goto sigbus; 141134c2f668SLeonid Yegoshin } else { 141234c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 8 * rvar)) 141334c2f668SLeonid Yegoshin goto sigbus; 141434c2f668SLeonid Yegoshin } 141534c2f668SLeonid Yegoshin if (rvar == 9) 141634c2f668SLeonid Yegoshin rvar = 8; 141734c2f668SLeonid Yegoshin 141834c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 141934c2f668SLeonid Yegoshin LoadDW(addr, value, res); 142034c2f668SLeonid Yegoshin if (res) 142134c2f668SLeonid Yegoshin goto fault; 142234c2f668SLeonid Yegoshin addr += 4; 142334c2f668SLeonid Yegoshin regs->regs[i] = value; 142434c2f668SLeonid Yegoshin } 142534c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 142634c2f668SLeonid Yegoshin LoadDW(addr, value, res); 142734c2f668SLeonid Yegoshin if (res) 142834c2f668SLeonid Yegoshin goto fault; 142934c2f668SLeonid Yegoshin addr += 8; 143034c2f668SLeonid Yegoshin regs->regs[30] = value; 143134c2f668SLeonid Yegoshin } 143234c2f668SLeonid Yegoshin if (reg & 0x10) { 143334c2f668SLeonid Yegoshin LoadDW(addr, value, res); 143434c2f668SLeonid Yegoshin if (res) 143534c2f668SLeonid Yegoshin goto fault; 143634c2f668SLeonid Yegoshin regs->regs[31] = value; 143734c2f668SLeonid Yegoshin } 143834c2f668SLeonid Yegoshin goto success; 143934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 144034c2f668SLeonid Yegoshin 144134c2f668SLeonid Yegoshin goto sigill; 144234c2f668SLeonid Yegoshin 144334c2f668SLeonid Yegoshin case mm_sdm_func: 144434c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 144534c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 144634c2f668SLeonid Yegoshin rvar = reg & 0xf; 144734c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 144834c2f668SLeonid Yegoshin goto sigill; 144934c2f668SLeonid Yegoshin if (reg & 0x10) { 145034c2f668SLeonid Yegoshin if (!access_ok 145134c2f668SLeonid Yegoshin (VERIFY_WRITE, addr, 8 * (rvar + 1))) 145234c2f668SLeonid Yegoshin goto sigbus; 145334c2f668SLeonid Yegoshin } else { 145434c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 8 * rvar)) 145534c2f668SLeonid Yegoshin goto sigbus; 145634c2f668SLeonid Yegoshin } 145734c2f668SLeonid Yegoshin if (rvar == 9) 145834c2f668SLeonid Yegoshin rvar = 8; 145934c2f668SLeonid Yegoshin 146034c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 146134c2f668SLeonid Yegoshin value = regs->regs[i]; 146234c2f668SLeonid Yegoshin StoreDW(addr, value, res); 146334c2f668SLeonid Yegoshin if (res) 146434c2f668SLeonid Yegoshin goto fault; 146534c2f668SLeonid Yegoshin addr += 8; 146634c2f668SLeonid Yegoshin } 146734c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 146834c2f668SLeonid Yegoshin value = regs->regs[30]; 146934c2f668SLeonid Yegoshin StoreDW(addr, value, res); 147034c2f668SLeonid Yegoshin if (res) 147134c2f668SLeonid Yegoshin goto fault; 147234c2f668SLeonid Yegoshin addr += 8; 147334c2f668SLeonid Yegoshin } 147434c2f668SLeonid Yegoshin if (reg & 0x10) { 147534c2f668SLeonid Yegoshin value = regs->regs[31]; 147634c2f668SLeonid Yegoshin StoreDW(addr, value, res); 147734c2f668SLeonid Yegoshin if (res) 147834c2f668SLeonid Yegoshin goto fault; 147934c2f668SLeonid Yegoshin } 148034c2f668SLeonid Yegoshin goto success; 148134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 148234c2f668SLeonid Yegoshin 148334c2f668SLeonid Yegoshin goto sigill; 148434c2f668SLeonid Yegoshin 148534c2f668SLeonid Yegoshin /* LWC2, SWC2, LDC2, SDC2 are not serviced */ 148634c2f668SLeonid Yegoshin } 148734c2f668SLeonid Yegoshin 148834c2f668SLeonid Yegoshin goto sigbus; 148934c2f668SLeonid Yegoshin 149034c2f668SLeonid Yegoshin case mm_pool32c_op: 149134c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) { 149234c2f668SLeonid Yegoshin case mm_lwu_func: 149334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 149434c2f668SLeonid Yegoshin goto loadWU; 149534c2f668SLeonid Yegoshin } 149634c2f668SLeonid Yegoshin 149734c2f668SLeonid Yegoshin /* LL,SC,LLD,SCD are not serviced */ 149834c2f668SLeonid Yegoshin goto sigbus; 149934c2f668SLeonid Yegoshin 150034c2f668SLeonid Yegoshin case mm_pool32f_op: 150134c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) { 150234c2f668SLeonid Yegoshin case mm_lwxc1_func: 150334c2f668SLeonid Yegoshin case mm_swxc1_func: 150434c2f668SLeonid Yegoshin case mm_ldxc1_func: 150534c2f668SLeonid Yegoshin case mm_sdxc1_func: 150634c2f668SLeonid Yegoshin goto fpu_emul; 150734c2f668SLeonid Yegoshin } 150834c2f668SLeonid Yegoshin 150934c2f668SLeonid Yegoshin goto sigbus; 151034c2f668SLeonid Yegoshin 151134c2f668SLeonid Yegoshin case mm_ldc132_op: 151234c2f668SLeonid Yegoshin case mm_sdc132_op: 151334c2f668SLeonid Yegoshin case mm_lwc132_op: 151434c2f668SLeonid Yegoshin case mm_swc132_op: 151534c2f668SLeonid Yegoshin fpu_emul: 151634c2f668SLeonid Yegoshin /* roll back jump/branch */ 151734c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 151834c2f668SLeonid Yegoshin regs->regs[31] = orig31; 151934c2f668SLeonid Yegoshin 152034c2f668SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs); 152134c2f668SLeonid Yegoshin BUG_ON(!used_math()); 152234c2f668SLeonid Yegoshin BUG_ON(!is_fpu_owner()); 152334c2f668SLeonid Yegoshin 152434c2f668SLeonid Yegoshin lose_fpu(1); /* save the FPU state for the emulator */ 152534c2f668SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, 152634c2f668SLeonid Yegoshin &fault_addr); 152734c2f668SLeonid Yegoshin own_fpu(1); /* restore FPU state */ 152834c2f668SLeonid Yegoshin 152934c2f668SLeonid Yegoshin /* If something went wrong, signal */ 153034c2f668SLeonid Yegoshin process_fpemu_return(res, fault_addr); 153134c2f668SLeonid Yegoshin 153234c2f668SLeonid Yegoshin if (res == 0) 153334c2f668SLeonid Yegoshin goto success; 153434c2f668SLeonid Yegoshin return; 153534c2f668SLeonid Yegoshin 153634c2f668SLeonid Yegoshin case mm_lh32_op: 153734c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 153834c2f668SLeonid Yegoshin goto loadHW; 153934c2f668SLeonid Yegoshin 154034c2f668SLeonid Yegoshin case mm_lhu32_op: 154134c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 154234c2f668SLeonid Yegoshin goto loadHWU; 154334c2f668SLeonid Yegoshin 154434c2f668SLeonid Yegoshin case mm_lw32_op: 154534c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 154634c2f668SLeonid Yegoshin goto loadW; 154734c2f668SLeonid Yegoshin 154834c2f668SLeonid Yegoshin case mm_sh32_op: 154934c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 155034c2f668SLeonid Yegoshin goto storeHW; 155134c2f668SLeonid Yegoshin 155234c2f668SLeonid Yegoshin case mm_sw32_op: 155334c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 155434c2f668SLeonid Yegoshin goto storeW; 155534c2f668SLeonid Yegoshin 155634c2f668SLeonid Yegoshin case mm_ld32_op: 155734c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 155834c2f668SLeonid Yegoshin goto loadDW; 155934c2f668SLeonid Yegoshin 156034c2f668SLeonid Yegoshin case mm_sd32_op: 156134c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 156234c2f668SLeonid Yegoshin goto storeDW; 156334c2f668SLeonid Yegoshin 156434c2f668SLeonid Yegoshin case mm_pool16c_op: 156534c2f668SLeonid Yegoshin switch (insn.mm16_m_format.func) { 156634c2f668SLeonid Yegoshin case mm_lwm16_op: 156734c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist; 156834c2f668SLeonid Yegoshin rvar = reg + 1; 156934c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4 * rvar)) 157034c2f668SLeonid Yegoshin goto sigbus; 157134c2f668SLeonid Yegoshin 157234c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 157334c2f668SLeonid Yegoshin LoadW(addr, value, res); 157434c2f668SLeonid Yegoshin if (res) 157534c2f668SLeonid Yegoshin goto fault; 157634c2f668SLeonid Yegoshin addr += 4; 157734c2f668SLeonid Yegoshin regs->regs[i] = value; 157834c2f668SLeonid Yegoshin } 157934c2f668SLeonid Yegoshin LoadW(addr, value, res); 158034c2f668SLeonid Yegoshin if (res) 158134c2f668SLeonid Yegoshin goto fault; 158234c2f668SLeonid Yegoshin regs->regs[31] = value; 158334c2f668SLeonid Yegoshin 158434c2f668SLeonid Yegoshin goto success; 158534c2f668SLeonid Yegoshin 158634c2f668SLeonid Yegoshin case mm_swm16_op: 158734c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist; 158834c2f668SLeonid Yegoshin rvar = reg + 1; 158934c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4 * rvar)) 159034c2f668SLeonid Yegoshin goto sigbus; 159134c2f668SLeonid Yegoshin 159234c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 159334c2f668SLeonid Yegoshin value = regs->regs[i]; 159434c2f668SLeonid Yegoshin StoreW(addr, value, res); 159534c2f668SLeonid Yegoshin if (res) 159634c2f668SLeonid Yegoshin goto fault; 159734c2f668SLeonid Yegoshin addr += 4; 159834c2f668SLeonid Yegoshin } 159934c2f668SLeonid Yegoshin value = regs->regs[31]; 160034c2f668SLeonid Yegoshin StoreW(addr, value, res); 160134c2f668SLeonid Yegoshin if (res) 160234c2f668SLeonid Yegoshin goto fault; 160334c2f668SLeonid Yegoshin 160434c2f668SLeonid Yegoshin goto success; 160534c2f668SLeonid Yegoshin 160634c2f668SLeonid Yegoshin } 160734c2f668SLeonid Yegoshin 160834c2f668SLeonid Yegoshin goto sigbus; 160934c2f668SLeonid Yegoshin 161034c2f668SLeonid Yegoshin case mm_lhu16_op: 161134c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt]; 161234c2f668SLeonid Yegoshin goto loadHWU; 161334c2f668SLeonid Yegoshin 161434c2f668SLeonid Yegoshin case mm_lw16_op: 161534c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt]; 161634c2f668SLeonid Yegoshin goto loadW; 161734c2f668SLeonid Yegoshin 161834c2f668SLeonid Yegoshin case mm_sh16_op: 161934c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt]; 162034c2f668SLeonid Yegoshin goto storeHW; 162134c2f668SLeonid Yegoshin 162234c2f668SLeonid Yegoshin case mm_sw16_op: 162334c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt]; 162434c2f668SLeonid Yegoshin goto storeW; 162534c2f668SLeonid Yegoshin 162634c2f668SLeonid Yegoshin case mm_lwsp16_op: 162734c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt; 162834c2f668SLeonid Yegoshin goto loadW; 162934c2f668SLeonid Yegoshin 163034c2f668SLeonid Yegoshin case mm_swsp16_op: 163134c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt; 163234c2f668SLeonid Yegoshin goto storeW; 163334c2f668SLeonid Yegoshin 163434c2f668SLeonid Yegoshin case mm_lwgp16_op: 163534c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_r3_format.rt]; 163634c2f668SLeonid Yegoshin goto loadW; 163734c2f668SLeonid Yegoshin 163834c2f668SLeonid Yegoshin default: 163934c2f668SLeonid Yegoshin goto sigill; 164034c2f668SLeonid Yegoshin } 164134c2f668SLeonid Yegoshin 164234c2f668SLeonid Yegoshin loadHW: 164334c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) 164434c2f668SLeonid Yegoshin goto sigbus; 164534c2f668SLeonid Yegoshin 164634c2f668SLeonid Yegoshin LoadHW(addr, value, res); 164734c2f668SLeonid Yegoshin if (res) 164834c2f668SLeonid Yegoshin goto fault; 164934c2f668SLeonid Yegoshin regs->regs[reg] = value; 165034c2f668SLeonid Yegoshin goto success; 165134c2f668SLeonid Yegoshin 165234c2f668SLeonid Yegoshin loadHWU: 165334c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 2)) 165434c2f668SLeonid Yegoshin goto sigbus; 165534c2f668SLeonid Yegoshin 165634c2f668SLeonid Yegoshin LoadHWU(addr, value, res); 165734c2f668SLeonid Yegoshin if (res) 165834c2f668SLeonid Yegoshin goto fault; 165934c2f668SLeonid Yegoshin regs->regs[reg] = value; 166034c2f668SLeonid Yegoshin goto success; 166134c2f668SLeonid Yegoshin 166234c2f668SLeonid Yegoshin loadW: 166334c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4)) 166434c2f668SLeonid Yegoshin goto sigbus; 166534c2f668SLeonid Yegoshin 166634c2f668SLeonid Yegoshin LoadW(addr, value, res); 166734c2f668SLeonid Yegoshin if (res) 166834c2f668SLeonid Yegoshin goto fault; 166934c2f668SLeonid Yegoshin regs->regs[reg] = value; 167034c2f668SLeonid Yegoshin goto success; 167134c2f668SLeonid Yegoshin 167234c2f668SLeonid Yegoshin loadWU: 167334c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 167434c2f668SLeonid Yegoshin /* 167534c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 167634c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 167734c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 167834c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 167934c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 168034c2f668SLeonid Yegoshin */ 168134c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 4)) 168234c2f668SLeonid Yegoshin goto sigbus; 168334c2f668SLeonid Yegoshin 168434c2f668SLeonid Yegoshin LoadWU(addr, value, res); 168534c2f668SLeonid Yegoshin if (res) 168634c2f668SLeonid Yegoshin goto fault; 168734c2f668SLeonid Yegoshin regs->regs[reg] = value; 168834c2f668SLeonid Yegoshin goto success; 168934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 169034c2f668SLeonid Yegoshin 169134c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 169234c2f668SLeonid Yegoshin goto sigill; 169334c2f668SLeonid Yegoshin 169434c2f668SLeonid Yegoshin loadDW: 169534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 169634c2f668SLeonid Yegoshin /* 169734c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 169834c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 169934c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 170034c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 170134c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 170234c2f668SLeonid Yegoshin */ 170334c2f668SLeonid Yegoshin if (!access_ok(VERIFY_READ, addr, 8)) 170434c2f668SLeonid Yegoshin goto sigbus; 170534c2f668SLeonid Yegoshin 170634c2f668SLeonid Yegoshin LoadDW(addr, value, res); 170734c2f668SLeonid Yegoshin if (res) 170834c2f668SLeonid Yegoshin goto fault; 170934c2f668SLeonid Yegoshin regs->regs[reg] = value; 171034c2f668SLeonid Yegoshin goto success; 171134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 171234c2f668SLeonid Yegoshin 171334c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 171434c2f668SLeonid Yegoshin goto sigill; 171534c2f668SLeonid Yegoshin 171634c2f668SLeonid Yegoshin storeHW: 171734c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 2)) 171834c2f668SLeonid Yegoshin goto sigbus; 171934c2f668SLeonid Yegoshin 172034c2f668SLeonid Yegoshin value = regs->regs[reg]; 172134c2f668SLeonid Yegoshin StoreHW(addr, value, res); 172234c2f668SLeonid Yegoshin if (res) 172334c2f668SLeonid Yegoshin goto fault; 172434c2f668SLeonid Yegoshin goto success; 172534c2f668SLeonid Yegoshin 172634c2f668SLeonid Yegoshin storeW: 172734c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 4)) 172834c2f668SLeonid Yegoshin goto sigbus; 172934c2f668SLeonid Yegoshin 173034c2f668SLeonid Yegoshin value = regs->regs[reg]; 173134c2f668SLeonid Yegoshin StoreW(addr, value, res); 173234c2f668SLeonid Yegoshin if (res) 173334c2f668SLeonid Yegoshin goto fault; 173434c2f668SLeonid Yegoshin goto success; 173534c2f668SLeonid Yegoshin 173634c2f668SLeonid Yegoshin storeDW: 173734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 173834c2f668SLeonid Yegoshin /* 173934c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 174034c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 174134c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 174234c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 174334c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 174434c2f668SLeonid Yegoshin */ 174534c2f668SLeonid Yegoshin if (!access_ok(VERIFY_WRITE, addr, 8)) 174634c2f668SLeonid Yegoshin goto sigbus; 174734c2f668SLeonid Yegoshin 174834c2f668SLeonid Yegoshin value = regs->regs[reg]; 174934c2f668SLeonid Yegoshin StoreDW(addr, value, res); 175034c2f668SLeonid Yegoshin if (res) 175134c2f668SLeonid Yegoshin goto fault; 175234c2f668SLeonid Yegoshin goto success; 175334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 175434c2f668SLeonid Yegoshin 175534c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 175634c2f668SLeonid Yegoshin goto sigill; 175734c2f668SLeonid Yegoshin 175834c2f668SLeonid Yegoshin success: 175934c2f668SLeonid Yegoshin regs->cp0_epc = contpc; /* advance or branch */ 176034c2f668SLeonid Yegoshin 176134c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS 176234c2f668SLeonid Yegoshin unaligned_instructions++; 176334c2f668SLeonid Yegoshin #endif 176434c2f668SLeonid Yegoshin return; 176534c2f668SLeonid Yegoshin 176634c2f668SLeonid Yegoshin fault: 176734c2f668SLeonid Yegoshin /* roll back jump/branch */ 176834c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 176934c2f668SLeonid Yegoshin regs->regs[31] = orig31; 177034c2f668SLeonid Yegoshin /* Did we have an exception handler installed? */ 177134c2f668SLeonid Yegoshin if (fixup_exception(regs)) 177234c2f668SLeonid Yegoshin return; 177334c2f668SLeonid Yegoshin 177434c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs); 177534c2f668SLeonid Yegoshin force_sig(SIGSEGV, current); 177634c2f668SLeonid Yegoshin 177734c2f668SLeonid Yegoshin return; 177834c2f668SLeonid Yegoshin 177934c2f668SLeonid Yegoshin sigbus: 178034c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs); 178134c2f668SLeonid Yegoshin force_sig(SIGBUS, current); 178234c2f668SLeonid Yegoshin 178334c2f668SLeonid Yegoshin return; 178434c2f668SLeonid Yegoshin 178534c2f668SLeonid Yegoshin sigill: 178634c2f668SLeonid Yegoshin die_if_kernel 178734c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs); 1788a6d5ff04SDavid Daney force_sig(SIGILL, current); 17891da177e4SLinus Torvalds } 17901da177e4SLinus Torvalds 1791451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr) 1792451b001bSSteven J. Hill { 1793451b001bSSteven J. Hill unsigned long value; 1794451b001bSSteven J. Hill unsigned int res; 1795451b001bSSteven J. Hill int reg; 1796451b001bSSteven J. Hill unsigned long orig31; 1797451b001bSSteven J. Hill u16 __user *pc16; 1798451b001bSSteven J. Hill unsigned long origpc; 1799451b001bSSteven J. Hill union mips16e_instruction mips16inst, oldinst; 1800451b001bSSteven J. Hill 1801451b001bSSteven J. Hill origpc = regs->cp0_epc; 1802451b001bSSteven J. Hill orig31 = regs->regs[31]; 1803451b001bSSteven J. Hill pc16 = (unsigned short __user *)msk_isa16_mode(origpc); 1804451b001bSSteven J. Hill /* 1805451b001bSSteven J. Hill * This load never faults. 1806451b001bSSteven J. Hill */ 1807451b001bSSteven J. Hill __get_user(mips16inst.full, pc16); 1808451b001bSSteven J. Hill oldinst = mips16inst; 1809451b001bSSteven J. Hill 1810451b001bSSteven J. Hill /* skip EXTEND instruction */ 1811451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_extend_op) { 1812451b001bSSteven J. Hill pc16++; 1813451b001bSSteven J. Hill __get_user(mips16inst.full, pc16); 1814451b001bSSteven J. Hill } else if (delay_slot(regs)) { 1815451b001bSSteven J. Hill /* skip jump instructions */ 1816451b001bSSteven J. Hill /* JAL/JALX are 32 bits but have OPCODE in first short int */ 1817451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_jal_op) 1818451b001bSSteven J. Hill pc16++; 1819451b001bSSteven J. Hill pc16++; 1820451b001bSSteven J. Hill if (get_user(mips16inst.full, pc16)) 1821451b001bSSteven J. Hill goto sigbus; 1822451b001bSSteven J. Hill } 1823451b001bSSteven J. Hill 1824451b001bSSteven J. Hill switch (mips16inst.ri.opcode) { 1825451b001bSSteven J. Hill case MIPS16e_i64_op: /* I64 or RI64 instruction */ 1826451b001bSSteven J. Hill switch (mips16inst.i64.func) { /* I64/RI64 func field check */ 1827451b001bSSteven J. Hill case MIPS16e_ldpc_func: 1828451b001bSSteven J. Hill case MIPS16e_ldsp_func: 1829451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry]; 1830451b001bSSteven J. Hill goto loadDW; 1831451b001bSSteven J. Hill 1832451b001bSSteven J. Hill case MIPS16e_sdsp_func: 1833451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry]; 1834451b001bSSteven J. Hill goto writeDW; 1835451b001bSSteven J. Hill 1836451b001bSSteven J. Hill case MIPS16e_sdrasp_func: 1837451b001bSSteven J. Hill reg = 29; /* GPRSP */ 1838451b001bSSteven J. Hill goto writeDW; 1839451b001bSSteven J. Hill } 1840451b001bSSteven J. Hill 1841451b001bSSteven J. Hill goto sigbus; 1842451b001bSSteven J. Hill 1843451b001bSSteven J. Hill case MIPS16e_swsp_op: 1844451b001bSSteven J. Hill case MIPS16e_lwpc_op: 1845451b001bSSteven J. Hill case MIPS16e_lwsp_op: 1846451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri.rx]; 1847451b001bSSteven J. Hill break; 1848451b001bSSteven J. Hill 1849451b001bSSteven J. Hill case MIPS16e_i8_op: 1850451b001bSSteven J. Hill if (mips16inst.i8.func != MIPS16e_swrasp_func) 1851451b001bSSteven J. Hill goto sigbus; 1852451b001bSSteven J. Hill reg = 29; /* GPRSP */ 1853451b001bSSteven J. Hill break; 1854451b001bSSteven J. Hill 1855451b001bSSteven J. Hill default: 1856451b001bSSteven J. Hill reg = reg16to32[mips16inst.rri.ry]; 1857451b001bSSteven J. Hill break; 1858451b001bSSteven J. Hill } 1859451b001bSSteven J. Hill 1860451b001bSSteven J. Hill switch (mips16inst.ri.opcode) { 1861451b001bSSteven J. Hill 1862451b001bSSteven J. Hill case MIPS16e_lb_op: 1863451b001bSSteven J. Hill case MIPS16e_lbu_op: 1864451b001bSSteven J. Hill case MIPS16e_sb_op: 1865451b001bSSteven J. Hill goto sigbus; 1866451b001bSSteven J. Hill 1867451b001bSSteven J. Hill case MIPS16e_lh_op: 1868451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 2)) 1869451b001bSSteven J. Hill goto sigbus; 1870451b001bSSteven J. Hill 1871451b001bSSteven J. Hill LoadHW(addr, value, res); 1872451b001bSSteven J. Hill if (res) 1873451b001bSSteven J. Hill goto fault; 1874451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1875451b001bSSteven J. Hill regs->regs[reg] = value; 1876451b001bSSteven J. Hill break; 1877451b001bSSteven J. Hill 1878451b001bSSteven J. Hill case MIPS16e_lhu_op: 1879451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 2)) 1880451b001bSSteven J. Hill goto sigbus; 1881451b001bSSteven J. Hill 1882451b001bSSteven J. Hill LoadHWU(addr, value, res); 1883451b001bSSteven J. Hill if (res) 1884451b001bSSteven J. Hill goto fault; 1885451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1886451b001bSSteven J. Hill regs->regs[reg] = value; 1887451b001bSSteven J. Hill break; 1888451b001bSSteven J. Hill 1889451b001bSSteven J. Hill case MIPS16e_lw_op: 1890451b001bSSteven J. Hill case MIPS16e_lwpc_op: 1891451b001bSSteven J. Hill case MIPS16e_lwsp_op: 1892451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 4)) 1893451b001bSSteven J. Hill goto sigbus; 1894451b001bSSteven J. Hill 1895451b001bSSteven J. Hill LoadW(addr, value, res); 1896451b001bSSteven J. Hill if (res) 1897451b001bSSteven J. Hill goto fault; 1898451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1899451b001bSSteven J. Hill regs->regs[reg] = value; 1900451b001bSSteven J. Hill break; 1901451b001bSSteven J. Hill 1902451b001bSSteven J. Hill case MIPS16e_lwu_op: 1903451b001bSSteven J. Hill #ifdef CONFIG_64BIT 1904451b001bSSteven J. Hill /* 1905451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 1906451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 1907451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 1908451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 1909451b001bSSteven J. Hill * instructions on 32-bit kernels. 1910451b001bSSteven J. Hill */ 1911451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 4)) 1912451b001bSSteven J. Hill goto sigbus; 1913451b001bSSteven J. Hill 1914451b001bSSteven J. Hill LoadWU(addr, value, res); 1915451b001bSSteven J. Hill if (res) 1916451b001bSSteven J. Hill goto fault; 1917451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1918451b001bSSteven J. Hill regs->regs[reg] = value; 1919451b001bSSteven J. Hill break; 1920451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 1921451b001bSSteven J. Hill 1922451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 1923451b001bSSteven J. Hill goto sigill; 1924451b001bSSteven J. Hill 1925451b001bSSteven J. Hill case MIPS16e_ld_op: 1926451b001bSSteven J. Hill loadDW: 1927451b001bSSteven J. Hill #ifdef CONFIG_64BIT 1928451b001bSSteven J. Hill /* 1929451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 1930451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 1931451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 1932451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 1933451b001bSSteven J. Hill * instructions on 32-bit kernels. 1934451b001bSSteven J. Hill */ 1935451b001bSSteven J. Hill if (!access_ok(VERIFY_READ, addr, 8)) 1936451b001bSSteven J. Hill goto sigbus; 1937451b001bSSteven J. Hill 1938451b001bSSteven J. Hill LoadDW(addr, value, res); 1939451b001bSSteven J. Hill if (res) 1940451b001bSSteven J. Hill goto fault; 1941451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1942451b001bSSteven J. Hill regs->regs[reg] = value; 1943451b001bSSteven J. Hill break; 1944451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 1945451b001bSSteven J. Hill 1946451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 1947451b001bSSteven J. Hill goto sigill; 1948451b001bSSteven J. Hill 1949451b001bSSteven J. Hill case MIPS16e_sh_op: 1950451b001bSSteven J. Hill if (!access_ok(VERIFY_WRITE, addr, 2)) 1951451b001bSSteven J. Hill goto sigbus; 1952451b001bSSteven J. Hill 1953451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1954451b001bSSteven J. Hill value = regs->regs[reg]; 1955451b001bSSteven J. Hill StoreHW(addr, value, res); 1956451b001bSSteven J. Hill if (res) 1957451b001bSSteven J. Hill goto fault; 1958451b001bSSteven J. Hill break; 1959451b001bSSteven J. Hill 1960451b001bSSteven J. Hill case MIPS16e_sw_op: 1961451b001bSSteven J. Hill case MIPS16e_swsp_op: 1962451b001bSSteven J. Hill case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */ 1963451b001bSSteven J. Hill if (!access_ok(VERIFY_WRITE, addr, 4)) 1964451b001bSSteven J. Hill goto sigbus; 1965451b001bSSteven J. Hill 1966451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1967451b001bSSteven J. Hill value = regs->regs[reg]; 1968451b001bSSteven J. Hill StoreW(addr, value, res); 1969451b001bSSteven J. Hill if (res) 1970451b001bSSteven J. Hill goto fault; 1971451b001bSSteven J. Hill break; 1972451b001bSSteven J. Hill 1973451b001bSSteven J. Hill case MIPS16e_sd_op: 1974451b001bSSteven J. Hill writeDW: 1975451b001bSSteven J. Hill #ifdef CONFIG_64BIT 1976451b001bSSteven J. Hill /* 1977451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 1978451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 1979451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 1980451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 1981451b001bSSteven J. Hill * instructions on 32-bit kernels. 1982451b001bSSteven J. Hill */ 1983451b001bSSteven J. Hill if (!access_ok(VERIFY_WRITE, addr, 8)) 1984451b001bSSteven J. Hill goto sigbus; 1985451b001bSSteven J. Hill 1986451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1987451b001bSSteven J. Hill value = regs->regs[reg]; 1988451b001bSSteven J. Hill StoreDW(addr, value, res); 1989451b001bSSteven J. Hill if (res) 1990451b001bSSteven J. Hill goto fault; 1991451b001bSSteven J. Hill break; 1992451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 1993451b001bSSteven J. Hill 1994451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 1995451b001bSSteven J. Hill goto sigill; 1996451b001bSSteven J. Hill 1997451b001bSSteven J. Hill default: 1998451b001bSSteven J. Hill /* 1999451b001bSSteven J. Hill * Pheeee... We encountered an yet unknown instruction or 2000451b001bSSteven J. Hill * cache coherence problem. Die sucker, die ... 2001451b001bSSteven J. Hill */ 2002451b001bSSteven J. Hill goto sigill; 2003451b001bSSteven J. Hill } 2004451b001bSSteven J. Hill 2005451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS 2006451b001bSSteven J. Hill unaligned_instructions++; 2007451b001bSSteven J. Hill #endif 2008451b001bSSteven J. Hill 2009451b001bSSteven J. Hill return; 2010451b001bSSteven J. Hill 2011451b001bSSteven J. Hill fault: 2012451b001bSSteven J. Hill /* roll back jump/branch */ 2013451b001bSSteven J. Hill regs->cp0_epc = origpc; 2014451b001bSSteven J. Hill regs->regs[31] = orig31; 2015451b001bSSteven J. Hill /* Did we have an exception handler installed? */ 2016451b001bSSteven J. Hill if (fixup_exception(regs)) 2017451b001bSSteven J. Hill return; 2018451b001bSSteven J. Hill 2019451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs); 2020451b001bSSteven J. Hill force_sig(SIGSEGV, current); 2021451b001bSSteven J. Hill 2022451b001bSSteven J. Hill return; 2023451b001bSSteven J. Hill 2024451b001bSSteven J. Hill sigbus: 2025451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs); 2026451b001bSSteven J. Hill force_sig(SIGBUS, current); 2027451b001bSSteven J. Hill 2028451b001bSSteven J. Hill return; 2029451b001bSSteven J. Hill 2030451b001bSSteven J. Hill sigill: 2031451b001bSSteven J. Hill die_if_kernel 2032451b001bSSteven J. Hill ("Unhandled kernel unaligned access or invalid instruction", regs); 2033451b001bSSteven J. Hill force_sig(SIGILL, current); 2034451b001bSSteven J. Hill } 2035fc192e50STony Wu 20361da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs) 20371da177e4SLinus Torvalds { 2038c3fc5cd5SRalf Baechle enum ctx_state prev_state; 2039fe00f943SRalf Baechle unsigned int __user *pc; 20401da177e4SLinus Torvalds mm_segment_t seg; 20411da177e4SLinus Torvalds 2042c3fc5cd5SRalf Baechle prev_state = exception_enter(); 20437f788d2dSDeng-Cheng Zhu perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 2044a8b0ca17SPeter Zijlstra 1, regs, regs->cp0_badvaddr); 20451da177e4SLinus Torvalds /* 20461da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction? 20471da177e4SLinus Torvalds */ 204834c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == regs->cp0_epc) 20491da177e4SLinus Torvalds goto sigbus; 20501da177e4SLinus Torvalds 2051293c5bd1SRalf Baechle if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) 20521da177e4SLinus Torvalds goto sigbus; 20536312e0eeSAtsushi Nemoto if (unaligned_action == UNALIGNED_ACTION_SIGNAL) 20546312e0eeSAtsushi Nemoto goto sigbus; 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds /* 20571da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception. 20581da177e4SLinus Torvalds * This is all so but ugly ... 20591da177e4SLinus Torvalds */ 206034c2f668SLeonid Yegoshin 206134c2f668SLeonid Yegoshin /* 206234c2f668SLeonid Yegoshin * Are we running in microMIPS mode? 206334c2f668SLeonid Yegoshin */ 206434c2f668SLeonid Yegoshin if (get_isa16_mode(regs->cp0_epc)) { 206534c2f668SLeonid Yegoshin /* 206634c2f668SLeonid Yegoshin * Did we catch a fault trying to load an instruction in 206734c2f668SLeonid Yegoshin * 16-bit mode? 206834c2f668SLeonid Yegoshin */ 206934c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc)) 207034c2f668SLeonid Yegoshin goto sigbus; 207134c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW) 207234c2f668SLeonid Yegoshin show_registers(regs); 207334c2f668SLeonid Yegoshin 207434c2f668SLeonid Yegoshin if (cpu_has_mmips) { 207534c2f668SLeonid Yegoshin seg = get_fs(); 207634c2f668SLeonid Yegoshin if (!user_mode(regs)) 207734c2f668SLeonid Yegoshin set_fs(KERNEL_DS); 207834c2f668SLeonid Yegoshin emulate_load_store_microMIPS(regs, 207934c2f668SLeonid Yegoshin (void __user *)regs->cp0_badvaddr); 208034c2f668SLeonid Yegoshin set_fs(seg); 208134c2f668SLeonid Yegoshin 208234c2f668SLeonid Yegoshin return; 208334c2f668SLeonid Yegoshin } 208434c2f668SLeonid Yegoshin 2085451b001bSSteven J. Hill if (cpu_has_mips16) { 2086451b001bSSteven J. Hill seg = get_fs(); 2087451b001bSSteven J. Hill if (!user_mode(regs)) 2088451b001bSSteven J. Hill set_fs(KERNEL_DS); 2089451b001bSSteven J. Hill emulate_load_store_MIPS16e(regs, 2090451b001bSSteven J. Hill (void __user *)regs->cp0_badvaddr); 2091451b001bSSteven J. Hill set_fs(seg); 2092451b001bSSteven J. Hill 2093451b001bSSteven J. Hill return; 2094451b001bSSteven J. Hill } 2095451b001bSSteven J. Hill 209634c2f668SLeonid Yegoshin goto sigbus; 209734c2f668SLeonid Yegoshin } 209834c2f668SLeonid Yegoshin 209934c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW) 210034c2f668SLeonid Yegoshin show_registers(regs); 210134c2f668SLeonid Yegoshin pc = (unsigned int __user *)exception_epc(regs); 210234c2f668SLeonid Yegoshin 21031da177e4SLinus Torvalds seg = get_fs(); 21041da177e4SLinus Torvalds if (!user_mode(regs)) 21051da177e4SLinus Torvalds set_fs(KERNEL_DS); 21067f18f151SRalf Baechle emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); 21071da177e4SLinus Torvalds set_fs(seg); 21081da177e4SLinus Torvalds 21091da177e4SLinus Torvalds return; 21101da177e4SLinus Torvalds 21111da177e4SLinus Torvalds sigbus: 21121da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs); 21131da177e4SLinus Torvalds force_sig(SIGBUS, current); 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds /* 21161da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc 21171da177e4SLinus Torvalds */ 2118c3fc5cd5SRalf Baechle exception_exit(prev_state); 21191da177e4SLinus Torvalds } 21206312e0eeSAtsushi Nemoto 21216312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 21226312e0eeSAtsushi Nemoto extern struct dentry *mips_debugfs_dir; 21236312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void) 21246312e0eeSAtsushi Nemoto { 21256312e0eeSAtsushi Nemoto struct dentry *d; 21266312e0eeSAtsushi Nemoto 21276312e0eeSAtsushi Nemoto if (!mips_debugfs_dir) 21286312e0eeSAtsushi Nemoto return -ENODEV; 21296312e0eeSAtsushi Nemoto d = debugfs_create_u32("unaligned_instructions", S_IRUGO, 21306312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_instructions); 2131b517531cSZhaolei if (!d) 2132b517531cSZhaolei return -ENOMEM; 21336312e0eeSAtsushi Nemoto d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, 21346312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_action); 2135b517531cSZhaolei if (!d) 2136b517531cSZhaolei return -ENOMEM; 21376312e0eeSAtsushi Nemoto return 0; 21386312e0eeSAtsushi Nemoto } 21396312e0eeSAtsushi Nemoto __initcall(debugfs_unaligned); 21406312e0eeSAtsushi Nemoto #endif 2141