11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Handle unaligned accesses by emulation. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 51da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 61da177e4SLinus Torvalds * for more details. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle 91da177e4SLinus Torvalds * Copyright (C) 1999 Silicon Graphics, Inc. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This file contains exception handler for address error exception with the 121da177e4SLinus Torvalds * special capability to execute faulting instructions in software. The 131da177e4SLinus Torvalds * handler does not try to handle the case when the program counter points 141da177e4SLinus Torvalds * to an address not aligned to a word boundary. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * Putting data to unaligned addresses is a bad practice even on Intel where 171da177e4SLinus Torvalds * only the performance is affected. Much worse is that such code is non- 181da177e4SLinus Torvalds * portable. Due to several programs that die on MIPS due to alignment 191da177e4SLinus Torvalds * problems I decided to implement this handler anyway though I originally 201da177e4SLinus Torvalds * didn't intend to do this at all for user code. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * For now I enable fixing of address errors by default to make life easier. 231da177e4SLinus Torvalds * I however intend to disable this somewhen in the future when the alignment 241da177e4SLinus Torvalds * problems with user programs have been fixed. For programmers this is the 251da177e4SLinus Torvalds * right way to go. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * Fixing address errors is a per process option. The option is inherited 281da177e4SLinus Torvalds * across fork(2) and execve(2) calls. If you really want to use the 291da177e4SLinus Torvalds * option in your user programs - I discourage the use of the software 301da177e4SLinus Torvalds * emulation strongly - use the following code in your userland stuff: 311da177e4SLinus Torvalds * 321da177e4SLinus Torvalds * #include <sys/sysmips.h> 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * ... 351da177e4SLinus Torvalds * sysmips(MIPS_FIXADE, x); 361da177e4SLinus Torvalds * ... 371da177e4SLinus Torvalds * 381da177e4SLinus Torvalds * The argument x is 0 for disabling software emulation, enabled otherwise. 391da177e4SLinus Torvalds * 401da177e4SLinus Torvalds * Below a little program to play around with this feature. 411da177e4SLinus Torvalds * 421da177e4SLinus Torvalds * #include <stdio.h> 431da177e4SLinus Torvalds * #include <sys/sysmips.h> 441da177e4SLinus Torvalds * 451da177e4SLinus Torvalds * struct foo { 461da177e4SLinus Torvalds * unsigned char bar[8]; 471da177e4SLinus Torvalds * }; 481da177e4SLinus Torvalds * 491da177e4SLinus Torvalds * main(int argc, char *argv[]) 501da177e4SLinus Torvalds * { 511da177e4SLinus Torvalds * struct foo x = {0, 1, 2, 3, 4, 5, 6, 7}; 521da177e4SLinus Torvalds * unsigned int *p = (unsigned int *) (x.bar + 3); 531da177e4SLinus Torvalds * int i; 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds * if (argc > 1) 561da177e4SLinus Torvalds * sysmips(MIPS_FIXADE, atoi(argv[1])); 571da177e4SLinus Torvalds * 581da177e4SLinus Torvalds * printf("*p = %08lx\n", *p); 591da177e4SLinus Torvalds * 601da177e4SLinus Torvalds * *p = 0xdeadface; 611da177e4SLinus Torvalds * 621da177e4SLinus Torvalds * for(i = 0; i <= 7; i++) 631da177e4SLinus Torvalds * printf("%02x ", x.bar[i]); 641da177e4SLinus Torvalds * printf("\n"); 651da177e4SLinus Torvalds * } 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * Coprocessor loads are not supported; I think this case is unimportant 681da177e4SLinus Torvalds * in the practice. 691da177e4SLinus Torvalds * 701da177e4SLinus Torvalds * TODO: Handle ndc (attempted store to doubleword in uncached memory) 711da177e4SLinus Torvalds * exception for the R6000. 721da177e4SLinus Torvalds * A store crossing a page boundary might be executed only partially. 731da177e4SLinus Torvalds * Undo the partial store in this case. 741da177e4SLinus Torvalds */ 751da177e4SLinus Torvalds #include <linux/mm.h> 761da177e4SLinus Torvalds #include <linux/module.h> 771da177e4SLinus Torvalds #include <linux/signal.h> 781da177e4SLinus Torvalds #include <linux/smp.h> 79e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 806312e0eeSAtsushi Nemoto #include <linux/debugfs.h> 811da177e4SLinus Torvalds #include <asm/asm.h> 821da177e4SLinus Torvalds #include <asm/branch.h> 831da177e4SLinus Torvalds #include <asm/byteorder.h> 84*69f3a7deSRalf Baechle #include <asm/cop2.h> 851da177e4SLinus Torvalds #include <asm/inst.h> 861da177e4SLinus Torvalds #include <asm/uaccess.h> 871da177e4SLinus Torvalds #include <asm/system.h> 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds #define STR(x) __STR(x) 901da177e4SLinus Torvalds #define __STR(x) #x 911da177e4SLinus Torvalds 926312e0eeSAtsushi Nemoto enum { 936312e0eeSAtsushi Nemoto UNALIGNED_ACTION_QUIET, 946312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SIGNAL, 956312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SHOW, 966312e0eeSAtsushi Nemoto }; 976312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 986312e0eeSAtsushi Nemoto static u32 unaligned_instructions; 996312e0eeSAtsushi Nemoto static u32 unaligned_action; 1006312e0eeSAtsushi Nemoto #else 1016312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET 1021da177e4SLinus Torvalds #endif 1036312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs); 1041da177e4SLinus Torvalds 1057f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs, 1067f18f151SRalf Baechle void __user *addr, unsigned int __user *pc) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds union mips_instruction insn; 1091da177e4SLinus Torvalds unsigned long value; 1101da177e4SLinus Torvalds unsigned int res; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds regs->regs[0] = 0; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* 1151da177e4SLinus Torvalds * This load never faults. 1161da177e4SLinus Torvalds */ 117fe00f943SRalf Baechle __get_user(insn.word, pc); 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds switch (insn.i_format.opcode) { 1201da177e4SLinus Torvalds /* 1211da177e4SLinus Torvalds * These are instructions that a compiler doesn't generate. We 1221da177e4SLinus Torvalds * can assume therefore that the code is MIPS-aware and 1231da177e4SLinus Torvalds * really buggy. Emulating these instructions would break the 1241da177e4SLinus Torvalds * semantics anyway. 1251da177e4SLinus Torvalds */ 1261da177e4SLinus Torvalds case ll_op: 1271da177e4SLinus Torvalds case lld_op: 1281da177e4SLinus Torvalds case sc_op: 1291da177e4SLinus Torvalds case scd_op: 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds /* 1321da177e4SLinus Torvalds * For these instructions the only way to create an address 1331da177e4SLinus Torvalds * error is an attempted access to kernel/supervisor address 1341da177e4SLinus Torvalds * space. 1351da177e4SLinus Torvalds */ 1361da177e4SLinus Torvalds case ldl_op: 1371da177e4SLinus Torvalds case ldr_op: 1381da177e4SLinus Torvalds case lwl_op: 1391da177e4SLinus Torvalds case lwr_op: 1401da177e4SLinus Torvalds case sdl_op: 1411da177e4SLinus Torvalds case sdr_op: 1421da177e4SLinus Torvalds case swl_op: 1431da177e4SLinus Torvalds case swr_op: 1441da177e4SLinus Torvalds case lb_op: 1451da177e4SLinus Torvalds case lbu_op: 1461da177e4SLinus Torvalds case sb_op: 1471da177e4SLinus Torvalds goto sigbus; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /* 1501da177e4SLinus Torvalds * The remaining opcodes are the ones that are really of interest. 1511da177e4SLinus Torvalds */ 1521da177e4SLinus Torvalds case lh_op: 1531da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 1541da177e4SLinus Torvalds goto sigbus; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds __asm__ __volatile__ (".set\tnoat\n" 1571da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 1581da177e4SLinus Torvalds "1:\tlb\t%0, 0(%2)\n" 1591da177e4SLinus Torvalds "2:\tlbu\t$1, 1(%2)\n\t" 1601da177e4SLinus Torvalds #endif 1611da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 1621da177e4SLinus Torvalds "1:\tlb\t%0, 1(%2)\n" 1631da177e4SLinus Torvalds "2:\tlbu\t$1, 0(%2)\n\t" 1641da177e4SLinus Torvalds #endif 1651da177e4SLinus Torvalds "sll\t%0, 0x8\n\t" 1661da177e4SLinus Torvalds "or\t%0, $1\n\t" 1671da177e4SLinus Torvalds "li\t%1, 0\n" 1681da177e4SLinus Torvalds "3:\t.set\tat\n\t" 1691da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 1701da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 1711da177e4SLinus Torvalds "j\t3b\n\t" 1721da177e4SLinus Torvalds ".previous\n\t" 1731da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 1741da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 1751da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 1761da177e4SLinus Torvalds ".previous" 1771da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 1781da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 1791da177e4SLinus Torvalds if (res) 1801da177e4SLinus Torvalds goto fault; 1817f18f151SRalf Baechle compute_return_epc(regs); 1827f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 1831da177e4SLinus Torvalds break; 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds case lw_op: 1861da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 1871da177e4SLinus Torvalds goto sigbus; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds __asm__ __volatile__ ( 1901da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 1911da177e4SLinus Torvalds "1:\tlwl\t%0, (%2)\n" 1921da177e4SLinus Torvalds "2:\tlwr\t%0, 3(%2)\n\t" 1931da177e4SLinus Torvalds #endif 1941da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 1951da177e4SLinus Torvalds "1:\tlwl\t%0, 3(%2)\n" 1961da177e4SLinus Torvalds "2:\tlwr\t%0, (%2)\n\t" 1971da177e4SLinus Torvalds #endif 1981da177e4SLinus Torvalds "li\t%1, 0\n" 1991da177e4SLinus Torvalds "3:\t.section\t.fixup,\"ax\"\n\t" 2001da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 2011da177e4SLinus Torvalds "j\t3b\n\t" 2021da177e4SLinus Torvalds ".previous\n\t" 2031da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 2041da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 2051da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 2061da177e4SLinus Torvalds ".previous" 2071da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 2081da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 2091da177e4SLinus Torvalds if (res) 2101da177e4SLinus Torvalds goto fault; 2117f18f151SRalf Baechle compute_return_epc(regs); 2127f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 2131da177e4SLinus Torvalds break; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds case lhu_op: 2161da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 2171da177e4SLinus Torvalds goto sigbus; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds __asm__ __volatile__ ( 2201da177e4SLinus Torvalds ".set\tnoat\n" 2211da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 2221da177e4SLinus Torvalds "1:\tlbu\t%0, 0(%2)\n" 2231da177e4SLinus Torvalds "2:\tlbu\t$1, 1(%2)\n\t" 2241da177e4SLinus Torvalds #endif 2251da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 2261da177e4SLinus Torvalds "1:\tlbu\t%0, 1(%2)\n" 2271da177e4SLinus Torvalds "2:\tlbu\t$1, 0(%2)\n\t" 2281da177e4SLinus Torvalds #endif 2291da177e4SLinus Torvalds "sll\t%0, 0x8\n\t" 2301da177e4SLinus Torvalds "or\t%0, $1\n\t" 2311da177e4SLinus Torvalds "li\t%1, 0\n" 2321da177e4SLinus Torvalds "3:\t.set\tat\n\t" 2331da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 2341da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 2351da177e4SLinus Torvalds "j\t3b\n\t" 2361da177e4SLinus Torvalds ".previous\n\t" 2371da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 2381da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 2391da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 2401da177e4SLinus Torvalds ".previous" 2411da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 2421da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 2431da177e4SLinus Torvalds if (res) 2441da177e4SLinus Torvalds goto fault; 2457f18f151SRalf Baechle compute_return_epc(regs); 2467f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 2471da177e4SLinus Torvalds break; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds case lwu_op: 250875d43e7SRalf Baechle #ifdef CONFIG_64BIT 2511da177e4SLinus Torvalds /* 2521da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 2531da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 2541da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 2551da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 2561da177e4SLinus Torvalds * instructions on 32-bit kernels. 2571da177e4SLinus Torvalds */ 2581da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 2591da177e4SLinus Torvalds goto sigbus; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds __asm__ __volatile__ ( 2621da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 2631da177e4SLinus Torvalds "1:\tlwl\t%0, (%2)\n" 2641da177e4SLinus Torvalds "2:\tlwr\t%0, 3(%2)\n\t" 2651da177e4SLinus Torvalds #endif 2661da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 2671da177e4SLinus Torvalds "1:\tlwl\t%0, 3(%2)\n" 2681da177e4SLinus Torvalds "2:\tlwr\t%0, (%2)\n\t" 2691da177e4SLinus Torvalds #endif 2701da177e4SLinus Torvalds "dsll\t%0, %0, 32\n\t" 2711da177e4SLinus Torvalds "dsrl\t%0, %0, 32\n\t" 2721da177e4SLinus Torvalds "li\t%1, 0\n" 2731da177e4SLinus Torvalds "3:\t.section\t.fixup,\"ax\"\n\t" 2741da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 2751da177e4SLinus Torvalds "j\t3b\n\t" 2761da177e4SLinus Torvalds ".previous\n\t" 2771da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 2781da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 2791da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 2801da177e4SLinus Torvalds ".previous" 2811da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 2821da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 2831da177e4SLinus Torvalds if (res) 2841da177e4SLinus Torvalds goto fault; 2857f18f151SRalf Baechle compute_return_epc(regs); 2867f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 2871da177e4SLinus Torvalds break; 288875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 2911da177e4SLinus Torvalds goto sigill; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds case ld_op: 294875d43e7SRalf Baechle #ifdef CONFIG_64BIT 2951da177e4SLinus Torvalds /* 2961da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 2971da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 2981da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 2991da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 3001da177e4SLinus Torvalds * instructions on 32-bit kernels. 3011da177e4SLinus Torvalds */ 3021da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 8)) 3031da177e4SLinus Torvalds goto sigbus; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds __asm__ __volatile__ ( 3061da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 3071da177e4SLinus Torvalds "1:\tldl\t%0, (%2)\n" 3081da177e4SLinus Torvalds "2:\tldr\t%0, 7(%2)\n\t" 3091da177e4SLinus Torvalds #endif 3101da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 3111da177e4SLinus Torvalds "1:\tldl\t%0, 7(%2)\n" 3121da177e4SLinus Torvalds "2:\tldr\t%0, (%2)\n\t" 3131da177e4SLinus Torvalds #endif 3141da177e4SLinus Torvalds "li\t%1, 0\n" 3151da177e4SLinus Torvalds "3:\t.section\t.fixup,\"ax\"\n\t" 3161da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 3171da177e4SLinus Torvalds "j\t3b\n\t" 3181da177e4SLinus Torvalds ".previous\n\t" 3191da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 3201da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 3211da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 3221da177e4SLinus Torvalds ".previous" 3231da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 3241da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 3251da177e4SLinus Torvalds if (res) 3261da177e4SLinus Torvalds goto fault; 3277f18f151SRalf Baechle compute_return_epc(regs); 3287f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 3291da177e4SLinus Torvalds break; 330875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 3331da177e4SLinus Torvalds goto sigill; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds case sh_op: 3361da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 2)) 3371da177e4SLinus Torvalds goto sigbus; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 3401da177e4SLinus Torvalds __asm__ __volatile__ ( 3411da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 3421da177e4SLinus Torvalds ".set\tnoat\n" 3431da177e4SLinus Torvalds "1:\tsb\t%1, 1(%2)\n\t" 3441da177e4SLinus Torvalds "srl\t$1, %1, 0x8\n" 3451da177e4SLinus Torvalds "2:\tsb\t$1, 0(%2)\n\t" 3461da177e4SLinus Torvalds ".set\tat\n\t" 3471da177e4SLinus Torvalds #endif 3481da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 3491da177e4SLinus Torvalds ".set\tnoat\n" 3501da177e4SLinus Torvalds "1:\tsb\t%1, 0(%2)\n\t" 3511da177e4SLinus Torvalds "srl\t$1,%1, 0x8\n" 3521da177e4SLinus Torvalds "2:\tsb\t$1, 1(%2)\n\t" 3531da177e4SLinus Torvalds ".set\tat\n\t" 3541da177e4SLinus Torvalds #endif 3551da177e4SLinus Torvalds "li\t%0, 0\n" 3561da177e4SLinus Torvalds "3:\n\t" 3571da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 3581da177e4SLinus Torvalds "4:\tli\t%0, %3\n\t" 3591da177e4SLinus Torvalds "j\t3b\n\t" 3601da177e4SLinus Torvalds ".previous\n\t" 3611da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 3621da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 3631da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 3641da177e4SLinus Torvalds ".previous" 3651da177e4SLinus Torvalds : "=r" (res) 3661da177e4SLinus Torvalds : "r" (value), "r" (addr), "i" (-EFAULT)); 3671da177e4SLinus Torvalds if (res) 3681da177e4SLinus Torvalds goto fault; 3697f18f151SRalf Baechle compute_return_epc(regs); 3701da177e4SLinus Torvalds break; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds case sw_op: 3731da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 4)) 3741da177e4SLinus Torvalds goto sigbus; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 3771da177e4SLinus Torvalds __asm__ __volatile__ ( 3781da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 3791da177e4SLinus Torvalds "1:\tswl\t%1,(%2)\n" 3801da177e4SLinus Torvalds "2:\tswr\t%1, 3(%2)\n\t" 3811da177e4SLinus Torvalds #endif 3821da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 3831da177e4SLinus Torvalds "1:\tswl\t%1, 3(%2)\n" 3841da177e4SLinus Torvalds "2:\tswr\t%1, (%2)\n\t" 3851da177e4SLinus Torvalds #endif 3861da177e4SLinus Torvalds "li\t%0, 0\n" 3871da177e4SLinus Torvalds "3:\n\t" 3881da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 3891da177e4SLinus Torvalds "4:\tli\t%0, %3\n\t" 3901da177e4SLinus Torvalds "j\t3b\n\t" 3911da177e4SLinus Torvalds ".previous\n\t" 3921da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 3931da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 3941da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 3951da177e4SLinus Torvalds ".previous" 3961da177e4SLinus Torvalds : "=r" (res) 3971da177e4SLinus Torvalds : "r" (value), "r" (addr), "i" (-EFAULT)); 3981da177e4SLinus Torvalds if (res) 3991da177e4SLinus Torvalds goto fault; 4007f18f151SRalf Baechle compute_return_epc(regs); 4011da177e4SLinus Torvalds break; 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds case sd_op: 404875d43e7SRalf Baechle #ifdef CONFIG_64BIT 4051da177e4SLinus Torvalds /* 4061da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 4071da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 4081da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 4091da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 4101da177e4SLinus Torvalds * instructions on 32-bit kernels. 4111da177e4SLinus Torvalds */ 4121da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 8)) 4131da177e4SLinus Torvalds goto sigbus; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 4161da177e4SLinus Torvalds __asm__ __volatile__ ( 4171da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 4181da177e4SLinus Torvalds "1:\tsdl\t%1,(%2)\n" 4191da177e4SLinus Torvalds "2:\tsdr\t%1, 7(%2)\n\t" 4201da177e4SLinus Torvalds #endif 4211da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 4221da177e4SLinus Torvalds "1:\tsdl\t%1, 7(%2)\n" 4231da177e4SLinus Torvalds "2:\tsdr\t%1, (%2)\n\t" 4241da177e4SLinus Torvalds #endif 4251da177e4SLinus Torvalds "li\t%0, 0\n" 4261da177e4SLinus Torvalds "3:\n\t" 4271da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 4281da177e4SLinus Torvalds "4:\tli\t%0, %3\n\t" 4291da177e4SLinus Torvalds "j\t3b\n\t" 4301da177e4SLinus Torvalds ".previous\n\t" 4311da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 4321da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 4331da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 4341da177e4SLinus Torvalds ".previous" 4351da177e4SLinus Torvalds : "=r" (res) 4361da177e4SLinus Torvalds : "r" (value), "r" (addr), "i" (-EFAULT)); 4371da177e4SLinus Torvalds if (res) 4381da177e4SLinus Torvalds goto fault; 4397f18f151SRalf Baechle compute_return_epc(regs); 4401da177e4SLinus Torvalds break; 441875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 4441da177e4SLinus Torvalds goto sigill; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds case lwc1_op: 4471da177e4SLinus Torvalds case ldc1_op: 4481da177e4SLinus Torvalds case swc1_op: 4491da177e4SLinus Torvalds case sdc1_op: 4501da177e4SLinus Torvalds /* 4511da177e4SLinus Torvalds * I herewith declare: this does not happen. So send SIGBUS. 4521da177e4SLinus Torvalds */ 4531da177e4SLinus Torvalds goto sigbus; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds /* 456*69f3a7deSRalf Baechle * COP2 is available to implementor for application specific use. 457*69f3a7deSRalf Baechle * It's up to applications to register a notifier chain and do 458*69f3a7deSRalf Baechle * whatever they have to do, including possible sending of signals. 4591da177e4SLinus Torvalds */ 460*69f3a7deSRalf Baechle case lwc2_op: 461*69f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LWC2_OP, regs); 462*69f3a7deSRalf Baechle break; 463*69f3a7deSRalf Baechle 464*69f3a7deSRalf Baechle case ldc2_op: 465*69f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LDC2_OP, regs); 466*69f3a7deSRalf Baechle break; 467*69f3a7deSRalf Baechle 468*69f3a7deSRalf Baechle case swc2_op: 469*69f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SWC2_OP, regs); 470*69f3a7deSRalf Baechle break; 471*69f3a7deSRalf Baechle 472*69f3a7deSRalf Baechle case sdc2_op: 473*69f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SDC2_OP, regs); 474*69f3a7deSRalf Baechle break; 475*69f3a7deSRalf Baechle 4761da177e4SLinus Torvalds default: 4771da177e4SLinus Torvalds /* 4781da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or 4791da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ... 4801da177e4SLinus Torvalds */ 4811da177e4SLinus Torvalds goto sigill; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds 4846312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 4851da177e4SLinus Torvalds unaligned_instructions++; 4861da177e4SLinus Torvalds #endif 4871da177e4SLinus Torvalds 4887f18f151SRalf Baechle return; 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds fault: 4911da177e4SLinus Torvalds /* Did we have an exception handler installed? */ 4921da177e4SLinus Torvalds if (fixup_exception(regs)) 4937f18f151SRalf Baechle return; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 496a6d5ff04SDavid Daney force_sig(SIGSEGV, current); 4971da177e4SLinus Torvalds 4987f18f151SRalf Baechle return; 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds sigbus: 5011da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 502a6d5ff04SDavid Daney force_sig(SIGBUS, current); 5031da177e4SLinus Torvalds 5047f18f151SRalf Baechle return; 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds sigill: 5071da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs); 508a6d5ff04SDavid Daney force_sig(SIGILL, current); 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs) 5121da177e4SLinus Torvalds { 513fe00f943SRalf Baechle unsigned int __user *pc; 5141da177e4SLinus Torvalds mm_segment_t seg; 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds /* 5171da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction? 5181da177e4SLinus Torvalds * Or are we running in MIPS16 mode? 5191da177e4SLinus Torvalds */ 5201da177e4SLinus Torvalds if ((regs->cp0_badvaddr == regs->cp0_epc) || (regs->cp0_epc & 0x1)) 5211da177e4SLinus Torvalds goto sigbus; 5221da177e4SLinus Torvalds 523fe00f943SRalf Baechle pc = (unsigned int __user *) exception_epc(regs); 524293c5bd1SRalf Baechle if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) 5251da177e4SLinus Torvalds goto sigbus; 5266312e0eeSAtsushi Nemoto if (unaligned_action == UNALIGNED_ACTION_SIGNAL) 5276312e0eeSAtsushi Nemoto goto sigbus; 5286312e0eeSAtsushi Nemoto else if (unaligned_action == UNALIGNED_ACTION_SHOW) 5296312e0eeSAtsushi Nemoto show_registers(regs); 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* 5321da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception. 5331da177e4SLinus Torvalds * This is all so but ugly ... 5341da177e4SLinus Torvalds */ 5351da177e4SLinus Torvalds seg = get_fs(); 5361da177e4SLinus Torvalds if (!user_mode(regs)) 5371da177e4SLinus Torvalds set_fs(KERNEL_DS); 5387f18f151SRalf Baechle emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); 5391da177e4SLinus Torvalds set_fs(seg); 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds return; 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds sigbus: 5441da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs); 5451da177e4SLinus Torvalds force_sig(SIGBUS, current); 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds /* 5481da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc 5491da177e4SLinus Torvalds */ 5501da177e4SLinus Torvalds } 5516312e0eeSAtsushi Nemoto 5526312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 5536312e0eeSAtsushi Nemoto extern struct dentry *mips_debugfs_dir; 5546312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void) 5556312e0eeSAtsushi Nemoto { 5566312e0eeSAtsushi Nemoto struct dentry *d; 5576312e0eeSAtsushi Nemoto 5586312e0eeSAtsushi Nemoto if (!mips_debugfs_dir) 5596312e0eeSAtsushi Nemoto return -ENODEV; 5606312e0eeSAtsushi Nemoto d = debugfs_create_u32("unaligned_instructions", S_IRUGO, 5616312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_instructions); 562b517531cSZhaolei if (!d) 563b517531cSZhaolei return -ENOMEM; 5646312e0eeSAtsushi Nemoto d = debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, 5656312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_action); 566b517531cSZhaolei if (!d) 567b517531cSZhaolei return -ENOMEM; 5686312e0eeSAtsushi Nemoto return 0; 5696312e0eeSAtsushi Nemoto } 5706312e0eeSAtsushi Nemoto __initcall(debugfs_unaligned); 5716312e0eeSAtsushi Nemoto #endif 572