11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Handle unaligned accesses by emulation. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 51da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 61da177e4SLinus Torvalds * for more details. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle 91da177e4SLinus Torvalds * Copyright (C) 1999 Silicon Graphics, Inc. 109d8e5736SMarkos Chandras * Copyright (C) 2014 Imagination Technologies Ltd. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This file contains exception handler for address error exception with the 131da177e4SLinus Torvalds * special capability to execute faulting instructions in software. The 141da177e4SLinus Torvalds * handler does not try to handle the case when the program counter points 151da177e4SLinus Torvalds * to an address not aligned to a word boundary. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Putting data to unaligned addresses is a bad practice even on Intel where 181da177e4SLinus Torvalds * only the performance is affected. Much worse is that such code is non- 191da177e4SLinus Torvalds * portable. Due to several programs that die on MIPS due to alignment 201da177e4SLinus Torvalds * problems I decided to implement this handler anyway though I originally 211da177e4SLinus Torvalds * didn't intend to do this at all for user code. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * For now I enable fixing of address errors by default to make life easier. 241da177e4SLinus Torvalds * I however intend to disable this somewhen in the future when the alignment 251da177e4SLinus Torvalds * problems with user programs have been fixed. For programmers this is the 261da177e4SLinus Torvalds * right way to go. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * Fixing address errors is a per process option. The option is inherited 291da177e4SLinus Torvalds * across fork(2) and execve(2) calls. If you really want to use the 301da177e4SLinus Torvalds * option in your user programs - I discourage the use of the software 311da177e4SLinus Torvalds * emulation strongly - use the following code in your userland stuff: 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * #include <sys/sysmips.h> 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds * ... 361da177e4SLinus Torvalds * sysmips(MIPS_FIXADE, x); 371da177e4SLinus Torvalds * ... 381da177e4SLinus Torvalds * 391da177e4SLinus Torvalds * The argument x is 0 for disabling software emulation, enabled otherwise. 401da177e4SLinus Torvalds * 411da177e4SLinus Torvalds * Below a little program to play around with this feature. 421da177e4SLinus Torvalds * 431da177e4SLinus Torvalds * #include <stdio.h> 441da177e4SLinus Torvalds * #include <sys/sysmips.h> 451da177e4SLinus Torvalds * 461da177e4SLinus Torvalds * struct foo { 471da177e4SLinus Torvalds * unsigned char bar[8]; 481da177e4SLinus Torvalds * }; 491da177e4SLinus Torvalds * 501da177e4SLinus Torvalds * main(int argc, char *argv[]) 511da177e4SLinus Torvalds * { 521da177e4SLinus Torvalds * struct foo x = {0, 1, 2, 3, 4, 5, 6, 7}; 531da177e4SLinus Torvalds * unsigned int *p = (unsigned int *) (x.bar + 3); 541da177e4SLinus Torvalds * int i; 551da177e4SLinus Torvalds * 561da177e4SLinus Torvalds * if (argc > 1) 571da177e4SLinus Torvalds * sysmips(MIPS_FIXADE, atoi(argv[1])); 581da177e4SLinus Torvalds * 591da177e4SLinus Torvalds * printf("*p = %08lx\n", *p); 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * *p = 0xdeadface; 621da177e4SLinus Torvalds * 631da177e4SLinus Torvalds * for(i = 0; i <= 7; i++) 641da177e4SLinus Torvalds * printf("%02x ", x.bar[i]); 651da177e4SLinus Torvalds * printf("\n"); 661da177e4SLinus Torvalds * } 671da177e4SLinus Torvalds * 681da177e4SLinus Torvalds * Coprocessor loads are not supported; I think this case is unimportant 691da177e4SLinus Torvalds * in the practice. 701da177e4SLinus Torvalds * 711da177e4SLinus Torvalds * TODO: Handle ndc (attempted store to doubleword in uncached memory) 721da177e4SLinus Torvalds * exception for the R6000. 731da177e4SLinus Torvalds * A store crossing a page boundary might be executed only partially. 741da177e4SLinus Torvalds * Undo the partial store in this case. 751da177e4SLinus Torvalds */ 76c3fc5cd5SRalf Baechle #include <linux/context_tracking.h> 771da177e4SLinus Torvalds #include <linux/mm.h> 781da177e4SLinus Torvalds #include <linux/signal.h> 791da177e4SLinus Torvalds #include <linux/smp.h> 80e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 816312e0eeSAtsushi Nemoto #include <linux/debugfs.h> 827f788d2dSDeng-Cheng Zhu #include <linux/perf_event.h> 837f788d2dSDeng-Cheng Zhu 841da177e4SLinus Torvalds #include <asm/asm.h> 851da177e4SLinus Torvalds #include <asm/branch.h> 861da177e4SLinus Torvalds #include <asm/byteorder.h> 8769f3a7deSRalf Baechle #include <asm/cop2.h> 8875dcfc1dSPaul Burton #include <asm/debug.h> 89102cedc3SLeonid Yegoshin #include <asm/fpu.h> 90102cedc3SLeonid Yegoshin #include <asm/fpu_emulator.h> 911da177e4SLinus Torvalds #include <asm/inst.h> 92b3878a6aSThomas Bogendoerfer #include <asm/unaligned-emul.h> 93c8790d65SPaul Burton #include <asm/mmu_context.h> 947c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 951da177e4SLinus Torvalds 9645deb5faSThomas Bogendoerfer #include "access-helper.h" 9745deb5faSThomas Bogendoerfer 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 1117f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs, 1127cba4128SThomas Bogendoerfer void __user *addr, unsigned int *pc) 1131da177e4SLinus Torvalds { 11485164fd8SPaul Burton unsigned long origpc, orig31, value; 1151da177e4SLinus Torvalds union mips_instruction insn; 11685164fd8SPaul Burton unsigned int res; 11745deb5faSThomas Bogendoerfer bool user = user_mode(regs); 11845deb5faSThomas Bogendoerfer 11934c2f668SLeonid Yegoshin origpc = (unsigned long)pc; 12034c2f668SLeonid Yegoshin orig31 = regs->regs[31]; 12134c2f668SLeonid Yegoshin 122a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); 1237f788d2dSDeng-Cheng Zhu 1241da177e4SLinus Torvalds /* 1251da177e4SLinus Torvalds * This load never faults. 1261da177e4SLinus Torvalds */ 12745deb5faSThomas Bogendoerfer __get_inst32(&insn.word, pc, user); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds switch (insn.i_format.opcode) { 1301da177e4SLinus Torvalds /* 1311da177e4SLinus Torvalds * These are instructions that a compiler doesn't generate. We 1321da177e4SLinus Torvalds * can assume therefore that the code is MIPS-aware and 1331da177e4SLinus Torvalds * really buggy. Emulating these instructions would break the 1341da177e4SLinus Torvalds * semantics anyway. 1351da177e4SLinus Torvalds */ 1361da177e4SLinus Torvalds case ll_op: 1371da177e4SLinus Torvalds case lld_op: 1381da177e4SLinus Torvalds case sc_op: 1391da177e4SLinus Torvalds case scd_op: 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* 1421da177e4SLinus Torvalds * For these instructions the only way to create an address 1431da177e4SLinus Torvalds * error is an attempted access to kernel/supervisor address 1441da177e4SLinus Torvalds * space. 1451da177e4SLinus Torvalds */ 1461da177e4SLinus Torvalds case ldl_op: 1471da177e4SLinus Torvalds case ldr_op: 1481da177e4SLinus Torvalds case lwl_op: 1491da177e4SLinus Torvalds case lwr_op: 1501da177e4SLinus Torvalds case sdl_op: 1511da177e4SLinus Torvalds case sdr_op: 1521da177e4SLinus Torvalds case swl_op: 1531da177e4SLinus Torvalds case swr_op: 1541da177e4SLinus Torvalds case lb_op: 1551da177e4SLinus Torvalds case lbu_op: 1561da177e4SLinus Torvalds case sb_op: 1571da177e4SLinus Torvalds goto sigbus; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds /* 16034c2f668SLeonid Yegoshin * The remaining opcodes are the ones that are really of 16134c2f668SLeonid Yegoshin * interest. 1621da177e4SLinus Torvalds */ 163c1771216SLeonid Yegoshin case spec3_op: 1643f88ec63SMiodrag Dinic if (insn.dsp_format.func == lx_op) { 1653f88ec63SMiodrag Dinic switch (insn.dsp_format.op) { 1663f88ec63SMiodrag Dinic case lwx_op: 16745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 1683f88ec63SMiodrag Dinic goto sigbus; 1693f88ec63SMiodrag Dinic LoadW(addr, value, res); 1703f88ec63SMiodrag Dinic if (res) 1713f88ec63SMiodrag Dinic goto fault; 1723f88ec63SMiodrag Dinic compute_return_epc(regs); 1733f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value; 1743f88ec63SMiodrag Dinic break; 1753f88ec63SMiodrag Dinic case lhx_op: 17645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 1773f88ec63SMiodrag Dinic goto sigbus; 1783f88ec63SMiodrag Dinic LoadHW(addr, value, res); 1793f88ec63SMiodrag Dinic if (res) 1803f88ec63SMiodrag Dinic goto fault; 1813f88ec63SMiodrag Dinic compute_return_epc(regs); 1823f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value; 1833f88ec63SMiodrag Dinic break; 1843f88ec63SMiodrag Dinic default: 1853f88ec63SMiodrag Dinic goto sigill; 1863f88ec63SMiodrag Dinic } 1873f88ec63SMiodrag Dinic } 1883f88ec63SMiodrag Dinic #ifdef CONFIG_EVA 1893f88ec63SMiodrag Dinic else { 190c1771216SLeonid Yegoshin /* 1913f88ec63SMiodrag Dinic * we can land here only from kernel accessing user 1923f88ec63SMiodrag Dinic * memory, so we need to "switch" the address limit to 1933f88ec63SMiodrag Dinic * user space, so that address check can work properly. 194c1771216SLeonid Yegoshin */ 195c1771216SLeonid Yegoshin switch (insn.spec3_format.func) { 196c1771216SLeonid Yegoshin case lhe_op: 19745deb5faSThomas Bogendoerfer if (!access_ok(addr, 2)) 198c1771216SLeonid Yegoshin goto sigbus; 199eeb53895SMarkos Chandras LoadHWE(addr, value, res); 20045deb5faSThomas Bogendoerfer if (res) 201c1771216SLeonid Yegoshin goto fault; 202c1771216SLeonid Yegoshin compute_return_epc(regs); 203c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 204c1771216SLeonid Yegoshin break; 205c1771216SLeonid Yegoshin case lwe_op: 20645deb5faSThomas Bogendoerfer if (!access_ok(addr, 4)) 207c1771216SLeonid Yegoshin goto sigbus; 208eeb53895SMarkos Chandras LoadWE(addr, value, res); 20945deb5faSThomas Bogendoerfer if (res) 210c1771216SLeonid Yegoshin goto fault; 211c1771216SLeonid Yegoshin compute_return_epc(regs); 212c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 213c1771216SLeonid Yegoshin break; 214c1771216SLeonid Yegoshin case lhue_op: 21545deb5faSThomas Bogendoerfer if (!access_ok(addr, 2)) 216c1771216SLeonid Yegoshin goto sigbus; 217eeb53895SMarkos Chandras LoadHWUE(addr, value, res); 21845deb5faSThomas Bogendoerfer if (res) 219c1771216SLeonid Yegoshin goto fault; 220c1771216SLeonid Yegoshin compute_return_epc(regs); 221c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value; 222c1771216SLeonid Yegoshin break; 223c1771216SLeonid Yegoshin case she_op: 22445deb5faSThomas Bogendoerfer if (!access_ok(addr, 2)) 225c1771216SLeonid Yegoshin goto sigbus; 226c1771216SLeonid Yegoshin compute_return_epc(regs); 227c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt]; 228eeb53895SMarkos Chandras StoreHWE(addr, value, res); 22945deb5faSThomas Bogendoerfer if (res) 230c1771216SLeonid Yegoshin goto fault; 231c1771216SLeonid Yegoshin break; 232c1771216SLeonid Yegoshin case swe_op: 23345deb5faSThomas Bogendoerfer if (!access_ok(addr, 4)) 234c1771216SLeonid Yegoshin goto sigbus; 235c1771216SLeonid Yegoshin compute_return_epc(regs); 236c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt]; 237eeb53895SMarkos Chandras StoreWE(addr, value, res); 23845deb5faSThomas Bogendoerfer if (res) 239c1771216SLeonid Yegoshin goto fault; 240c1771216SLeonid Yegoshin break; 241c1771216SLeonid Yegoshin default: 242c1771216SLeonid Yegoshin goto sigill; 243c1771216SLeonid Yegoshin } 2443f88ec63SMiodrag Dinic } 245c1771216SLeonid Yegoshin #endif 2463f88ec63SMiodrag Dinic break; 2471da177e4SLinus Torvalds case lh_op: 24845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 2491da177e4SLinus Torvalds goto sigbus; 2501da177e4SLinus Torvalds 25145deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user) 2526eae3548SMarkos Chandras LoadHWE(addr, value, res); 25345deb5faSThomas Bogendoerfer else 2546eae3548SMarkos Chandras LoadHW(addr, value, res); 2556eae3548SMarkos Chandras 2561da177e4SLinus Torvalds if (res) 2571da177e4SLinus Torvalds goto fault; 2587f18f151SRalf Baechle compute_return_epc(regs); 2597f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 2601da177e4SLinus Torvalds break; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds case lw_op: 26345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 2641da177e4SLinus Torvalds goto sigbus; 2651da177e4SLinus Torvalds 26645deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user) 2676eae3548SMarkos Chandras LoadWE(addr, value, res); 26845deb5faSThomas Bogendoerfer else 2696eae3548SMarkos Chandras LoadW(addr, value, res); 2706eae3548SMarkos Chandras 2711da177e4SLinus Torvalds if (res) 2721da177e4SLinus Torvalds goto fault; 2737f18f151SRalf Baechle compute_return_epc(regs); 2747f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 2751da177e4SLinus Torvalds break; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds case lhu_op: 27845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 2791da177e4SLinus Torvalds goto sigbus; 2801da177e4SLinus Torvalds 28145deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user) 2826eae3548SMarkos Chandras LoadHWUE(addr, value, res); 28345deb5faSThomas Bogendoerfer else 2846eae3548SMarkos Chandras LoadHWU(addr, value, res); 2856eae3548SMarkos Chandras 2861da177e4SLinus Torvalds if (res) 2871da177e4SLinus Torvalds goto fault; 2887f18f151SRalf Baechle compute_return_epc(regs); 2897f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 2901da177e4SLinus Torvalds break; 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds case lwu_op: 293875d43e7SRalf Baechle #ifdef CONFIG_64BIT 2941da177e4SLinus Torvalds /* 2951da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 2961da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 2971da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 2981da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 2991da177e4SLinus Torvalds * instructions on 32-bit kernels. 3001da177e4SLinus Torvalds */ 30145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 3021da177e4SLinus Torvalds goto sigbus; 3031da177e4SLinus Torvalds 30434c2f668SLeonid Yegoshin LoadWU(addr, value, res); 3051da177e4SLinus Torvalds if (res) 3061da177e4SLinus Torvalds goto fault; 3077f18f151SRalf Baechle compute_return_epc(regs); 3087f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 3091da177e4SLinus Torvalds break; 310875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 3131da177e4SLinus Torvalds goto sigill; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds case ld_op: 316875d43e7SRalf Baechle #ifdef CONFIG_64BIT 3171da177e4SLinus Torvalds /* 3181da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 3191da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 3201da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 3211da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 3221da177e4SLinus Torvalds * instructions on 32-bit kernels. 3231da177e4SLinus Torvalds */ 32445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 3251da177e4SLinus Torvalds goto sigbus; 3261da177e4SLinus Torvalds 32734c2f668SLeonid Yegoshin LoadDW(addr, value, res); 3281da177e4SLinus Torvalds if (res) 3291da177e4SLinus Torvalds goto fault; 3307f18f151SRalf Baechle compute_return_epc(regs); 3317f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value; 3321da177e4SLinus Torvalds break; 333875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 3361da177e4SLinus Torvalds goto sigill; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds case sh_op: 33945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 3401da177e4SLinus Torvalds goto sigbus; 3411da177e4SLinus Torvalds 34234c2f668SLeonid Yegoshin compute_return_epc(regs); 3431da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 3446eae3548SMarkos Chandras 34545deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user) 3466eae3548SMarkos Chandras StoreHWE(addr, value, res); 34745deb5faSThomas Bogendoerfer else 3486eae3548SMarkos Chandras StoreHW(addr, value, res); 3496eae3548SMarkos Chandras 3501da177e4SLinus Torvalds if (res) 3511da177e4SLinus Torvalds goto fault; 3521da177e4SLinus Torvalds break; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds case sw_op: 35545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 3561da177e4SLinus Torvalds goto sigbus; 3571da177e4SLinus Torvalds 35834c2f668SLeonid Yegoshin compute_return_epc(regs); 3591da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 3606eae3548SMarkos Chandras 36145deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user) 3626eae3548SMarkos Chandras StoreWE(addr, value, res); 36345deb5faSThomas Bogendoerfer else 3646eae3548SMarkos Chandras StoreW(addr, value, res); 3656eae3548SMarkos Chandras 3661da177e4SLinus Torvalds if (res) 3671da177e4SLinus Torvalds goto fault; 3681da177e4SLinus Torvalds break; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds case sd_op: 371875d43e7SRalf Baechle #ifdef CONFIG_64BIT 3721da177e4SLinus Torvalds /* 3731da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But 3741da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency 3751da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr 3761da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit 3771da177e4SLinus Torvalds * instructions on 32-bit kernels. 3781da177e4SLinus Torvalds */ 37945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 3801da177e4SLinus Torvalds goto sigbus; 3811da177e4SLinus Torvalds 38234c2f668SLeonid Yegoshin compute_return_epc(regs); 3831da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt]; 38434c2f668SLeonid Yegoshin StoreDW(addr, value, res); 3851da177e4SLinus Torvalds if (res) 3861da177e4SLinus Torvalds goto fault; 3871da177e4SLinus Torvalds break; 388875d43e7SRalf Baechle #endif /* CONFIG_64BIT */ 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */ 3911da177e4SLinus Torvalds goto sigill; 3921da177e4SLinus Torvalds 39385164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT 39485164fd8SPaul Burton 3951da177e4SLinus Torvalds case lwc1_op: 3961da177e4SLinus Torvalds case ldc1_op: 3971da177e4SLinus Torvalds case swc1_op: 3981da177e4SLinus Torvalds case sdc1_op: 39985164fd8SPaul Burton case cop1x_op: { 40085164fd8SPaul Burton void __user *fault_addr = NULL; 40185164fd8SPaul Burton 402102cedc3SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs); 403102cedc3SLeonid Yegoshin BUG_ON(!used_math()); 404102cedc3SLeonid Yegoshin 405102cedc3SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, 406102cedc3SLeonid Yegoshin &fault_addr); 407102cedc3SLeonid Yegoshin own_fpu(1); /* Restore FPU state. */ 408102cedc3SLeonid Yegoshin 409102cedc3SLeonid Yegoshin /* Signal if something went wrong. */ 410304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0); 411102cedc3SLeonid Yegoshin 412102cedc3SLeonid Yegoshin if (res == 0) 413102cedc3SLeonid Yegoshin break; 414102cedc3SLeonid Yegoshin return; 41585164fd8SPaul Burton } 41685164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */ 4171da177e4SLinus Torvalds 41885164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA 41985164fd8SPaul Burton 42085164fd8SPaul Burton case msa_op: { 42185164fd8SPaul Burton unsigned int wd, preempted; 42285164fd8SPaul Burton enum msa_2b_fmt df; 42385164fd8SPaul Burton union fpureg *fpr; 42485164fd8SPaul Burton 425e4aa1f15SLeonid Yegoshin if (!cpu_has_msa) 426e4aa1f15SLeonid Yegoshin goto sigill; 427e4aa1f15SLeonid Yegoshin 428e4aa1f15SLeonid Yegoshin /* 429e4aa1f15SLeonid Yegoshin * If we've reached this point then userland should have taken 430e4aa1f15SLeonid Yegoshin * the MSA disabled exception & initialised vector context at 431e4aa1f15SLeonid Yegoshin * some point in the past. 432e4aa1f15SLeonid Yegoshin */ 433e4aa1f15SLeonid Yegoshin BUG_ON(!thread_msa_context_live()); 434e4aa1f15SLeonid Yegoshin 435e4aa1f15SLeonid Yegoshin df = insn.msa_mi10_format.df; 436e4aa1f15SLeonid Yegoshin wd = insn.msa_mi10_format.wd; 437e4aa1f15SLeonid Yegoshin fpr = ¤t->thread.fpu.fpr[wd]; 438e4aa1f15SLeonid Yegoshin 439e4aa1f15SLeonid Yegoshin switch (insn.msa_mi10_format.func) { 440e4aa1f15SLeonid Yegoshin case msa_ld_op: 44196d4f267SLinus Torvalds if (!access_ok(addr, sizeof(*fpr))) 442e4aa1f15SLeonid Yegoshin goto sigbus; 443e4aa1f15SLeonid Yegoshin 444fa8ff601SPaul Burton do { 445e4aa1f15SLeonid Yegoshin /* 446fa8ff601SPaul Burton * If we have live MSA context keep track of 447fa8ff601SPaul Burton * whether we get preempted in order to avoid 448fa8ff601SPaul Burton * the register context we load being clobbered 449fa8ff601SPaul Burton * by the live context as it's saved during 450fa8ff601SPaul Burton * preemption. If we don't have live context 451fa8ff601SPaul Burton * then it can't be saved to clobber the value 452fa8ff601SPaul Burton * we load. 453e4aa1f15SLeonid Yegoshin */ 454fa8ff601SPaul Burton preempted = test_thread_flag(TIF_USEDMSA); 455e4aa1f15SLeonid Yegoshin 456e4aa1f15SLeonid Yegoshin res = __copy_from_user_inatomic(fpr, addr, 457e4aa1f15SLeonid Yegoshin sizeof(*fpr)); 458e4aa1f15SLeonid Yegoshin if (res) 459e4aa1f15SLeonid Yegoshin goto fault; 460e4aa1f15SLeonid Yegoshin 461e4aa1f15SLeonid Yegoshin /* 462fa8ff601SPaul Burton * Update the hardware register if it is in use 463fa8ff601SPaul Burton * by the task in this quantum, in order to 464fa8ff601SPaul Burton * avoid having to save & restore the whole 465fa8ff601SPaul Burton * vector context. 466e4aa1f15SLeonid Yegoshin */ 467fa8ff601SPaul Burton preempt_disable(); 468fa8ff601SPaul Burton if (test_thread_flag(TIF_USEDMSA)) { 469e4aa1f15SLeonid Yegoshin write_msa_wr(wd, fpr, df); 470fa8ff601SPaul Burton preempted = 0; 471fa8ff601SPaul Burton } 472e4aa1f15SLeonid Yegoshin preempt_enable(); 473fa8ff601SPaul Burton } while (preempted); 474e4aa1f15SLeonid Yegoshin break; 475e4aa1f15SLeonid Yegoshin 476e4aa1f15SLeonid Yegoshin case msa_st_op: 47796d4f267SLinus Torvalds if (!access_ok(addr, sizeof(*fpr))) 478e4aa1f15SLeonid Yegoshin goto sigbus; 479e4aa1f15SLeonid Yegoshin 480e4aa1f15SLeonid Yegoshin /* 481e4aa1f15SLeonid Yegoshin * Update from the hardware register if it is in use by 482e4aa1f15SLeonid Yegoshin * the task in this quantum, in order to avoid having to 483e4aa1f15SLeonid Yegoshin * save & restore the whole vector context. 484e4aa1f15SLeonid Yegoshin */ 485e4aa1f15SLeonid Yegoshin preempt_disable(); 486e4aa1f15SLeonid Yegoshin if (test_thread_flag(TIF_USEDMSA)) 487e4aa1f15SLeonid Yegoshin read_msa_wr(wd, fpr, df); 488e4aa1f15SLeonid Yegoshin preempt_enable(); 489e4aa1f15SLeonid Yegoshin 490e4aa1f15SLeonid Yegoshin res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr)); 491e4aa1f15SLeonid Yegoshin if (res) 492e4aa1f15SLeonid Yegoshin goto fault; 493e4aa1f15SLeonid Yegoshin break; 494e4aa1f15SLeonid Yegoshin 495e4aa1f15SLeonid Yegoshin default: 496e4aa1f15SLeonid Yegoshin goto sigbus; 497e4aa1f15SLeonid Yegoshin } 498e4aa1f15SLeonid Yegoshin 499e4aa1f15SLeonid Yegoshin compute_return_epc(regs); 500e4aa1f15SLeonid Yegoshin break; 50185164fd8SPaul Burton } 50285164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */ 503e4aa1f15SLeonid Yegoshin 5040593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6 5051da177e4SLinus Torvalds /* 50669f3a7deSRalf Baechle * COP2 is available to implementor for application specific use. 50769f3a7deSRalf Baechle * It's up to applications to register a notifier chain and do 50869f3a7deSRalf Baechle * whatever they have to do, including possible sending of signals. 5090593a44cSLeonid Yegoshin * 5100593a44cSLeonid Yegoshin * This instruction has been reallocated in Release 6 5111da177e4SLinus Torvalds */ 51269f3a7deSRalf Baechle case lwc2_op: 51369f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LWC2_OP, regs); 51469f3a7deSRalf Baechle break; 51569f3a7deSRalf Baechle 51669f3a7deSRalf Baechle case ldc2_op: 51769f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LDC2_OP, regs); 51869f3a7deSRalf Baechle break; 51969f3a7deSRalf Baechle 52069f3a7deSRalf Baechle case swc2_op: 52169f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SWC2_OP, regs); 52269f3a7deSRalf Baechle break; 52369f3a7deSRalf Baechle 52469f3a7deSRalf Baechle case sdc2_op: 52569f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SDC2_OP, regs); 52669f3a7deSRalf Baechle break; 5270593a44cSLeonid Yegoshin #endif 5281da177e4SLinus Torvalds default: 5291da177e4SLinus Torvalds /* 5301da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or 5311da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ... 5321da177e4SLinus Torvalds */ 5331da177e4SLinus Torvalds goto sigill; 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5366312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 5371da177e4SLinus Torvalds unaligned_instructions++; 5381da177e4SLinus Torvalds #endif 5391da177e4SLinus Torvalds 5407f18f151SRalf Baechle return; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds fault: 54334c2f668SLeonid Yegoshin /* roll back jump/branch */ 54434c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 54534c2f668SLeonid Yegoshin regs->regs[31] = orig31; 5461da177e4SLinus Torvalds /* Did we have an exception handler installed? */ 5471da177e4SLinus Torvalds if (fixup_exception(regs)) 5487f18f151SRalf Baechle return; 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 5513cf5d076SEric W. Biederman force_sig(SIGSEGV); 5521da177e4SLinus Torvalds 5537f18f151SRalf Baechle return; 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds sigbus: 5561da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs); 5573cf5d076SEric W. Biederman force_sig(SIGBUS); 5581da177e4SLinus Torvalds 5597f18f151SRalf Baechle return; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds sigill: 56234c2f668SLeonid Yegoshin die_if_kernel 56334c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs); 5643cf5d076SEric W. Biederman force_sig(SIGILL); 56534c2f668SLeonid Yegoshin } 56634c2f668SLeonid Yegoshin 56734c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */ 56834c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; 56934c2f668SLeonid Yegoshin 57034c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */ 571b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; 57234c2f668SLeonid Yegoshin 57374338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs, 57474338805SDavid Daney void __user *addr) 57534c2f668SLeonid Yegoshin { 57634c2f668SLeonid Yegoshin unsigned long value; 57734c2f668SLeonid Yegoshin unsigned int res; 57834c2f668SLeonid Yegoshin int i; 57934c2f668SLeonid Yegoshin unsigned int reg = 0, rvar; 58034c2f668SLeonid Yegoshin unsigned long orig31; 58134c2f668SLeonid Yegoshin u16 __user *pc16; 58234c2f668SLeonid Yegoshin u16 halfword; 58334c2f668SLeonid Yegoshin unsigned int word; 58434c2f668SLeonid Yegoshin unsigned long origpc, contpc; 58534c2f668SLeonid Yegoshin union mips_instruction insn; 58634c2f668SLeonid Yegoshin struct mm_decoded_insn mminsn; 58745deb5faSThomas Bogendoerfer bool user = user_mode(regs); 58834c2f668SLeonid Yegoshin 58934c2f668SLeonid Yegoshin origpc = regs->cp0_epc; 59034c2f668SLeonid Yegoshin orig31 = regs->regs[31]; 59134c2f668SLeonid Yegoshin 59234c2f668SLeonid Yegoshin mminsn.micro_mips_mode = 1; 59334c2f668SLeonid Yegoshin 59434c2f668SLeonid Yegoshin /* 59534c2f668SLeonid Yegoshin * This load never faults. 59634c2f668SLeonid Yegoshin */ 59734c2f668SLeonid Yegoshin pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc); 59834c2f668SLeonid Yegoshin __get_user(halfword, pc16); 59934c2f668SLeonid Yegoshin pc16++; 60034c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 2; 60134c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16); 60234c2f668SLeonid Yegoshin mminsn.pc_inc = 2; 60334c2f668SLeonid Yegoshin 60434c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) { 60534c2f668SLeonid Yegoshin __get_user(halfword, pc16); 60634c2f668SLeonid Yegoshin pc16++; 60734c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 4; 60834c2f668SLeonid Yegoshin mminsn.pc_inc = 4; 60934c2f668SLeonid Yegoshin word |= halfword; 61034c2f668SLeonid Yegoshin } 61134c2f668SLeonid Yegoshin mminsn.insn = word; 61234c2f668SLeonid Yegoshin 61334c2f668SLeonid Yegoshin if (get_user(halfword, pc16)) 61434c2f668SLeonid Yegoshin goto fault; 61534c2f668SLeonid Yegoshin mminsn.next_pc_inc = 2; 61634c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16); 61734c2f668SLeonid Yegoshin 61834c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) { 61934c2f668SLeonid Yegoshin pc16++; 62034c2f668SLeonid Yegoshin if (get_user(halfword, pc16)) 62134c2f668SLeonid Yegoshin goto fault; 62234c2f668SLeonid Yegoshin mminsn.next_pc_inc = 4; 62334c2f668SLeonid Yegoshin word |= halfword; 62434c2f668SLeonid Yegoshin } 62534c2f668SLeonid Yegoshin mminsn.next_insn = word; 62634c2f668SLeonid Yegoshin 62734c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.insn); 62834c2f668SLeonid Yegoshin if (mm_isBranchInstr(regs, mminsn, &contpc)) 62934c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.next_insn); 63034c2f668SLeonid Yegoshin 63134c2f668SLeonid Yegoshin /* Parse instruction to find what to do */ 63234c2f668SLeonid Yegoshin 63334c2f668SLeonid Yegoshin switch (insn.mm_i_format.opcode) { 63434c2f668SLeonid Yegoshin 63534c2f668SLeonid Yegoshin case mm_pool32a_op: 63634c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) { 63734c2f668SLeonid Yegoshin case mm_lwxs_op: 63834c2f668SLeonid Yegoshin reg = insn.mm_x_format.rd; 63934c2f668SLeonid Yegoshin goto loadW; 64034c2f668SLeonid Yegoshin } 64134c2f668SLeonid Yegoshin 64234c2f668SLeonid Yegoshin goto sigbus; 64334c2f668SLeonid Yegoshin 64434c2f668SLeonid Yegoshin case mm_pool32b_op: 64534c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) { 64634c2f668SLeonid Yegoshin case mm_lwp_func: 64734c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 64834c2f668SLeonid Yegoshin if (reg == 31) 64934c2f668SLeonid Yegoshin goto sigbus; 65034c2f668SLeonid Yegoshin 65145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 65234c2f668SLeonid Yegoshin goto sigbus; 65334c2f668SLeonid Yegoshin 65434c2f668SLeonid Yegoshin LoadW(addr, value, res); 65534c2f668SLeonid Yegoshin if (res) 65634c2f668SLeonid Yegoshin goto fault; 65734c2f668SLeonid Yegoshin regs->regs[reg] = value; 65834c2f668SLeonid Yegoshin addr += 4; 65934c2f668SLeonid Yegoshin LoadW(addr, value, res); 66034c2f668SLeonid Yegoshin if (res) 66134c2f668SLeonid Yegoshin goto fault; 66234c2f668SLeonid Yegoshin regs->regs[reg + 1] = value; 66334c2f668SLeonid Yegoshin goto success; 66434c2f668SLeonid Yegoshin 66534c2f668SLeonid Yegoshin case mm_swp_func: 66634c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 66734c2f668SLeonid Yegoshin if (reg == 31) 66834c2f668SLeonid Yegoshin goto sigbus; 66934c2f668SLeonid Yegoshin 67045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 67134c2f668SLeonid Yegoshin goto sigbus; 67234c2f668SLeonid Yegoshin 67334c2f668SLeonid Yegoshin value = regs->regs[reg]; 67434c2f668SLeonid Yegoshin StoreW(addr, value, res); 67534c2f668SLeonid Yegoshin if (res) 67634c2f668SLeonid Yegoshin goto fault; 67734c2f668SLeonid Yegoshin addr += 4; 67834c2f668SLeonid Yegoshin value = regs->regs[reg + 1]; 67934c2f668SLeonid Yegoshin StoreW(addr, value, res); 68034c2f668SLeonid Yegoshin if (res) 68134c2f668SLeonid Yegoshin goto fault; 68234c2f668SLeonid Yegoshin goto success; 68334c2f668SLeonid Yegoshin 68434c2f668SLeonid Yegoshin case mm_ldp_func: 68534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 68634c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 68734c2f668SLeonid Yegoshin if (reg == 31) 68834c2f668SLeonid Yegoshin goto sigbus; 68934c2f668SLeonid Yegoshin 69045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 16)) 69134c2f668SLeonid Yegoshin goto sigbus; 69234c2f668SLeonid Yegoshin 69334c2f668SLeonid Yegoshin LoadDW(addr, value, res); 69434c2f668SLeonid Yegoshin if (res) 69534c2f668SLeonid Yegoshin goto fault; 69634c2f668SLeonid Yegoshin regs->regs[reg] = value; 69734c2f668SLeonid Yegoshin addr += 8; 69834c2f668SLeonid Yegoshin LoadDW(addr, value, res); 69934c2f668SLeonid Yegoshin if (res) 70034c2f668SLeonid Yegoshin goto fault; 70134c2f668SLeonid Yegoshin regs->regs[reg + 1] = value; 70234c2f668SLeonid Yegoshin goto success; 70334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 70434c2f668SLeonid Yegoshin 70534c2f668SLeonid Yegoshin goto sigill; 70634c2f668SLeonid Yegoshin 70734c2f668SLeonid Yegoshin case mm_sdp_func: 70834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 70934c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 71034c2f668SLeonid Yegoshin if (reg == 31) 71134c2f668SLeonid Yegoshin goto sigbus; 71234c2f668SLeonid Yegoshin 71345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 16)) 71434c2f668SLeonid Yegoshin goto sigbus; 71534c2f668SLeonid Yegoshin 71634c2f668SLeonid Yegoshin value = regs->regs[reg]; 71734c2f668SLeonid Yegoshin StoreDW(addr, value, res); 71834c2f668SLeonid Yegoshin if (res) 71934c2f668SLeonid Yegoshin goto fault; 72034c2f668SLeonid Yegoshin addr += 8; 72134c2f668SLeonid Yegoshin value = regs->regs[reg + 1]; 72234c2f668SLeonid Yegoshin StoreDW(addr, value, res); 72334c2f668SLeonid Yegoshin if (res) 72434c2f668SLeonid Yegoshin goto fault; 72534c2f668SLeonid Yegoshin goto success; 72634c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 72734c2f668SLeonid Yegoshin 72834c2f668SLeonid Yegoshin goto sigill; 72934c2f668SLeonid Yegoshin 73034c2f668SLeonid Yegoshin case mm_lwm32_func: 73134c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 73234c2f668SLeonid Yegoshin rvar = reg & 0xf; 73334c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 73434c2f668SLeonid Yegoshin goto sigill; 73534c2f668SLeonid Yegoshin if (reg & 0x10) { 73645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * (rvar + 1))) 73734c2f668SLeonid Yegoshin goto sigbus; 73834c2f668SLeonid Yegoshin } else { 73945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar)) 74034c2f668SLeonid Yegoshin goto sigbus; 74134c2f668SLeonid Yegoshin } 74234c2f668SLeonid Yegoshin if (rvar == 9) 74334c2f668SLeonid Yegoshin rvar = 8; 74434c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 74534c2f668SLeonid Yegoshin LoadW(addr, value, res); 74634c2f668SLeonid Yegoshin if (res) 74734c2f668SLeonid Yegoshin goto fault; 74834c2f668SLeonid Yegoshin addr += 4; 74934c2f668SLeonid Yegoshin regs->regs[i] = value; 75034c2f668SLeonid Yegoshin } 75134c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 75234c2f668SLeonid Yegoshin LoadW(addr, value, res); 75334c2f668SLeonid Yegoshin if (res) 75434c2f668SLeonid Yegoshin goto fault; 75534c2f668SLeonid Yegoshin addr += 4; 75634c2f668SLeonid Yegoshin regs->regs[30] = value; 75734c2f668SLeonid Yegoshin } 75834c2f668SLeonid Yegoshin if (reg & 0x10) { 75934c2f668SLeonid Yegoshin LoadW(addr, value, res); 76034c2f668SLeonid Yegoshin if (res) 76134c2f668SLeonid Yegoshin goto fault; 76234c2f668SLeonid Yegoshin regs->regs[31] = value; 76334c2f668SLeonid Yegoshin } 76434c2f668SLeonid Yegoshin goto success; 76534c2f668SLeonid Yegoshin 76634c2f668SLeonid Yegoshin case mm_swm32_func: 76734c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 76834c2f668SLeonid Yegoshin rvar = reg & 0xf; 76934c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 77034c2f668SLeonid Yegoshin goto sigill; 77134c2f668SLeonid Yegoshin if (reg & 0x10) { 77245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * (rvar + 1))) 77334c2f668SLeonid Yegoshin goto sigbus; 77434c2f668SLeonid Yegoshin } else { 77545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar)) 77634c2f668SLeonid Yegoshin goto sigbus; 77734c2f668SLeonid Yegoshin } 77834c2f668SLeonid Yegoshin if (rvar == 9) 77934c2f668SLeonid Yegoshin rvar = 8; 78034c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 78134c2f668SLeonid Yegoshin value = regs->regs[i]; 78234c2f668SLeonid Yegoshin StoreW(addr, value, res); 78334c2f668SLeonid Yegoshin if (res) 78434c2f668SLeonid Yegoshin goto fault; 78534c2f668SLeonid Yegoshin addr += 4; 78634c2f668SLeonid Yegoshin } 78734c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 78834c2f668SLeonid Yegoshin value = regs->regs[30]; 78934c2f668SLeonid Yegoshin StoreW(addr, value, res); 79034c2f668SLeonid Yegoshin if (res) 79134c2f668SLeonid Yegoshin goto fault; 79234c2f668SLeonid Yegoshin addr += 4; 79334c2f668SLeonid Yegoshin } 79434c2f668SLeonid Yegoshin if (reg & 0x10) { 79534c2f668SLeonid Yegoshin value = regs->regs[31]; 79634c2f668SLeonid Yegoshin StoreW(addr, value, res); 79734c2f668SLeonid Yegoshin if (res) 79834c2f668SLeonid Yegoshin goto fault; 79934c2f668SLeonid Yegoshin } 80034c2f668SLeonid Yegoshin goto success; 80134c2f668SLeonid Yegoshin 80234c2f668SLeonid Yegoshin case mm_ldm_func: 80334c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 80434c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 80534c2f668SLeonid Yegoshin rvar = reg & 0xf; 80634c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 80734c2f668SLeonid Yegoshin goto sigill; 80834c2f668SLeonid Yegoshin if (reg & 0x10) { 80945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * (rvar + 1))) 81034c2f668SLeonid Yegoshin goto sigbus; 81134c2f668SLeonid Yegoshin } else { 81245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * rvar)) 81334c2f668SLeonid Yegoshin goto sigbus; 81434c2f668SLeonid Yegoshin } 81534c2f668SLeonid Yegoshin if (rvar == 9) 81634c2f668SLeonid Yegoshin rvar = 8; 81734c2f668SLeonid Yegoshin 81834c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 81934c2f668SLeonid Yegoshin LoadDW(addr, value, res); 82034c2f668SLeonid Yegoshin if (res) 82134c2f668SLeonid Yegoshin goto fault; 82234c2f668SLeonid Yegoshin addr += 4; 82334c2f668SLeonid Yegoshin regs->regs[i] = value; 82434c2f668SLeonid Yegoshin } 82534c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 82634c2f668SLeonid Yegoshin LoadDW(addr, value, res); 82734c2f668SLeonid Yegoshin if (res) 82834c2f668SLeonid Yegoshin goto fault; 82934c2f668SLeonid Yegoshin addr += 8; 83034c2f668SLeonid Yegoshin regs->regs[30] = value; 83134c2f668SLeonid Yegoshin } 83234c2f668SLeonid Yegoshin if (reg & 0x10) { 83334c2f668SLeonid Yegoshin LoadDW(addr, value, res); 83434c2f668SLeonid Yegoshin if (res) 83534c2f668SLeonid Yegoshin goto fault; 83634c2f668SLeonid Yegoshin regs->regs[31] = value; 83734c2f668SLeonid Yegoshin } 83834c2f668SLeonid Yegoshin goto success; 83934c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 84034c2f668SLeonid Yegoshin 84134c2f668SLeonid Yegoshin goto sigill; 84234c2f668SLeonid Yegoshin 84334c2f668SLeonid Yegoshin case mm_sdm_func: 84434c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 84534c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 84634c2f668SLeonid Yegoshin rvar = reg & 0xf; 84734c2f668SLeonid Yegoshin if ((rvar > 9) || !reg) 84834c2f668SLeonid Yegoshin goto sigill; 84934c2f668SLeonid Yegoshin if (reg & 0x10) { 85045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * (rvar + 1))) 85134c2f668SLeonid Yegoshin goto sigbus; 85234c2f668SLeonid Yegoshin } else { 85345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * rvar)) 85434c2f668SLeonid Yegoshin goto sigbus; 85534c2f668SLeonid Yegoshin } 85634c2f668SLeonid Yegoshin if (rvar == 9) 85734c2f668SLeonid Yegoshin rvar = 8; 85834c2f668SLeonid Yegoshin 85934c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 86034c2f668SLeonid Yegoshin value = regs->regs[i]; 86134c2f668SLeonid Yegoshin StoreDW(addr, value, res); 86234c2f668SLeonid Yegoshin if (res) 86334c2f668SLeonid Yegoshin goto fault; 86434c2f668SLeonid Yegoshin addr += 8; 86534c2f668SLeonid Yegoshin } 86634c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) { 86734c2f668SLeonid Yegoshin value = regs->regs[30]; 86834c2f668SLeonid Yegoshin StoreDW(addr, value, res); 86934c2f668SLeonid Yegoshin if (res) 87034c2f668SLeonid Yegoshin goto fault; 87134c2f668SLeonid Yegoshin addr += 8; 87234c2f668SLeonid Yegoshin } 87334c2f668SLeonid Yegoshin if (reg & 0x10) { 87434c2f668SLeonid Yegoshin value = regs->regs[31]; 87534c2f668SLeonid Yegoshin StoreDW(addr, value, res); 87634c2f668SLeonid Yegoshin if (res) 87734c2f668SLeonid Yegoshin goto fault; 87834c2f668SLeonid Yegoshin } 87934c2f668SLeonid Yegoshin goto success; 88034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 88134c2f668SLeonid Yegoshin 88234c2f668SLeonid Yegoshin goto sigill; 88334c2f668SLeonid Yegoshin 88434c2f668SLeonid Yegoshin /* LWC2, SWC2, LDC2, SDC2 are not serviced */ 88534c2f668SLeonid Yegoshin } 88634c2f668SLeonid Yegoshin 88734c2f668SLeonid Yegoshin goto sigbus; 88834c2f668SLeonid Yegoshin 88934c2f668SLeonid Yegoshin case mm_pool32c_op: 89034c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) { 89134c2f668SLeonid Yegoshin case mm_lwu_func: 89234c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd; 89334c2f668SLeonid Yegoshin goto loadWU; 89434c2f668SLeonid Yegoshin } 89534c2f668SLeonid Yegoshin 89634c2f668SLeonid Yegoshin /* LL,SC,LLD,SCD are not serviced */ 89734c2f668SLeonid Yegoshin goto sigbus; 89834c2f668SLeonid Yegoshin 89985164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT 90034c2f668SLeonid Yegoshin case mm_pool32f_op: 90134c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) { 90234c2f668SLeonid Yegoshin case mm_lwxc1_func: 90334c2f668SLeonid Yegoshin case mm_swxc1_func: 90434c2f668SLeonid Yegoshin case mm_ldxc1_func: 90534c2f668SLeonid Yegoshin case mm_sdxc1_func: 90634c2f668SLeonid Yegoshin goto fpu_emul; 90734c2f668SLeonid Yegoshin } 90834c2f668SLeonid Yegoshin 90934c2f668SLeonid Yegoshin goto sigbus; 91034c2f668SLeonid Yegoshin 91134c2f668SLeonid Yegoshin case mm_ldc132_op: 91234c2f668SLeonid Yegoshin case mm_sdc132_op: 91334c2f668SLeonid Yegoshin case mm_lwc132_op: 91485164fd8SPaul Burton case mm_swc132_op: { 91585164fd8SPaul Burton void __user *fault_addr = NULL; 91685164fd8SPaul Burton 91734c2f668SLeonid Yegoshin fpu_emul: 91834c2f668SLeonid Yegoshin /* roll back jump/branch */ 91934c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 92034c2f668SLeonid Yegoshin regs->regs[31] = orig31; 92134c2f668SLeonid Yegoshin 92234c2f668SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs); 92334c2f668SLeonid Yegoshin BUG_ON(!used_math()); 92434c2f668SLeonid Yegoshin BUG_ON(!is_fpu_owner()); 92534c2f668SLeonid Yegoshin 92634c2f668SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, 92734c2f668SLeonid Yegoshin &fault_addr); 92834c2f668SLeonid Yegoshin own_fpu(1); /* restore FPU state */ 92934c2f668SLeonid Yegoshin 93034c2f668SLeonid Yegoshin /* If something went wrong, signal */ 931304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0); 93234c2f668SLeonid Yegoshin 93334c2f668SLeonid Yegoshin if (res == 0) 93434c2f668SLeonid Yegoshin goto success; 93534c2f668SLeonid Yegoshin return; 93685164fd8SPaul Burton } 93785164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */ 93834c2f668SLeonid Yegoshin 93934c2f668SLeonid Yegoshin case mm_lh32_op: 94034c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 94134c2f668SLeonid Yegoshin goto loadHW; 94234c2f668SLeonid Yegoshin 94334c2f668SLeonid Yegoshin case mm_lhu32_op: 94434c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 94534c2f668SLeonid Yegoshin goto loadHWU; 94634c2f668SLeonid Yegoshin 94734c2f668SLeonid Yegoshin case mm_lw32_op: 94834c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 94934c2f668SLeonid Yegoshin goto loadW; 95034c2f668SLeonid Yegoshin 95134c2f668SLeonid Yegoshin case mm_sh32_op: 95234c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 95334c2f668SLeonid Yegoshin goto storeHW; 95434c2f668SLeonid Yegoshin 95534c2f668SLeonid Yegoshin case mm_sw32_op: 95634c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 95734c2f668SLeonid Yegoshin goto storeW; 95834c2f668SLeonid Yegoshin 95934c2f668SLeonid Yegoshin case mm_ld32_op: 96034c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 96134c2f668SLeonid Yegoshin goto loadDW; 96234c2f668SLeonid Yegoshin 96334c2f668SLeonid Yegoshin case mm_sd32_op: 96434c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt; 96534c2f668SLeonid Yegoshin goto storeDW; 96634c2f668SLeonid Yegoshin 96734c2f668SLeonid Yegoshin case mm_pool16c_op: 96834c2f668SLeonid Yegoshin switch (insn.mm16_m_format.func) { 96934c2f668SLeonid Yegoshin case mm_lwm16_op: 97034c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist; 97134c2f668SLeonid Yegoshin rvar = reg + 1; 97245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar)) 97334c2f668SLeonid Yegoshin goto sigbus; 97434c2f668SLeonid Yegoshin 97534c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 97634c2f668SLeonid Yegoshin LoadW(addr, value, res); 97734c2f668SLeonid Yegoshin if (res) 97834c2f668SLeonid Yegoshin goto fault; 97934c2f668SLeonid Yegoshin addr += 4; 98034c2f668SLeonid Yegoshin regs->regs[i] = value; 98134c2f668SLeonid Yegoshin } 98234c2f668SLeonid Yegoshin LoadW(addr, value, res); 98334c2f668SLeonid Yegoshin if (res) 98434c2f668SLeonid Yegoshin goto fault; 98534c2f668SLeonid Yegoshin regs->regs[31] = value; 98634c2f668SLeonid Yegoshin 98734c2f668SLeonid Yegoshin goto success; 98834c2f668SLeonid Yegoshin 98934c2f668SLeonid Yegoshin case mm_swm16_op: 99034c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist; 99134c2f668SLeonid Yegoshin rvar = reg + 1; 99245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar)) 99334c2f668SLeonid Yegoshin goto sigbus; 99434c2f668SLeonid Yegoshin 99534c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) { 99634c2f668SLeonid Yegoshin value = regs->regs[i]; 99734c2f668SLeonid Yegoshin StoreW(addr, value, res); 99834c2f668SLeonid Yegoshin if (res) 99934c2f668SLeonid Yegoshin goto fault; 100034c2f668SLeonid Yegoshin addr += 4; 100134c2f668SLeonid Yegoshin } 100234c2f668SLeonid Yegoshin value = regs->regs[31]; 100334c2f668SLeonid Yegoshin StoreW(addr, value, res); 100434c2f668SLeonid Yegoshin if (res) 100534c2f668SLeonid Yegoshin goto fault; 100634c2f668SLeonid Yegoshin 100734c2f668SLeonid Yegoshin goto success; 100834c2f668SLeonid Yegoshin 100934c2f668SLeonid Yegoshin } 101034c2f668SLeonid Yegoshin 101134c2f668SLeonid Yegoshin goto sigbus; 101234c2f668SLeonid Yegoshin 101334c2f668SLeonid Yegoshin case mm_lhu16_op: 101434c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt]; 101534c2f668SLeonid Yegoshin goto loadHWU; 101634c2f668SLeonid Yegoshin 101734c2f668SLeonid Yegoshin case mm_lw16_op: 101834c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt]; 101934c2f668SLeonid Yegoshin goto loadW; 102034c2f668SLeonid Yegoshin 102134c2f668SLeonid Yegoshin case mm_sh16_op: 102234c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt]; 102334c2f668SLeonid Yegoshin goto storeHW; 102434c2f668SLeonid Yegoshin 102534c2f668SLeonid Yegoshin case mm_sw16_op: 102634c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt]; 102734c2f668SLeonid Yegoshin goto storeW; 102834c2f668SLeonid Yegoshin 102934c2f668SLeonid Yegoshin case mm_lwsp16_op: 103034c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt; 103134c2f668SLeonid Yegoshin goto loadW; 103234c2f668SLeonid Yegoshin 103334c2f668SLeonid Yegoshin case mm_swsp16_op: 103434c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt; 103534c2f668SLeonid Yegoshin goto storeW; 103634c2f668SLeonid Yegoshin 103734c2f668SLeonid Yegoshin case mm_lwgp16_op: 103834c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_r3_format.rt]; 103934c2f668SLeonid Yegoshin goto loadW; 104034c2f668SLeonid Yegoshin 104134c2f668SLeonid Yegoshin default: 104234c2f668SLeonid Yegoshin goto sigill; 104334c2f668SLeonid Yegoshin } 104434c2f668SLeonid Yegoshin 104534c2f668SLeonid Yegoshin loadHW: 104645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 104734c2f668SLeonid Yegoshin goto sigbus; 104834c2f668SLeonid Yegoshin 104934c2f668SLeonid Yegoshin LoadHW(addr, value, res); 105034c2f668SLeonid Yegoshin if (res) 105134c2f668SLeonid Yegoshin goto fault; 105234c2f668SLeonid Yegoshin regs->regs[reg] = value; 105334c2f668SLeonid Yegoshin goto success; 105434c2f668SLeonid Yegoshin 105534c2f668SLeonid Yegoshin loadHWU: 105645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 105734c2f668SLeonid Yegoshin goto sigbus; 105834c2f668SLeonid Yegoshin 105934c2f668SLeonid Yegoshin LoadHWU(addr, value, res); 106034c2f668SLeonid Yegoshin if (res) 106134c2f668SLeonid Yegoshin goto fault; 106234c2f668SLeonid Yegoshin regs->regs[reg] = value; 106334c2f668SLeonid Yegoshin goto success; 106434c2f668SLeonid Yegoshin 106534c2f668SLeonid Yegoshin loadW: 106645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 106734c2f668SLeonid Yegoshin goto sigbus; 106834c2f668SLeonid Yegoshin 106934c2f668SLeonid Yegoshin LoadW(addr, value, res); 107034c2f668SLeonid Yegoshin if (res) 107134c2f668SLeonid Yegoshin goto fault; 107234c2f668SLeonid Yegoshin regs->regs[reg] = value; 107334c2f668SLeonid Yegoshin goto success; 107434c2f668SLeonid Yegoshin 107534c2f668SLeonid Yegoshin loadWU: 107634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 107734c2f668SLeonid Yegoshin /* 107834c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 107934c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 108034c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 108134c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 108234c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 108334c2f668SLeonid Yegoshin */ 108445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 108534c2f668SLeonid Yegoshin goto sigbus; 108634c2f668SLeonid Yegoshin 108734c2f668SLeonid Yegoshin LoadWU(addr, value, res); 108834c2f668SLeonid Yegoshin if (res) 108934c2f668SLeonid Yegoshin goto fault; 109034c2f668SLeonid Yegoshin regs->regs[reg] = value; 109134c2f668SLeonid Yegoshin goto success; 109234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 109334c2f668SLeonid Yegoshin 109434c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 109534c2f668SLeonid Yegoshin goto sigill; 109634c2f668SLeonid Yegoshin 109734c2f668SLeonid Yegoshin loadDW: 109834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 109934c2f668SLeonid Yegoshin /* 110034c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 110134c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 110234c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 110334c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 110434c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 110534c2f668SLeonid Yegoshin */ 110645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 110734c2f668SLeonid Yegoshin goto sigbus; 110834c2f668SLeonid Yegoshin 110934c2f668SLeonid Yegoshin LoadDW(addr, value, res); 111034c2f668SLeonid Yegoshin if (res) 111134c2f668SLeonid Yegoshin goto fault; 111234c2f668SLeonid Yegoshin regs->regs[reg] = value; 111334c2f668SLeonid Yegoshin goto success; 111434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 111534c2f668SLeonid Yegoshin 111634c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 111734c2f668SLeonid Yegoshin goto sigill; 111834c2f668SLeonid Yegoshin 111934c2f668SLeonid Yegoshin storeHW: 112045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 112134c2f668SLeonid Yegoshin goto sigbus; 112234c2f668SLeonid Yegoshin 112334c2f668SLeonid Yegoshin value = regs->regs[reg]; 112434c2f668SLeonid Yegoshin StoreHW(addr, value, res); 112534c2f668SLeonid Yegoshin if (res) 112634c2f668SLeonid Yegoshin goto fault; 112734c2f668SLeonid Yegoshin goto success; 112834c2f668SLeonid Yegoshin 112934c2f668SLeonid Yegoshin storeW: 113045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 113134c2f668SLeonid Yegoshin goto sigbus; 113234c2f668SLeonid Yegoshin 113334c2f668SLeonid Yegoshin value = regs->regs[reg]; 113434c2f668SLeonid Yegoshin StoreW(addr, value, res); 113534c2f668SLeonid Yegoshin if (res) 113634c2f668SLeonid Yegoshin goto fault; 113734c2f668SLeonid Yegoshin goto success; 113834c2f668SLeonid Yegoshin 113934c2f668SLeonid Yegoshin storeDW: 114034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT 114134c2f668SLeonid Yegoshin /* 114234c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But 114334c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency 114434c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr 114534c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit 114634c2f668SLeonid Yegoshin * instructions on 32-bit kernels. 114734c2f668SLeonid Yegoshin */ 114845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 114934c2f668SLeonid Yegoshin goto sigbus; 115034c2f668SLeonid Yegoshin 115134c2f668SLeonid Yegoshin value = regs->regs[reg]; 115234c2f668SLeonid Yegoshin StoreDW(addr, value, res); 115334c2f668SLeonid Yegoshin if (res) 115434c2f668SLeonid Yegoshin goto fault; 115534c2f668SLeonid Yegoshin goto success; 115634c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */ 115734c2f668SLeonid Yegoshin 115834c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */ 115934c2f668SLeonid Yegoshin goto sigill; 116034c2f668SLeonid Yegoshin 116134c2f668SLeonid Yegoshin success: 116234c2f668SLeonid Yegoshin regs->cp0_epc = contpc; /* advance or branch */ 116334c2f668SLeonid Yegoshin 116434c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS 116534c2f668SLeonid Yegoshin unaligned_instructions++; 116634c2f668SLeonid Yegoshin #endif 116734c2f668SLeonid Yegoshin return; 116834c2f668SLeonid Yegoshin 116934c2f668SLeonid Yegoshin fault: 117034c2f668SLeonid Yegoshin /* roll back jump/branch */ 117134c2f668SLeonid Yegoshin regs->cp0_epc = origpc; 117234c2f668SLeonid Yegoshin regs->regs[31] = orig31; 117334c2f668SLeonid Yegoshin /* Did we have an exception handler installed? */ 117434c2f668SLeonid Yegoshin if (fixup_exception(regs)) 117534c2f668SLeonid Yegoshin return; 117634c2f668SLeonid Yegoshin 117734c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs); 11783cf5d076SEric W. Biederman force_sig(SIGSEGV); 117934c2f668SLeonid Yegoshin 118034c2f668SLeonid Yegoshin return; 118134c2f668SLeonid Yegoshin 118234c2f668SLeonid Yegoshin sigbus: 118334c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs); 11843cf5d076SEric W. Biederman force_sig(SIGBUS); 118534c2f668SLeonid Yegoshin 118634c2f668SLeonid Yegoshin return; 118734c2f668SLeonid Yegoshin 118834c2f668SLeonid Yegoshin sigill: 118934c2f668SLeonid Yegoshin die_if_kernel 119034c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs); 11913cf5d076SEric W. Biederman force_sig(SIGILL); 11921da177e4SLinus Torvalds } 11931da177e4SLinus Torvalds 1194451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr) 1195451b001bSSteven J. Hill { 1196451b001bSSteven J. Hill unsigned long value; 1197451b001bSSteven J. Hill unsigned int res; 1198451b001bSSteven J. Hill int reg; 1199451b001bSSteven J. Hill unsigned long orig31; 1200451b001bSSteven J. Hill u16 __user *pc16; 1201451b001bSSteven J. Hill unsigned long origpc; 1202451b001bSSteven J. Hill union mips16e_instruction mips16inst, oldinst; 1203f3235d32SMaciej W. Rozycki unsigned int opcode; 1204f3235d32SMaciej W. Rozycki int extended = 0; 120545deb5faSThomas Bogendoerfer bool user = user_mode(regs); 1206451b001bSSteven J. Hill 1207451b001bSSteven J. Hill origpc = regs->cp0_epc; 1208451b001bSSteven J. Hill orig31 = regs->regs[31]; 1209451b001bSSteven J. Hill pc16 = (unsigned short __user *)msk_isa16_mode(origpc); 1210451b001bSSteven J. Hill /* 1211451b001bSSteven J. Hill * This load never faults. 1212451b001bSSteven J. Hill */ 1213451b001bSSteven J. Hill __get_user(mips16inst.full, pc16); 1214451b001bSSteven J. Hill oldinst = mips16inst; 1215451b001bSSteven J. Hill 1216451b001bSSteven J. Hill /* skip EXTEND instruction */ 1217451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_extend_op) { 1218f3235d32SMaciej W. Rozycki extended = 1; 1219451b001bSSteven J. Hill pc16++; 1220451b001bSSteven J. Hill __get_user(mips16inst.full, pc16); 1221451b001bSSteven J. Hill } else if (delay_slot(regs)) { 1222451b001bSSteven J. Hill /* skip jump instructions */ 1223451b001bSSteven J. Hill /* JAL/JALX are 32 bits but have OPCODE in first short int */ 1224451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_jal_op) 1225451b001bSSteven J. Hill pc16++; 1226451b001bSSteven J. Hill pc16++; 1227451b001bSSteven J. Hill if (get_user(mips16inst.full, pc16)) 1228451b001bSSteven J. Hill goto sigbus; 1229451b001bSSteven J. Hill } 1230451b001bSSteven J. Hill 1231f3235d32SMaciej W. Rozycki opcode = mips16inst.ri.opcode; 1232f3235d32SMaciej W. Rozycki switch (opcode) { 1233451b001bSSteven J. Hill case MIPS16e_i64_op: /* I64 or RI64 instruction */ 1234451b001bSSteven J. Hill switch (mips16inst.i64.func) { /* I64/RI64 func field check */ 1235451b001bSSteven J. Hill case MIPS16e_ldpc_func: 1236451b001bSSteven J. Hill case MIPS16e_ldsp_func: 1237451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry]; 1238451b001bSSteven J. Hill goto loadDW; 1239451b001bSSteven J. Hill 1240451b001bSSteven J. Hill case MIPS16e_sdsp_func: 1241451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry]; 1242451b001bSSteven J. Hill goto writeDW; 1243451b001bSSteven J. Hill 1244451b001bSSteven J. Hill case MIPS16e_sdrasp_func: 1245451b001bSSteven J. Hill reg = 29; /* GPRSP */ 1246451b001bSSteven J. Hill goto writeDW; 1247451b001bSSteven J. Hill } 1248451b001bSSteven J. Hill 1249451b001bSSteven J. Hill goto sigbus; 1250451b001bSSteven J. Hill 1251451b001bSSteven J. Hill case MIPS16e_swsp_op: 1252f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx]; 1253f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2) 1254f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) { 1255f3235d32SMaciej W. Rozycki case 0: /* SWSP */ 1256f3235d32SMaciej W. Rozycki case 1: /* SWGP */ 1257f3235d32SMaciej W. Rozycki break; 1258f3235d32SMaciej W. Rozycki case 2: /* SHGP */ 1259f3235d32SMaciej W. Rozycki opcode = MIPS16e_sh_op; 1260f3235d32SMaciej W. Rozycki break; 1261f3235d32SMaciej W. Rozycki default: 1262f3235d32SMaciej W. Rozycki goto sigbus; 1263f3235d32SMaciej W. Rozycki } 1264f3235d32SMaciej W. Rozycki break; 1265f3235d32SMaciej W. Rozycki 1266451b001bSSteven J. Hill case MIPS16e_lwpc_op: 1267f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx]; 1268f3235d32SMaciej W. Rozycki break; 1269f3235d32SMaciej W. Rozycki 1270451b001bSSteven J. Hill case MIPS16e_lwsp_op: 1271451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri.rx]; 1272f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2) 1273f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) { 1274f3235d32SMaciej W. Rozycki case 0: /* LWSP */ 1275f3235d32SMaciej W. Rozycki case 1: /* LWGP */ 1276f3235d32SMaciej W. Rozycki break; 1277f3235d32SMaciej W. Rozycki case 2: /* LHGP */ 1278f3235d32SMaciej W. Rozycki opcode = MIPS16e_lh_op; 1279f3235d32SMaciej W. Rozycki break; 1280f3235d32SMaciej W. Rozycki case 4: /* LHUGP */ 1281f3235d32SMaciej W. Rozycki opcode = MIPS16e_lhu_op; 1282f3235d32SMaciej W. Rozycki break; 1283f3235d32SMaciej W. Rozycki default: 1284f3235d32SMaciej W. Rozycki goto sigbus; 1285f3235d32SMaciej W. Rozycki } 1286451b001bSSteven J. Hill break; 1287451b001bSSteven J. Hill 1288451b001bSSteven J. Hill case MIPS16e_i8_op: 1289451b001bSSteven J. Hill if (mips16inst.i8.func != MIPS16e_swrasp_func) 1290451b001bSSteven J. Hill goto sigbus; 1291451b001bSSteven J. Hill reg = 29; /* GPRSP */ 1292451b001bSSteven J. Hill break; 1293451b001bSSteven J. Hill 1294451b001bSSteven J. Hill default: 1295451b001bSSteven J. Hill reg = reg16to32[mips16inst.rri.ry]; 1296451b001bSSteven J. Hill break; 1297451b001bSSteven J. Hill } 1298451b001bSSteven J. Hill 1299f3235d32SMaciej W. Rozycki switch (opcode) { 1300451b001bSSteven J. Hill 1301451b001bSSteven J. Hill case MIPS16e_lb_op: 1302451b001bSSteven J. Hill case MIPS16e_lbu_op: 1303451b001bSSteven J. Hill case MIPS16e_sb_op: 1304451b001bSSteven J. Hill goto sigbus; 1305451b001bSSteven J. Hill 1306451b001bSSteven J. Hill case MIPS16e_lh_op: 130745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 1308451b001bSSteven J. Hill goto sigbus; 1309451b001bSSteven J. Hill 1310451b001bSSteven J. Hill LoadHW(addr, value, res); 1311451b001bSSteven J. Hill if (res) 1312451b001bSSteven J. Hill goto fault; 1313451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1314451b001bSSteven J. Hill regs->regs[reg] = value; 1315451b001bSSteven J. Hill break; 1316451b001bSSteven J. Hill 1317451b001bSSteven J. Hill case MIPS16e_lhu_op: 131845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 1319451b001bSSteven J. Hill goto sigbus; 1320451b001bSSteven J. Hill 1321451b001bSSteven J. Hill LoadHWU(addr, value, res); 1322451b001bSSteven J. Hill if (res) 1323451b001bSSteven J. Hill goto fault; 1324451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1325451b001bSSteven J. Hill regs->regs[reg] = value; 1326451b001bSSteven J. Hill break; 1327451b001bSSteven J. Hill 1328451b001bSSteven J. Hill case MIPS16e_lw_op: 1329451b001bSSteven J. Hill case MIPS16e_lwpc_op: 1330451b001bSSteven J. Hill case MIPS16e_lwsp_op: 133145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 1332451b001bSSteven J. Hill goto sigbus; 1333451b001bSSteven J. Hill 1334451b001bSSteven J. Hill LoadW(addr, value, res); 1335451b001bSSteven J. Hill if (res) 1336451b001bSSteven J. Hill goto fault; 1337451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1338451b001bSSteven J. Hill regs->regs[reg] = value; 1339451b001bSSteven J. Hill break; 1340451b001bSSteven J. Hill 1341451b001bSSteven J. Hill case MIPS16e_lwu_op: 1342451b001bSSteven J. Hill #ifdef CONFIG_64BIT 1343451b001bSSteven J. Hill /* 1344451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 1345451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 1346451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 1347451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 1348451b001bSSteven J. Hill * instructions on 32-bit kernels. 1349451b001bSSteven J. Hill */ 135045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 1351451b001bSSteven J. Hill goto sigbus; 1352451b001bSSteven J. Hill 1353451b001bSSteven J. Hill LoadWU(addr, value, res); 1354451b001bSSteven J. Hill if (res) 1355451b001bSSteven J. Hill goto fault; 1356451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1357451b001bSSteven J. Hill regs->regs[reg] = value; 1358451b001bSSteven J. Hill break; 1359451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 1360451b001bSSteven J. Hill 1361451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 1362451b001bSSteven J. Hill goto sigill; 1363451b001bSSteven J. Hill 1364451b001bSSteven J. Hill case MIPS16e_ld_op: 1365451b001bSSteven J. Hill loadDW: 1366451b001bSSteven J. Hill #ifdef CONFIG_64BIT 1367451b001bSSteven J. Hill /* 1368451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 1369451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 1370451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 1371451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 1372451b001bSSteven J. Hill * instructions on 32-bit kernels. 1373451b001bSSteven J. Hill */ 137445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 1375451b001bSSteven J. Hill goto sigbus; 1376451b001bSSteven J. Hill 1377451b001bSSteven J. Hill LoadDW(addr, value, res); 1378451b001bSSteven J. Hill if (res) 1379451b001bSSteven J. Hill goto fault; 1380451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1381451b001bSSteven J. Hill regs->regs[reg] = value; 1382451b001bSSteven J. Hill break; 1383451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 1384451b001bSSteven J. Hill 1385451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 1386451b001bSSteven J. Hill goto sigill; 1387451b001bSSteven J. Hill 1388451b001bSSteven J. Hill case MIPS16e_sh_op: 138945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2)) 1390451b001bSSteven J. Hill goto sigbus; 1391451b001bSSteven J. Hill 1392451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1393451b001bSSteven J. Hill value = regs->regs[reg]; 1394451b001bSSteven J. Hill StoreHW(addr, value, res); 1395451b001bSSteven J. Hill if (res) 1396451b001bSSteven J. Hill goto fault; 1397451b001bSSteven J. Hill break; 1398451b001bSSteven J. Hill 1399451b001bSSteven J. Hill case MIPS16e_sw_op: 1400451b001bSSteven J. Hill case MIPS16e_swsp_op: 1401451b001bSSteven J. Hill case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */ 140245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4)) 1403451b001bSSteven J. Hill goto sigbus; 1404451b001bSSteven J. Hill 1405451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1406451b001bSSteven J. Hill value = regs->regs[reg]; 1407451b001bSSteven J. Hill StoreW(addr, value, res); 1408451b001bSSteven J. Hill if (res) 1409451b001bSSteven J. Hill goto fault; 1410451b001bSSteven J. Hill break; 1411451b001bSSteven J. Hill 1412451b001bSSteven J. Hill case MIPS16e_sd_op: 1413451b001bSSteven J. Hill writeDW: 1414451b001bSSteven J. Hill #ifdef CONFIG_64BIT 1415451b001bSSteven J. Hill /* 1416451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But 1417451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency 1418451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr 1419451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit 1420451b001bSSteven J. Hill * instructions on 32-bit kernels. 1421451b001bSSteven J. Hill */ 142245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8)) 1423451b001bSSteven J. Hill goto sigbus; 1424451b001bSSteven J. Hill 1425451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst); 1426451b001bSSteven J. Hill value = regs->regs[reg]; 1427451b001bSSteven J. Hill StoreDW(addr, value, res); 1428451b001bSSteven J. Hill if (res) 1429451b001bSSteven J. Hill goto fault; 1430451b001bSSteven J. Hill break; 1431451b001bSSteven J. Hill #endif /* CONFIG_64BIT */ 1432451b001bSSteven J. Hill 1433451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */ 1434451b001bSSteven J. Hill goto sigill; 1435451b001bSSteven J. Hill 1436451b001bSSteven J. Hill default: 1437451b001bSSteven J. Hill /* 1438451b001bSSteven J. Hill * Pheeee... We encountered an yet unknown instruction or 1439451b001bSSteven J. Hill * cache coherence problem. Die sucker, die ... 1440451b001bSSteven J. Hill */ 1441451b001bSSteven J. Hill goto sigill; 1442451b001bSSteven J. Hill } 1443451b001bSSteven J. Hill 1444451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS 1445451b001bSSteven J. Hill unaligned_instructions++; 1446451b001bSSteven J. Hill #endif 1447451b001bSSteven J. Hill 1448451b001bSSteven J. Hill return; 1449451b001bSSteven J. Hill 1450451b001bSSteven J. Hill fault: 1451451b001bSSteven J. Hill /* roll back jump/branch */ 1452451b001bSSteven J. Hill regs->cp0_epc = origpc; 1453451b001bSSteven J. Hill regs->regs[31] = orig31; 1454451b001bSSteven J. Hill /* Did we have an exception handler installed? */ 1455451b001bSSteven J. Hill if (fixup_exception(regs)) 1456451b001bSSteven J. Hill return; 1457451b001bSSteven J. Hill 1458451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs); 14593cf5d076SEric W. Biederman force_sig(SIGSEGV); 1460451b001bSSteven J. Hill 1461451b001bSSteven J. Hill return; 1462451b001bSSteven J. Hill 1463451b001bSSteven J. Hill sigbus: 1464451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs); 14653cf5d076SEric W. Biederman force_sig(SIGBUS); 1466451b001bSSteven J. Hill 1467451b001bSSteven J. Hill return; 1468451b001bSSteven J. Hill 1469451b001bSSteven J. Hill sigill: 1470451b001bSSteven J. Hill die_if_kernel 1471451b001bSSteven J. Hill ("Unhandled kernel unaligned access or invalid instruction", regs); 14723cf5d076SEric W. Biederman force_sig(SIGILL); 1473451b001bSSteven J. Hill } 1474fc192e50STony Wu 14751da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs) 14761da177e4SLinus Torvalds { 1477c3fc5cd5SRalf Baechle enum ctx_state prev_state; 14787cba4128SThomas Bogendoerfer unsigned int *pc; 14791da177e4SLinus Torvalds 1480c3fc5cd5SRalf Baechle prev_state = exception_enter(); 14817f788d2dSDeng-Cheng Zhu perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1482a8b0ca17SPeter Zijlstra 1, regs, regs->cp0_badvaddr); 1483*429124d9SThomas Bogendoerfer 1484*429124d9SThomas Bogendoerfer #ifdef CONFIG_64BIT 1485*429124d9SThomas Bogendoerfer /* 1486*429124d9SThomas Bogendoerfer * check, if we are hitting space between CPU implemented maximum 1487*429124d9SThomas Bogendoerfer * virtual user address and 64bit maximum virtual user address 1488*429124d9SThomas Bogendoerfer * and do exception handling to get EFAULTs for get_user/put_user 1489*429124d9SThomas Bogendoerfer */ 1490*429124d9SThomas Bogendoerfer if ((regs->cp0_badvaddr >= (1UL << cpu_vmbits)) && 1491*429124d9SThomas Bogendoerfer (regs->cp0_badvaddr < XKSSEG)) { 1492*429124d9SThomas Bogendoerfer if (fixup_exception(regs)) { 1493*429124d9SThomas Bogendoerfer current->thread.cp0_baduaddr = regs->cp0_badvaddr; 1494*429124d9SThomas Bogendoerfer return; 1495*429124d9SThomas Bogendoerfer } 1496*429124d9SThomas Bogendoerfer goto sigbus; 1497*429124d9SThomas Bogendoerfer } 1498*429124d9SThomas Bogendoerfer #endif 1499*429124d9SThomas Bogendoerfer 15001da177e4SLinus Torvalds /* 15011da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction? 15021da177e4SLinus Torvalds */ 150334c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == regs->cp0_epc) 15041da177e4SLinus Torvalds goto sigbus; 15051da177e4SLinus Torvalds 1506293c5bd1SRalf Baechle if (user_mode(regs) && !test_thread_flag(TIF_FIXADE)) 15071da177e4SLinus Torvalds goto sigbus; 15086312e0eeSAtsushi Nemoto if (unaligned_action == UNALIGNED_ACTION_SIGNAL) 15096312e0eeSAtsushi Nemoto goto sigbus; 15101da177e4SLinus Torvalds 15111da177e4SLinus Torvalds /* 15121da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception. 15131da177e4SLinus Torvalds * This is all so but ugly ... 15141da177e4SLinus Torvalds */ 151534c2f668SLeonid Yegoshin 151634c2f668SLeonid Yegoshin /* 151734c2f668SLeonid Yegoshin * Are we running in microMIPS mode? 151834c2f668SLeonid Yegoshin */ 151934c2f668SLeonid Yegoshin if (get_isa16_mode(regs->cp0_epc)) { 152034c2f668SLeonid Yegoshin /* 152134c2f668SLeonid Yegoshin * Did we catch a fault trying to load an instruction in 152234c2f668SLeonid Yegoshin * 16-bit mode? 152334c2f668SLeonid Yegoshin */ 152434c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc)) 152534c2f668SLeonid Yegoshin goto sigbus; 152634c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW) 152734c2f668SLeonid Yegoshin show_registers(regs); 152834c2f668SLeonid Yegoshin 152934c2f668SLeonid Yegoshin if (cpu_has_mmips) { 153034c2f668SLeonid Yegoshin emulate_load_store_microMIPS(regs, 153134c2f668SLeonid Yegoshin (void __user *)regs->cp0_badvaddr); 153234c2f668SLeonid Yegoshin return; 153334c2f668SLeonid Yegoshin } 153434c2f668SLeonid Yegoshin 1535451b001bSSteven J. Hill if (cpu_has_mips16) { 1536451b001bSSteven J. Hill emulate_load_store_MIPS16e(regs, 1537451b001bSSteven J. Hill (void __user *)regs->cp0_badvaddr); 1538451b001bSSteven J. Hill return; 1539451b001bSSteven J. Hill } 1540451b001bSSteven J. Hill 154134c2f668SLeonid Yegoshin goto sigbus; 154234c2f668SLeonid Yegoshin } 154334c2f668SLeonid Yegoshin 154434c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW) 154534c2f668SLeonid Yegoshin show_registers(regs); 15467cba4128SThomas Bogendoerfer pc = (unsigned int *)exception_epc(regs); 154734c2f668SLeonid Yegoshin 15487f18f151SRalf Baechle emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); 15491da177e4SLinus Torvalds 15501da177e4SLinus Torvalds return; 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds sigbus: 15531da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs); 15543cf5d076SEric W. Biederman force_sig(SIGBUS); 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds /* 15571da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc 15581da177e4SLinus Torvalds */ 1559c3fc5cd5SRalf Baechle exception_exit(prev_state); 15601da177e4SLinus Torvalds } 15616312e0eeSAtsushi Nemoto 15626312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS 15636312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void) 15646312e0eeSAtsushi Nemoto { 1565d8140426SGreg Kroah-Hartman debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir, 1566d8140426SGreg Kroah-Hartman &unaligned_instructions); 1567d8140426SGreg Kroah-Hartman debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR, 15686312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_action); 15696312e0eeSAtsushi Nemoto return 0; 15706312e0eeSAtsushi Nemoto } 15718d6b591cSRalf Baechle arch_initcall(debugfs_unaligned); 15726312e0eeSAtsushi Nemoto #endif 1573