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> 801da177e4SLinus Torvalds #include <asm/asm.h> 811da177e4SLinus Torvalds #include <asm/branch.h> 821da177e4SLinus Torvalds #include <asm/byteorder.h> 831da177e4SLinus Torvalds #include <asm/inst.h> 841da177e4SLinus Torvalds #include <asm/uaccess.h> 851da177e4SLinus Torvalds #include <asm/system.h> 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds #define STR(x) __STR(x) 881da177e4SLinus Torvalds #define __STR(x) #x 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 911da177e4SLinus Torvalds unsigned long unaligned_instructions; 921da177e4SLinus Torvalds #endif 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static inline int emulate_load_store_insn(struct pt_regs *regs, 95fe00f943SRalf Baechle void __user *addr, unsigned int __user *pc, 961da177e4SLinus Torvalds unsigned long **regptr, unsigned long *newvalue) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds union mips_instruction insn; 991da177e4SLinus Torvalds unsigned long value; 1001da177e4SLinus Torvalds unsigned int res; 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds regs->regs[0] = 0; 1031da177e4SLinus Torvalds *regptr=NULL; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* 1061da177e4SLinus Torvalds * This load never faults. 1071da177e4SLinus Torvalds */ 108fe00f943SRalf Baechle __get_user(insn.word, pc); 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds switch (insn.i_format.opcode) { 1111da177e4SLinus Torvalds /* 1121da177e4SLinus Torvalds * These are instructions that a compiler doesn't generate. We 1131da177e4SLinus Torvalds * can assume therefore that the code is MIPS-aware and 1141da177e4SLinus Torvalds * really buggy. Emulating these instructions would break the 1151da177e4SLinus Torvalds * semantics anyway. 1161da177e4SLinus Torvalds */ 1171da177e4SLinus Torvalds case ll_op: 1181da177e4SLinus Torvalds case lld_op: 1191da177e4SLinus Torvalds case sc_op: 1201da177e4SLinus Torvalds case scd_op: 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* 1231da177e4SLinus Torvalds * For these instructions the only way to create an address 1241da177e4SLinus Torvalds * error is an attempted access to kernel/supervisor address 1251da177e4SLinus Torvalds * space. 1261da177e4SLinus Torvalds */ 1271da177e4SLinus Torvalds case ldl_op: 1281da177e4SLinus Torvalds case ldr_op: 1291da177e4SLinus Torvalds case lwl_op: 1301da177e4SLinus Torvalds case lwr_op: 1311da177e4SLinus Torvalds case sdl_op: 1321da177e4SLinus Torvalds case sdr_op: 1331da177e4SLinus Torvalds case swl_op: 1341da177e4SLinus Torvalds case swr_op: 1351da177e4SLinus Torvalds case lb_op: 1361da177e4SLinus Torvalds case lbu_op: 1371da177e4SLinus Torvalds case sb_op: 1381da177e4SLinus Torvalds goto sigbus; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds /* 1411da177e4SLinus Torvalds * The remaining opcodes are the ones that are really of interest. 1421da177e4SLinus Torvalds */ 1431da177e4SLinus Torvalds case lh_op: 1441da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 1451da177e4SLinus Torvalds goto sigbus; 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds __asm__ __volatile__ (".set\tnoat\n" 1481da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 1491da177e4SLinus Torvalds "1:\tlb\t%0, 0(%2)\n" 1501da177e4SLinus Torvalds "2:\tlbu\t$1, 1(%2)\n\t" 1511da177e4SLinus Torvalds #endif 1521da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 1531da177e4SLinus Torvalds "1:\tlb\t%0, 1(%2)\n" 1541da177e4SLinus Torvalds "2:\tlbu\t$1, 0(%2)\n\t" 1551da177e4SLinus Torvalds #endif 1561da177e4SLinus Torvalds "sll\t%0, 0x8\n\t" 1571da177e4SLinus Torvalds "or\t%0, $1\n\t" 1581da177e4SLinus Torvalds "li\t%1, 0\n" 1591da177e4SLinus Torvalds "3:\t.set\tat\n\t" 1601da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 1611da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 1621da177e4SLinus Torvalds "j\t3b\n\t" 1631da177e4SLinus Torvalds ".previous\n\t" 1641da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 1651da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 1661da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 1671da177e4SLinus Torvalds ".previous" 1681da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 1691da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 1701da177e4SLinus Torvalds if (res) 1711da177e4SLinus Torvalds goto fault; 1721da177e4SLinus Torvalds *newvalue = value; 1731da177e4SLinus Torvalds *regptr = ®s->regs[insn.i_format.rt]; 1741da177e4SLinus Torvalds break; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds case lw_op: 1771da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 1781da177e4SLinus Torvalds goto sigbus; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds __asm__ __volatile__ ( 1811da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 1821da177e4SLinus Torvalds "1:\tlwl\t%0, (%2)\n" 1831da177e4SLinus Torvalds "2:\tlwr\t%0, 3(%2)\n\t" 1841da177e4SLinus Torvalds #endif 1851da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 1861da177e4SLinus Torvalds "1:\tlwl\t%0, 3(%2)\n" 1871da177e4SLinus Torvalds "2:\tlwr\t%0, (%2)\n\t" 1881da177e4SLinus Torvalds #endif 1891da177e4SLinus Torvalds "li\t%1, 0\n" 1901da177e4SLinus Torvalds "3:\t.section\t.fixup,\"ax\"\n\t" 1911da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 1921da177e4SLinus Torvalds "j\t3b\n\t" 1931da177e4SLinus Torvalds ".previous\n\t" 1941da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 1951da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 1961da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 1971da177e4SLinus Torvalds ".previous" 1981da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 1991da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 2001da177e4SLinus Torvalds if (res) 2011da177e4SLinus Torvalds goto fault; 2021da177e4SLinus Torvalds *newvalue = value; 2031da177e4SLinus Torvalds *regptr = ®s->regs[insn.i_format.rt]; 2041da177e4SLinus Torvalds break; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds case lhu_op: 2071da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 2)) 2081da177e4SLinus Torvalds goto sigbus; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds __asm__ __volatile__ ( 2111da177e4SLinus Torvalds ".set\tnoat\n" 2121da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 2131da177e4SLinus Torvalds "1:\tlbu\t%0, 0(%2)\n" 2141da177e4SLinus Torvalds "2:\tlbu\t$1, 1(%2)\n\t" 2151da177e4SLinus Torvalds #endif 2161da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 2171da177e4SLinus Torvalds "1:\tlbu\t%0, 1(%2)\n" 2181da177e4SLinus Torvalds "2:\tlbu\t$1, 0(%2)\n\t" 2191da177e4SLinus Torvalds #endif 2201da177e4SLinus Torvalds "sll\t%0, 0x8\n\t" 2211da177e4SLinus Torvalds "or\t%0, $1\n\t" 2221da177e4SLinus Torvalds "li\t%1, 0\n" 2231da177e4SLinus Torvalds "3:\t.set\tat\n\t" 2241da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 2251da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 2261da177e4SLinus Torvalds "j\t3b\n\t" 2271da177e4SLinus Torvalds ".previous\n\t" 2281da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 2291da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 2301da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 2311da177e4SLinus Torvalds ".previous" 2321da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 2331da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 2341da177e4SLinus Torvalds if (res) 2351da177e4SLinus Torvalds goto fault; 2361da177e4SLinus Torvalds *newvalue = value; 2371da177e4SLinus Torvalds *regptr = ®s->regs[insn.i_format.rt]; 2381da177e4SLinus Torvalds break; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds case lwu_op: 241875d43e7SRalf Baechle #ifdef CONFIG_64BIT 2421da177e4SLinus Torvalds /* 2431da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 2441da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 2451da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 2461da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 2471da177e4SLinus Torvalds * instructions on 32-bit kernels. 2481da177e4SLinus Torvalds */ 2491da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 4)) 2501da177e4SLinus Torvalds goto sigbus; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds __asm__ __volatile__ ( 2531da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 2541da177e4SLinus Torvalds "1:\tlwl\t%0, (%2)\n" 2551da177e4SLinus Torvalds "2:\tlwr\t%0, 3(%2)\n\t" 2561da177e4SLinus Torvalds #endif 2571da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 2581da177e4SLinus Torvalds "1:\tlwl\t%0, 3(%2)\n" 2591da177e4SLinus Torvalds "2:\tlwr\t%0, (%2)\n\t" 2601da177e4SLinus Torvalds #endif 2611da177e4SLinus Torvalds "dsll\t%0, %0, 32\n\t" 2621da177e4SLinus Torvalds "dsrl\t%0, %0, 32\n\t" 2631da177e4SLinus Torvalds "li\t%1, 0\n" 2641da177e4SLinus Torvalds "3:\t.section\t.fixup,\"ax\"\n\t" 2651da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 2661da177e4SLinus Torvalds "j\t3b\n\t" 2671da177e4SLinus Torvalds ".previous\n\t" 2681da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 2691da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 2701da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 2711da177e4SLinus Torvalds ".previous" 2721da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 2731da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 2741da177e4SLinus Torvalds if (res) 2751da177e4SLinus Torvalds goto fault; 2761da177e4SLinus Torvalds *newvalue = value; 2771da177e4SLinus Torvalds *regptr = ®s->regs[insn.i_format.rt]; 2781da177e4SLinus Torvalds break; 279875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 2821da177e4SLinus Torvalds goto sigill; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds case ld_op: 285875d43e7SRalf Baechle #ifdef CONFIG_64BIT 2861da177e4SLinus Torvalds /* 2871da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 2881da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 2891da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 2901da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 2911da177e4SLinus Torvalds * instructions on 32-bit kernels. 2921da177e4SLinus Torvalds */ 2931da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, addr, 8)) 2941da177e4SLinus Torvalds goto sigbus; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds __asm__ __volatile__ ( 2971da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 2981da177e4SLinus Torvalds "1:\tldl\t%0, (%2)\n" 2991da177e4SLinus Torvalds "2:\tldr\t%0, 7(%2)\n\t" 3001da177e4SLinus Torvalds #endif 3011da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 3021da177e4SLinus Torvalds "1:\tldl\t%0, 7(%2)\n" 3031da177e4SLinus Torvalds "2:\tldr\t%0, (%2)\n\t" 3041da177e4SLinus Torvalds #endif 3051da177e4SLinus Torvalds "li\t%1, 0\n" 3061da177e4SLinus Torvalds "3:\t.section\t.fixup,\"ax\"\n\t" 3071da177e4SLinus Torvalds "4:\tli\t%1, %3\n\t" 3081da177e4SLinus Torvalds "j\t3b\n\t" 3091da177e4SLinus Torvalds ".previous\n\t" 3101da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 3111da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 3121da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 3131da177e4SLinus Torvalds ".previous" 3141da177e4SLinus Torvalds : "=&r" (value), "=r" (res) 3151da177e4SLinus Torvalds : "r" (addr), "i" (-EFAULT)); 3161da177e4SLinus Torvalds if (res) 3171da177e4SLinus Torvalds goto fault; 3181da177e4SLinus Torvalds *newvalue = value; 3191da177e4SLinus Torvalds *regptr = ®s->regs[insn.i_format.rt]; 3201da177e4SLinus Torvalds break; 321875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 3241da177e4SLinus Torvalds goto sigill; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds case sh_op: 3271da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 2)) 3281da177e4SLinus Torvalds goto sigbus; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 3311da177e4SLinus Torvalds __asm__ __volatile__ ( 3321da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 3331da177e4SLinus Torvalds ".set\tnoat\n" 3341da177e4SLinus Torvalds "1:\tsb\t%1, 1(%2)\n\t" 3351da177e4SLinus Torvalds "srl\t$1, %1, 0x8\n" 3361da177e4SLinus Torvalds "2:\tsb\t$1, 0(%2)\n\t" 3371da177e4SLinus Torvalds ".set\tat\n\t" 3381da177e4SLinus Torvalds #endif 3391da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 3401da177e4SLinus Torvalds ".set\tnoat\n" 3411da177e4SLinus Torvalds "1:\tsb\t%1, 0(%2)\n\t" 3421da177e4SLinus Torvalds "srl\t$1,%1, 0x8\n" 3431da177e4SLinus Torvalds "2:\tsb\t$1, 1(%2)\n\t" 3441da177e4SLinus Torvalds ".set\tat\n\t" 3451da177e4SLinus Torvalds #endif 3461da177e4SLinus Torvalds "li\t%0, 0\n" 3471da177e4SLinus Torvalds "3:\n\t" 3481da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 3491da177e4SLinus Torvalds "4:\tli\t%0, %3\n\t" 3501da177e4SLinus Torvalds "j\t3b\n\t" 3511da177e4SLinus Torvalds ".previous\n\t" 3521da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 3531da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 3541da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 3551da177e4SLinus Torvalds ".previous" 3561da177e4SLinus Torvalds : "=r" (res) 3571da177e4SLinus Torvalds : "r" (value), "r" (addr), "i" (-EFAULT)); 3581da177e4SLinus Torvalds if (res) 3591da177e4SLinus Torvalds goto fault; 3601da177e4SLinus Torvalds break; 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds case sw_op: 3631da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 4)) 3641da177e4SLinus Torvalds goto sigbus; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 3671da177e4SLinus Torvalds __asm__ __volatile__ ( 3681da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 3691da177e4SLinus Torvalds "1:\tswl\t%1,(%2)\n" 3701da177e4SLinus Torvalds "2:\tswr\t%1, 3(%2)\n\t" 3711da177e4SLinus Torvalds #endif 3721da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 3731da177e4SLinus Torvalds "1:\tswl\t%1, 3(%2)\n" 3741da177e4SLinus Torvalds "2:\tswr\t%1, (%2)\n\t" 3751da177e4SLinus Torvalds #endif 3761da177e4SLinus Torvalds "li\t%0, 0\n" 3771da177e4SLinus Torvalds "3:\n\t" 3781da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 3791da177e4SLinus Torvalds "4:\tli\t%0, %3\n\t" 3801da177e4SLinus Torvalds "j\t3b\n\t" 3811da177e4SLinus Torvalds ".previous\n\t" 3821da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 3831da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 3841da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 3851da177e4SLinus Torvalds ".previous" 3861da177e4SLinus Torvalds : "=r" (res) 3871da177e4SLinus Torvalds : "r" (value), "r" (addr), "i" (-EFAULT)); 3881da177e4SLinus Torvalds if (res) 3891da177e4SLinus Torvalds goto fault; 3901da177e4SLinus Torvalds break; 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds case sd_op: 393875d43e7SRalf Baechle #ifdef CONFIG_64BIT 3941da177e4SLinus Torvalds /* 3951da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 3961da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 3971da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 3981da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 3991da177e4SLinus Torvalds * instructions on 32-bit kernels. 4001da177e4SLinus Torvalds */ 4011da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, addr, 8)) 4021da177e4SLinus Torvalds goto sigbus; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 4051da177e4SLinus Torvalds __asm__ __volatile__ ( 4061da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 4071da177e4SLinus Torvalds "1:\tsdl\t%1,(%2)\n" 4081da177e4SLinus Torvalds "2:\tsdr\t%1, 7(%2)\n\t" 4091da177e4SLinus Torvalds #endif 4101da177e4SLinus Torvalds #ifdef __LITTLE_ENDIAN 4111da177e4SLinus Torvalds "1:\tsdl\t%1, 7(%2)\n" 4121da177e4SLinus Torvalds "2:\tsdr\t%1, (%2)\n\t" 4131da177e4SLinus Torvalds #endif 4141da177e4SLinus Torvalds "li\t%0, 0\n" 4151da177e4SLinus Torvalds "3:\n\t" 4161da177e4SLinus Torvalds ".section\t.fixup,\"ax\"\n\t" 4171da177e4SLinus Torvalds "4:\tli\t%0, %3\n\t" 4181da177e4SLinus Torvalds "j\t3b\n\t" 4191da177e4SLinus Torvalds ".previous\n\t" 4201da177e4SLinus Torvalds ".section\t__ex_table,\"a\"\n\t" 4211da177e4SLinus Torvalds STR(PTR)"\t1b, 4b\n\t" 4221da177e4SLinus Torvalds STR(PTR)"\t2b, 4b\n\t" 4231da177e4SLinus Torvalds ".previous" 4241da177e4SLinus Torvalds : "=r" (res) 4251da177e4SLinus Torvalds : "r" (value), "r" (addr), "i" (-EFAULT)); 4261da177e4SLinus Torvalds if (res) 4271da177e4SLinus Torvalds goto fault; 4281da177e4SLinus Torvalds break; 429875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 4321da177e4SLinus Torvalds goto sigill; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds case lwc1_op: 4351da177e4SLinus Torvalds case ldc1_op: 4361da177e4SLinus Torvalds case swc1_op: 4371da177e4SLinus Torvalds case sdc1_op: 4381da177e4SLinus Torvalds /* 4391da177e4SLinus Torvalds * I herewith declare: this does not happen. So send SIGBUS. 4401da177e4SLinus Torvalds */ 4411da177e4SLinus Torvalds goto sigbus; 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds case lwc2_op: 4441da177e4SLinus Torvalds case ldc2_op: 4451da177e4SLinus Torvalds case swc2_op: 4461da177e4SLinus Torvalds case sdc2_op: 4471da177e4SLinus Torvalds /* 4481da177e4SLinus Torvalds * These are the coprocessor 2 load/stores. The current 4491da177e4SLinus Torvalds * implementations don't use cp2 and cp2 should always be 4501da177e4SLinus Torvalds * disabled in c0_status. So send SIGILL. 4511da177e4SLinus Torvalds * (No longer true: The Sony Praystation uses cp2 for 4521da177e4SLinus Torvalds * 3D matrix operations. Dunno if that thingy has a MMU ...) 4531da177e4SLinus Torvalds */ 4541da177e4SLinus Torvalds default: 4551da177e4SLinus Torvalds /* 4561da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or 4571da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ... 4581da177e4SLinus Torvalds */ 4591da177e4SLinus Torvalds goto sigill; 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 4631da177e4SLinus Torvalds unaligned_instructions++; 4641da177e4SLinus Torvalds #endif 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds return 0; 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds fault: 4691da177e4SLinus Torvalds /* Did we have an exception handler installed? */ 4701da177e4SLinus Torvalds if (fixup_exception(regs)) 4711da177e4SLinus Torvalds return 1; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds die_if_kernel ("Unhandled kernel unaligned access", regs); 4741da177e4SLinus Torvalds send_sig(SIGSEGV, current, 1); 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds return 0; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds sigbus: 4791da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 4801da177e4SLinus Torvalds send_sig(SIGBUS, current, 1); 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds return 0; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds sigill: 4851da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs); 4861da177e4SLinus Torvalds send_sig(SIGILL, current, 1); 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds return 0; 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs) 4921da177e4SLinus Torvalds { 4931da177e4SLinus Torvalds unsigned long *regptr, newval; 4941da177e4SLinus Torvalds extern int do_dsemulret(struct pt_regs *); 495fe00f943SRalf Baechle unsigned int __user *pc; 4961da177e4SLinus Torvalds mm_segment_t seg; 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds /* 4991da177e4SLinus Torvalds * Address errors may be deliberately induced by the FPU emulator to 5001da177e4SLinus Torvalds * retake control of the CPU after executing the instruction in the 5011da177e4SLinus Torvalds * delay slot of an emulated branch. 5021da177e4SLinus Torvalds */ 5031da177e4SLinus Torvalds /* Terminate if exception was recognized as a delay slot return */ 5041da177e4SLinus Torvalds if (do_dsemulret(regs)) 5051da177e4SLinus Torvalds return; 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds /* Otherwise handle as normal */ 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* 5101da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction? 5111da177e4SLinus Torvalds * Or are we running in MIPS16 mode? 5121da177e4SLinus Torvalds */ 5131da177e4SLinus Torvalds if ((regs->cp0_badvaddr == regs->cp0_epc) || (regs->cp0_epc & 0x1)) 5141da177e4SLinus Torvalds goto sigbus; 5151da177e4SLinus Torvalds 516fe00f943SRalf Baechle pc = (unsigned int __user *) exception_epc(regs); 517b772e6d2SRalf Baechle if (user_mode(regs) && (current->thread.mflags & MF_FIXADE) == 0) 5181da177e4SLinus Torvalds goto sigbus; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* 5211da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception. 5221da177e4SLinus Torvalds * This is all so but ugly ... 5231da177e4SLinus Torvalds */ 5241da177e4SLinus Torvalds seg = get_fs(); 5251da177e4SLinus Torvalds if (!user_mode(regs)) 5261da177e4SLinus Torvalds set_fs(KERNEL_DS); 527fe00f943SRalf Baechle if (!emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc, 5281da177e4SLinus Torvalds ®ptr, &newval)) { 5291da177e4SLinus Torvalds compute_return_epc(regs); 5301da177e4SLinus Torvalds /* 5311da177e4SLinus Torvalds * Now that branch is evaluated, update the dest 5321da177e4SLinus Torvalds * register if necessary 5331da177e4SLinus Torvalds */ 5341da177e4SLinus Torvalds if (regptr) 5351da177e4SLinus Torvalds *regptr = newval; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds set_fs(seg); 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds return; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds sigbus: 5421da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs); 5431da177e4SLinus Torvalds force_sig(SIGBUS, current); 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds /* 5461da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc 5471da177e4SLinus Torvalds */ 5481da177e4SLinus Torvalds } 549