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>
94*09fc778eSArnd Bergmann #include <asm/traps.h>
957c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
961da177e4SLinus Torvalds
9745deb5faSThomas Bogendoerfer #include "access-helper.h"
9845deb5faSThomas Bogendoerfer
996312e0eeSAtsushi Nemoto enum {
1006312e0eeSAtsushi Nemoto UNALIGNED_ACTION_QUIET,
1016312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SIGNAL,
1026312e0eeSAtsushi Nemoto UNALIGNED_ACTION_SHOW,
1036312e0eeSAtsushi Nemoto };
1046312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
1056312e0eeSAtsushi Nemoto static u32 unaligned_instructions;
1066312e0eeSAtsushi Nemoto static u32 unaligned_action;
1076312e0eeSAtsushi Nemoto #else
1086312e0eeSAtsushi Nemoto #define unaligned_action UNALIGNED_ACTION_QUIET
1091da177e4SLinus Torvalds #endif
1106312e0eeSAtsushi Nemoto extern void show_registers(struct pt_regs *regs);
1111da177e4SLinus Torvalds
emulate_load_store_insn(struct pt_regs * regs,void __user * addr,unsigned int * pc)1127f18f151SRalf Baechle static void emulate_load_store_insn(struct pt_regs *regs,
1137cba4128SThomas Bogendoerfer void __user *addr, unsigned int *pc)
1141da177e4SLinus Torvalds {
11585164fd8SPaul Burton unsigned long origpc, orig31, value;
1161da177e4SLinus Torvalds union mips_instruction insn;
11785164fd8SPaul Burton unsigned int res;
11845deb5faSThomas Bogendoerfer bool user = user_mode(regs);
11945deb5faSThomas Bogendoerfer
12034c2f668SLeonid Yegoshin origpc = (unsigned long)pc;
12134c2f668SLeonid Yegoshin orig31 = regs->regs[31];
12234c2f668SLeonid Yegoshin
123a8b0ca17SPeter Zijlstra perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
1247f788d2dSDeng-Cheng Zhu
1251da177e4SLinus Torvalds /*
1261da177e4SLinus Torvalds * This load never faults.
1271da177e4SLinus Torvalds */
12845deb5faSThomas Bogendoerfer __get_inst32(&insn.word, pc, user);
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds switch (insn.i_format.opcode) {
1311da177e4SLinus Torvalds /*
1321da177e4SLinus Torvalds * These are instructions that a compiler doesn't generate. We
1331da177e4SLinus Torvalds * can assume therefore that the code is MIPS-aware and
1341da177e4SLinus Torvalds * really buggy. Emulating these instructions would break the
1351da177e4SLinus Torvalds * semantics anyway.
1361da177e4SLinus Torvalds */
1371da177e4SLinus Torvalds case ll_op:
1381da177e4SLinus Torvalds case lld_op:
1391da177e4SLinus Torvalds case sc_op:
1401da177e4SLinus Torvalds case scd_op:
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds /*
1431da177e4SLinus Torvalds * For these instructions the only way to create an address
1441da177e4SLinus Torvalds * error is an attempted access to kernel/supervisor address
1451da177e4SLinus Torvalds * space.
1461da177e4SLinus Torvalds */
1471da177e4SLinus Torvalds case ldl_op:
1481da177e4SLinus Torvalds case ldr_op:
1491da177e4SLinus Torvalds case lwl_op:
1501da177e4SLinus Torvalds case lwr_op:
1511da177e4SLinus Torvalds case sdl_op:
1521da177e4SLinus Torvalds case sdr_op:
1531da177e4SLinus Torvalds case swl_op:
1541da177e4SLinus Torvalds case swr_op:
1551da177e4SLinus Torvalds case lb_op:
1561da177e4SLinus Torvalds case lbu_op:
1571da177e4SLinus Torvalds case sb_op:
1581da177e4SLinus Torvalds goto sigbus;
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds /*
16134c2f668SLeonid Yegoshin * The remaining opcodes are the ones that are really of
16234c2f668SLeonid Yegoshin * interest.
1631da177e4SLinus Torvalds */
1646673c276SSiarhei Volkau #ifdef CONFIG_MACH_INGENIC
1656673c276SSiarhei Volkau case spec2_op:
1666673c276SSiarhei Volkau if (insn.mxu_lx_format.func != mxu_lx_op)
1676673c276SSiarhei Volkau goto sigbus; /* other MXU instructions we don't care */
1686673c276SSiarhei Volkau
1696673c276SSiarhei Volkau switch (insn.mxu_lx_format.op) {
1706673c276SSiarhei Volkau case mxu_lxw_op:
1716673c276SSiarhei Volkau if (user && !access_ok(addr, 4))
1726673c276SSiarhei Volkau goto sigbus;
1736673c276SSiarhei Volkau LoadW(addr, value, res);
1746673c276SSiarhei Volkau if (res)
1756673c276SSiarhei Volkau goto fault;
1766673c276SSiarhei Volkau compute_return_epc(regs);
1776673c276SSiarhei Volkau regs->regs[insn.mxu_lx_format.rd] = value;
1786673c276SSiarhei Volkau break;
1796673c276SSiarhei Volkau case mxu_lxh_op:
1806673c276SSiarhei Volkau if (user && !access_ok(addr, 2))
1816673c276SSiarhei Volkau goto sigbus;
1826673c276SSiarhei Volkau LoadHW(addr, value, res);
1836673c276SSiarhei Volkau if (res)
1846673c276SSiarhei Volkau goto fault;
1856673c276SSiarhei Volkau compute_return_epc(regs);
1866673c276SSiarhei Volkau regs->regs[insn.dsp_format.rd] = value;
1876673c276SSiarhei Volkau break;
1886673c276SSiarhei Volkau case mxu_lxhu_op:
1896673c276SSiarhei Volkau if (user && !access_ok(addr, 2))
1906673c276SSiarhei Volkau goto sigbus;
1916673c276SSiarhei Volkau LoadHWU(addr, value, res);
1926673c276SSiarhei Volkau if (res)
1936673c276SSiarhei Volkau goto fault;
1946673c276SSiarhei Volkau compute_return_epc(regs);
1956673c276SSiarhei Volkau regs->regs[insn.dsp_format.rd] = value;
1966673c276SSiarhei Volkau break;
1976673c276SSiarhei Volkau case mxu_lxb_op:
1986673c276SSiarhei Volkau case mxu_lxbu_op:
1996673c276SSiarhei Volkau goto sigbus;
2006673c276SSiarhei Volkau default:
2016673c276SSiarhei Volkau goto sigill;
2026673c276SSiarhei Volkau }
2036673c276SSiarhei Volkau break;
2046673c276SSiarhei Volkau #endif
205c1771216SLeonid Yegoshin case spec3_op:
2063f88ec63SMiodrag Dinic if (insn.dsp_format.func == lx_op) {
2073f88ec63SMiodrag Dinic switch (insn.dsp_format.op) {
2083f88ec63SMiodrag Dinic case lwx_op:
20945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
2103f88ec63SMiodrag Dinic goto sigbus;
2113f88ec63SMiodrag Dinic LoadW(addr, value, res);
2123f88ec63SMiodrag Dinic if (res)
2133f88ec63SMiodrag Dinic goto fault;
2143f88ec63SMiodrag Dinic compute_return_epc(regs);
2153f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value;
2163f88ec63SMiodrag Dinic break;
2173f88ec63SMiodrag Dinic case lhx_op:
21845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
2193f88ec63SMiodrag Dinic goto sigbus;
2203f88ec63SMiodrag Dinic LoadHW(addr, value, res);
2213f88ec63SMiodrag Dinic if (res)
2223f88ec63SMiodrag Dinic goto fault;
2233f88ec63SMiodrag Dinic compute_return_epc(regs);
2243f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value;
2253f88ec63SMiodrag Dinic break;
2263f88ec63SMiodrag Dinic default:
2273f88ec63SMiodrag Dinic goto sigill;
2283f88ec63SMiodrag Dinic }
2293f88ec63SMiodrag Dinic }
2303f88ec63SMiodrag Dinic #ifdef CONFIG_EVA
2313f88ec63SMiodrag Dinic else {
232c1771216SLeonid Yegoshin /*
2333f88ec63SMiodrag Dinic * we can land here only from kernel accessing user
2343f88ec63SMiodrag Dinic * memory, so we need to "switch" the address limit to
2353f88ec63SMiodrag Dinic * user space, so that address check can work properly.
236c1771216SLeonid Yegoshin */
237c1771216SLeonid Yegoshin switch (insn.spec3_format.func) {
238c1771216SLeonid Yegoshin case lhe_op:
23945deb5faSThomas Bogendoerfer if (!access_ok(addr, 2))
240c1771216SLeonid Yegoshin goto sigbus;
241eeb53895SMarkos Chandras LoadHWE(addr, value, res);
24245deb5faSThomas Bogendoerfer if (res)
243c1771216SLeonid Yegoshin goto fault;
244c1771216SLeonid Yegoshin compute_return_epc(regs);
245c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value;
246c1771216SLeonid Yegoshin break;
247c1771216SLeonid Yegoshin case lwe_op:
24845deb5faSThomas Bogendoerfer if (!access_ok(addr, 4))
249c1771216SLeonid Yegoshin goto sigbus;
250eeb53895SMarkos Chandras LoadWE(addr, value, res);
25145deb5faSThomas Bogendoerfer if (res)
252c1771216SLeonid Yegoshin goto fault;
253c1771216SLeonid Yegoshin compute_return_epc(regs);
254c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value;
255c1771216SLeonid Yegoshin break;
256c1771216SLeonid Yegoshin case lhue_op:
25745deb5faSThomas Bogendoerfer if (!access_ok(addr, 2))
258c1771216SLeonid Yegoshin goto sigbus;
259eeb53895SMarkos Chandras LoadHWUE(addr, value, res);
26045deb5faSThomas Bogendoerfer if (res)
261c1771216SLeonid Yegoshin goto fault;
262c1771216SLeonid Yegoshin compute_return_epc(regs);
263c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value;
264c1771216SLeonid Yegoshin break;
265c1771216SLeonid Yegoshin case she_op:
26645deb5faSThomas Bogendoerfer if (!access_ok(addr, 2))
267c1771216SLeonid Yegoshin goto sigbus;
268c1771216SLeonid Yegoshin compute_return_epc(regs);
269c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt];
270eeb53895SMarkos Chandras StoreHWE(addr, value, res);
27145deb5faSThomas Bogendoerfer if (res)
272c1771216SLeonid Yegoshin goto fault;
273c1771216SLeonid Yegoshin break;
274c1771216SLeonid Yegoshin case swe_op:
27545deb5faSThomas Bogendoerfer if (!access_ok(addr, 4))
276c1771216SLeonid Yegoshin goto sigbus;
277c1771216SLeonid Yegoshin compute_return_epc(regs);
278c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt];
279eeb53895SMarkos Chandras StoreWE(addr, value, res);
28045deb5faSThomas Bogendoerfer if (res)
281c1771216SLeonid Yegoshin goto fault;
282c1771216SLeonid Yegoshin break;
283c1771216SLeonid Yegoshin default:
284c1771216SLeonid Yegoshin goto sigill;
285c1771216SLeonid Yegoshin }
2863f88ec63SMiodrag Dinic }
287c1771216SLeonid Yegoshin #endif
2883f88ec63SMiodrag Dinic break;
2891da177e4SLinus Torvalds case lh_op:
29045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
2911da177e4SLinus Torvalds goto sigbus;
2921da177e4SLinus Torvalds
29345deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
2946eae3548SMarkos Chandras LoadHWE(addr, value, res);
29545deb5faSThomas Bogendoerfer else
2966eae3548SMarkos Chandras LoadHW(addr, value, res);
2976eae3548SMarkos Chandras
2981da177e4SLinus Torvalds if (res)
2991da177e4SLinus Torvalds goto fault;
3007f18f151SRalf Baechle compute_return_epc(regs);
3017f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3021da177e4SLinus Torvalds break;
3031da177e4SLinus Torvalds
3041da177e4SLinus Torvalds case lw_op:
30545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
3061da177e4SLinus Torvalds goto sigbus;
3071da177e4SLinus Torvalds
30845deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
3096eae3548SMarkos Chandras LoadWE(addr, value, res);
31045deb5faSThomas Bogendoerfer else
3116eae3548SMarkos Chandras LoadW(addr, value, res);
3126eae3548SMarkos Chandras
3131da177e4SLinus Torvalds if (res)
3141da177e4SLinus Torvalds goto fault;
3157f18f151SRalf Baechle compute_return_epc(regs);
3167f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3171da177e4SLinus Torvalds break;
3181da177e4SLinus Torvalds
3191da177e4SLinus Torvalds case lhu_op:
32045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
3211da177e4SLinus Torvalds goto sigbus;
3221da177e4SLinus Torvalds
32345deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
3246eae3548SMarkos Chandras LoadHWUE(addr, value, res);
32545deb5faSThomas Bogendoerfer else
3266eae3548SMarkos Chandras LoadHWU(addr, value, res);
3276eae3548SMarkos Chandras
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;
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds case lwu_op:
335875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3361da177e4SLinus Torvalds /*
3371da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But
3381da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency
3391da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr
3401da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit
3411da177e4SLinus Torvalds * instructions on 32-bit kernels.
3421da177e4SLinus Torvalds */
34345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
3441da177e4SLinus Torvalds goto sigbus;
3451da177e4SLinus Torvalds
34634c2f668SLeonid Yegoshin LoadWU(addr, value, res);
3471da177e4SLinus Torvalds if (res)
3481da177e4SLinus Torvalds goto fault;
3497f18f151SRalf Baechle compute_return_epc(regs);
3507f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3511da177e4SLinus Torvalds break;
352875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3531da177e4SLinus Torvalds
3541da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */
3551da177e4SLinus Torvalds goto sigill;
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds case ld_op:
358875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3591da177e4SLinus Torvalds /*
3601da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But
3611da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency
3621da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr
3631da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit
3641da177e4SLinus Torvalds * instructions on 32-bit kernels.
3651da177e4SLinus Torvalds */
36645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
3671da177e4SLinus Torvalds goto sigbus;
3681da177e4SLinus Torvalds
36934c2f668SLeonid Yegoshin LoadDW(addr, value, res);
3701da177e4SLinus Torvalds if (res)
3711da177e4SLinus Torvalds goto fault;
3727f18f151SRalf Baechle compute_return_epc(regs);
3737f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3741da177e4SLinus Torvalds break;
375875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3761da177e4SLinus Torvalds
3771da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */
3781da177e4SLinus Torvalds goto sigill;
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds case sh_op:
38145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
3821da177e4SLinus Torvalds goto sigbus;
3831da177e4SLinus Torvalds
38434c2f668SLeonid Yegoshin compute_return_epc(regs);
3851da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt];
3866eae3548SMarkos Chandras
38745deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
3886eae3548SMarkos Chandras StoreHWE(addr, value, res);
38945deb5faSThomas Bogendoerfer else
3906eae3548SMarkos Chandras StoreHW(addr, value, res);
3916eae3548SMarkos Chandras
3921da177e4SLinus Torvalds if (res)
3931da177e4SLinus Torvalds goto fault;
3941da177e4SLinus Torvalds break;
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds case sw_op:
39745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
3981da177e4SLinus Torvalds goto sigbus;
3991da177e4SLinus Torvalds
40034c2f668SLeonid Yegoshin compute_return_epc(regs);
4011da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt];
4026eae3548SMarkos Chandras
40345deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
4046eae3548SMarkos Chandras StoreWE(addr, value, res);
40545deb5faSThomas Bogendoerfer else
4066eae3548SMarkos Chandras StoreW(addr, value, res);
4076eae3548SMarkos Chandras
4081da177e4SLinus Torvalds if (res)
4091da177e4SLinus Torvalds goto fault;
4101da177e4SLinus Torvalds break;
4111da177e4SLinus Torvalds
4121da177e4SLinus Torvalds case sd_op:
413875d43e7SRalf Baechle #ifdef CONFIG_64BIT
4141da177e4SLinus Torvalds /*
4151da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But
4161da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency
4171da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr
4181da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit
4191da177e4SLinus Torvalds * instructions on 32-bit kernels.
4201da177e4SLinus Torvalds */
42145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
4221da177e4SLinus Torvalds goto sigbus;
4231da177e4SLinus Torvalds
42434c2f668SLeonid Yegoshin compute_return_epc(regs);
4251da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt];
42634c2f668SLeonid Yegoshin StoreDW(addr, value, res);
4271da177e4SLinus Torvalds if (res)
4281da177e4SLinus Torvalds goto fault;
4291da177e4SLinus Torvalds break;
430875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */
4331da177e4SLinus Torvalds goto sigill;
4341da177e4SLinus Torvalds
43585164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
43685164fd8SPaul Burton
4371da177e4SLinus Torvalds case lwc1_op:
4381da177e4SLinus Torvalds case ldc1_op:
4391da177e4SLinus Torvalds case swc1_op:
4401da177e4SLinus Torvalds case sdc1_op:
44185164fd8SPaul Burton case cop1x_op: {
44285164fd8SPaul Burton void __user *fault_addr = NULL;
44385164fd8SPaul Burton
444102cedc3SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs);
445102cedc3SLeonid Yegoshin BUG_ON(!used_math());
446102cedc3SLeonid Yegoshin
447102cedc3SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
448102cedc3SLeonid Yegoshin &fault_addr);
449102cedc3SLeonid Yegoshin own_fpu(1); /* Restore FPU state. */
450102cedc3SLeonid Yegoshin
451102cedc3SLeonid Yegoshin /* Signal if something went wrong. */
452304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0);
453102cedc3SLeonid Yegoshin
454102cedc3SLeonid Yegoshin if (res == 0)
455102cedc3SLeonid Yegoshin break;
456102cedc3SLeonid Yegoshin return;
45785164fd8SPaul Burton }
45885164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
4591da177e4SLinus Torvalds
46085164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
46185164fd8SPaul Burton
46285164fd8SPaul Burton case msa_op: {
46385164fd8SPaul Burton unsigned int wd, preempted;
46485164fd8SPaul Burton enum msa_2b_fmt df;
46585164fd8SPaul Burton union fpureg *fpr;
46685164fd8SPaul Burton
467e4aa1f15SLeonid Yegoshin if (!cpu_has_msa)
468e4aa1f15SLeonid Yegoshin goto sigill;
469e4aa1f15SLeonid Yegoshin
470e4aa1f15SLeonid Yegoshin /*
471e4aa1f15SLeonid Yegoshin * If we've reached this point then userland should have taken
472e4aa1f15SLeonid Yegoshin * the MSA disabled exception & initialised vector context at
473e4aa1f15SLeonid Yegoshin * some point in the past.
474e4aa1f15SLeonid Yegoshin */
475e4aa1f15SLeonid Yegoshin BUG_ON(!thread_msa_context_live());
476e4aa1f15SLeonid Yegoshin
477e4aa1f15SLeonid Yegoshin df = insn.msa_mi10_format.df;
478e4aa1f15SLeonid Yegoshin wd = insn.msa_mi10_format.wd;
479e4aa1f15SLeonid Yegoshin fpr = ¤t->thread.fpu.fpr[wd];
480e4aa1f15SLeonid Yegoshin
481e4aa1f15SLeonid Yegoshin switch (insn.msa_mi10_format.func) {
482e4aa1f15SLeonid Yegoshin case msa_ld_op:
48396d4f267SLinus Torvalds if (!access_ok(addr, sizeof(*fpr)))
484e4aa1f15SLeonid Yegoshin goto sigbus;
485e4aa1f15SLeonid Yegoshin
486fa8ff601SPaul Burton do {
487e4aa1f15SLeonid Yegoshin /*
488fa8ff601SPaul Burton * If we have live MSA context keep track of
489fa8ff601SPaul Burton * whether we get preempted in order to avoid
490fa8ff601SPaul Burton * the register context we load being clobbered
491fa8ff601SPaul Burton * by the live context as it's saved during
492fa8ff601SPaul Burton * preemption. If we don't have live context
493fa8ff601SPaul Burton * then it can't be saved to clobber the value
494fa8ff601SPaul Burton * we load.
495e4aa1f15SLeonid Yegoshin */
496fa8ff601SPaul Burton preempted = test_thread_flag(TIF_USEDMSA);
497e4aa1f15SLeonid Yegoshin
498e4aa1f15SLeonid Yegoshin res = __copy_from_user_inatomic(fpr, addr,
499e4aa1f15SLeonid Yegoshin sizeof(*fpr));
500e4aa1f15SLeonid Yegoshin if (res)
501e4aa1f15SLeonid Yegoshin goto fault;
502e4aa1f15SLeonid Yegoshin
503e4aa1f15SLeonid Yegoshin /*
504fa8ff601SPaul Burton * Update the hardware register if it is in use
505fa8ff601SPaul Burton * by the task in this quantum, in order to
506fa8ff601SPaul Burton * avoid having to save & restore the whole
507fa8ff601SPaul Burton * vector context.
508e4aa1f15SLeonid Yegoshin */
509fa8ff601SPaul Burton preempt_disable();
510fa8ff601SPaul Burton if (test_thread_flag(TIF_USEDMSA)) {
511e4aa1f15SLeonid Yegoshin write_msa_wr(wd, fpr, df);
512fa8ff601SPaul Burton preempted = 0;
513fa8ff601SPaul Burton }
514e4aa1f15SLeonid Yegoshin preempt_enable();
515fa8ff601SPaul Burton } while (preempted);
516e4aa1f15SLeonid Yegoshin break;
517e4aa1f15SLeonid Yegoshin
518e4aa1f15SLeonid Yegoshin case msa_st_op:
51996d4f267SLinus Torvalds if (!access_ok(addr, sizeof(*fpr)))
520e4aa1f15SLeonid Yegoshin goto sigbus;
521e4aa1f15SLeonid Yegoshin
522e4aa1f15SLeonid Yegoshin /*
523e4aa1f15SLeonid Yegoshin * Update from the hardware register if it is in use by
524e4aa1f15SLeonid Yegoshin * the task in this quantum, in order to avoid having to
525e4aa1f15SLeonid Yegoshin * save & restore the whole vector context.
526e4aa1f15SLeonid Yegoshin */
527e4aa1f15SLeonid Yegoshin preempt_disable();
528e4aa1f15SLeonid Yegoshin if (test_thread_flag(TIF_USEDMSA))
529e4aa1f15SLeonid Yegoshin read_msa_wr(wd, fpr, df);
530e4aa1f15SLeonid Yegoshin preempt_enable();
531e4aa1f15SLeonid Yegoshin
532e4aa1f15SLeonid Yegoshin res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr));
533e4aa1f15SLeonid Yegoshin if (res)
534e4aa1f15SLeonid Yegoshin goto fault;
535e4aa1f15SLeonid Yegoshin break;
536e4aa1f15SLeonid Yegoshin
537e4aa1f15SLeonid Yegoshin default:
538e4aa1f15SLeonid Yegoshin goto sigbus;
539e4aa1f15SLeonid Yegoshin }
540e4aa1f15SLeonid Yegoshin
541e4aa1f15SLeonid Yegoshin compute_return_epc(regs);
542e4aa1f15SLeonid Yegoshin break;
54385164fd8SPaul Burton }
54485164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */
545e4aa1f15SLeonid Yegoshin
5460593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
5471da177e4SLinus Torvalds /*
54869f3a7deSRalf Baechle * COP2 is available to implementor for application specific use.
54969f3a7deSRalf Baechle * It's up to applications to register a notifier chain and do
55069f3a7deSRalf Baechle * whatever they have to do, including possible sending of signals.
5510593a44cSLeonid Yegoshin *
5520593a44cSLeonid Yegoshin * This instruction has been reallocated in Release 6
5531da177e4SLinus Torvalds */
55469f3a7deSRalf Baechle case lwc2_op:
55569f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LWC2_OP, regs);
55669f3a7deSRalf Baechle break;
55769f3a7deSRalf Baechle
55869f3a7deSRalf Baechle case ldc2_op:
55969f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LDC2_OP, regs);
56069f3a7deSRalf Baechle break;
56169f3a7deSRalf Baechle
56269f3a7deSRalf Baechle case swc2_op:
56369f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SWC2_OP, regs);
56469f3a7deSRalf Baechle break;
56569f3a7deSRalf Baechle
56669f3a7deSRalf Baechle case sdc2_op:
56769f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SDC2_OP, regs);
56869f3a7deSRalf Baechle break;
5690593a44cSLeonid Yegoshin #endif
5701da177e4SLinus Torvalds default:
5711da177e4SLinus Torvalds /*
5721da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or
5731da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ...
5741da177e4SLinus Torvalds */
5751da177e4SLinus Torvalds goto sigill;
5761da177e4SLinus Torvalds }
5771da177e4SLinus Torvalds
5786312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
5791da177e4SLinus Torvalds unaligned_instructions++;
5801da177e4SLinus Torvalds #endif
5811da177e4SLinus Torvalds
5827f18f151SRalf Baechle return;
5831da177e4SLinus Torvalds
5841da177e4SLinus Torvalds fault:
58534c2f668SLeonid Yegoshin /* roll back jump/branch */
58634c2f668SLeonid Yegoshin regs->cp0_epc = origpc;
58734c2f668SLeonid Yegoshin regs->regs[31] = orig31;
5881da177e4SLinus Torvalds /* Did we have an exception handler installed? */
5891da177e4SLinus Torvalds if (fixup_exception(regs))
5907f18f151SRalf Baechle return;
5911da177e4SLinus Torvalds
5921da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs);
5933cf5d076SEric W. Biederman force_sig(SIGSEGV);
5941da177e4SLinus Torvalds
5957f18f151SRalf Baechle return;
5961da177e4SLinus Torvalds
5971da177e4SLinus Torvalds sigbus:
5981da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs);
5993cf5d076SEric W. Biederman force_sig(SIGBUS);
6001da177e4SLinus Torvalds
6017f18f151SRalf Baechle return;
6021da177e4SLinus Torvalds
6031da177e4SLinus Torvalds sigill:
60434c2f668SLeonid Yegoshin die_if_kernel
60534c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs);
6063cf5d076SEric W. Biederman force_sig(SIGILL);
60734c2f668SLeonid Yegoshin }
60834c2f668SLeonid Yegoshin
60934c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
61034c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
61134c2f668SLeonid Yegoshin
61234c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
613b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
61434c2f668SLeonid Yegoshin
emulate_load_store_microMIPS(struct pt_regs * regs,void __user * addr)61574338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
61674338805SDavid Daney void __user *addr)
61734c2f668SLeonid Yegoshin {
61834c2f668SLeonid Yegoshin unsigned long value;
61934c2f668SLeonid Yegoshin unsigned int res;
62034c2f668SLeonid Yegoshin int i;
62134c2f668SLeonid Yegoshin unsigned int reg = 0, rvar;
62234c2f668SLeonid Yegoshin unsigned long orig31;
62334c2f668SLeonid Yegoshin u16 __user *pc16;
62434c2f668SLeonid Yegoshin u16 halfword;
62534c2f668SLeonid Yegoshin unsigned int word;
62634c2f668SLeonid Yegoshin unsigned long origpc, contpc;
62734c2f668SLeonid Yegoshin union mips_instruction insn;
62834c2f668SLeonid Yegoshin struct mm_decoded_insn mminsn;
62945deb5faSThomas Bogendoerfer bool user = user_mode(regs);
63034c2f668SLeonid Yegoshin
63134c2f668SLeonid Yegoshin origpc = regs->cp0_epc;
63234c2f668SLeonid Yegoshin orig31 = regs->regs[31];
63334c2f668SLeonid Yegoshin
63434c2f668SLeonid Yegoshin mminsn.micro_mips_mode = 1;
63534c2f668SLeonid Yegoshin
63634c2f668SLeonid Yegoshin /*
63734c2f668SLeonid Yegoshin * This load never faults.
63834c2f668SLeonid Yegoshin */
63934c2f668SLeonid Yegoshin pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
64034c2f668SLeonid Yegoshin __get_user(halfword, pc16);
64134c2f668SLeonid Yegoshin pc16++;
64234c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 2;
64334c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16);
64434c2f668SLeonid Yegoshin mminsn.pc_inc = 2;
64534c2f668SLeonid Yegoshin
64634c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) {
64734c2f668SLeonid Yegoshin __get_user(halfword, pc16);
64834c2f668SLeonid Yegoshin pc16++;
64934c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 4;
65034c2f668SLeonid Yegoshin mminsn.pc_inc = 4;
65134c2f668SLeonid Yegoshin word |= halfword;
65234c2f668SLeonid Yegoshin }
65334c2f668SLeonid Yegoshin mminsn.insn = word;
65434c2f668SLeonid Yegoshin
65534c2f668SLeonid Yegoshin if (get_user(halfword, pc16))
65634c2f668SLeonid Yegoshin goto fault;
65734c2f668SLeonid Yegoshin mminsn.next_pc_inc = 2;
65834c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16);
65934c2f668SLeonid Yegoshin
66034c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) {
66134c2f668SLeonid Yegoshin pc16++;
66234c2f668SLeonid Yegoshin if (get_user(halfword, pc16))
66334c2f668SLeonid Yegoshin goto fault;
66434c2f668SLeonid Yegoshin mminsn.next_pc_inc = 4;
66534c2f668SLeonid Yegoshin word |= halfword;
66634c2f668SLeonid Yegoshin }
66734c2f668SLeonid Yegoshin mminsn.next_insn = word;
66834c2f668SLeonid Yegoshin
66934c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.insn);
67034c2f668SLeonid Yegoshin if (mm_isBranchInstr(regs, mminsn, &contpc))
67134c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.next_insn);
67234c2f668SLeonid Yegoshin
67334c2f668SLeonid Yegoshin /* Parse instruction to find what to do */
67434c2f668SLeonid Yegoshin
67534c2f668SLeonid Yegoshin switch (insn.mm_i_format.opcode) {
67634c2f668SLeonid Yegoshin
67734c2f668SLeonid Yegoshin case mm_pool32a_op:
67834c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) {
67934c2f668SLeonid Yegoshin case mm_lwxs_op:
68034c2f668SLeonid Yegoshin reg = insn.mm_x_format.rd;
68134c2f668SLeonid Yegoshin goto loadW;
68234c2f668SLeonid Yegoshin }
68334c2f668SLeonid Yegoshin
68434c2f668SLeonid Yegoshin goto sigbus;
68534c2f668SLeonid Yegoshin
68634c2f668SLeonid Yegoshin case mm_pool32b_op:
68734c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) {
68834c2f668SLeonid Yegoshin case mm_lwp_func:
68934c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
69034c2f668SLeonid Yegoshin if (reg == 31)
69134c2f668SLeonid Yegoshin goto sigbus;
69234c2f668SLeonid Yegoshin
69345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
69434c2f668SLeonid Yegoshin goto sigbus;
69534c2f668SLeonid Yegoshin
69634c2f668SLeonid Yegoshin LoadW(addr, value, res);
69734c2f668SLeonid Yegoshin if (res)
69834c2f668SLeonid Yegoshin goto fault;
69934c2f668SLeonid Yegoshin regs->regs[reg] = value;
70034c2f668SLeonid Yegoshin addr += 4;
70134c2f668SLeonid Yegoshin LoadW(addr, value, res);
70234c2f668SLeonid Yegoshin if (res)
70334c2f668SLeonid Yegoshin goto fault;
70434c2f668SLeonid Yegoshin regs->regs[reg + 1] = value;
70534c2f668SLeonid Yegoshin goto success;
70634c2f668SLeonid Yegoshin
70734c2f668SLeonid Yegoshin case mm_swp_func:
70834c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
70934c2f668SLeonid Yegoshin if (reg == 31)
71034c2f668SLeonid Yegoshin goto sigbus;
71134c2f668SLeonid Yegoshin
71245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
71334c2f668SLeonid Yegoshin goto sigbus;
71434c2f668SLeonid Yegoshin
71534c2f668SLeonid Yegoshin value = regs->regs[reg];
71634c2f668SLeonid Yegoshin StoreW(addr, value, res);
71734c2f668SLeonid Yegoshin if (res)
71834c2f668SLeonid Yegoshin goto fault;
71934c2f668SLeonid Yegoshin addr += 4;
72034c2f668SLeonid Yegoshin value = regs->regs[reg + 1];
72134c2f668SLeonid Yegoshin StoreW(addr, value, res);
72234c2f668SLeonid Yegoshin if (res)
72334c2f668SLeonid Yegoshin goto fault;
72434c2f668SLeonid Yegoshin goto success;
72534c2f668SLeonid Yegoshin
72634c2f668SLeonid Yegoshin case mm_ldp_func:
72734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
72834c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
72934c2f668SLeonid Yegoshin if (reg == 31)
73034c2f668SLeonid Yegoshin goto sigbus;
73134c2f668SLeonid Yegoshin
73245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 16))
73334c2f668SLeonid Yegoshin goto sigbus;
73434c2f668SLeonid Yegoshin
73534c2f668SLeonid Yegoshin LoadDW(addr, value, res);
73634c2f668SLeonid Yegoshin if (res)
73734c2f668SLeonid Yegoshin goto fault;
73834c2f668SLeonid Yegoshin regs->regs[reg] = value;
73934c2f668SLeonid Yegoshin addr += 8;
74034c2f668SLeonid Yegoshin LoadDW(addr, value, res);
74134c2f668SLeonid Yegoshin if (res)
74234c2f668SLeonid Yegoshin goto fault;
74334c2f668SLeonid Yegoshin regs->regs[reg + 1] = value;
74434c2f668SLeonid Yegoshin goto success;
74534c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
74634c2f668SLeonid Yegoshin
74734c2f668SLeonid Yegoshin goto sigill;
74834c2f668SLeonid Yegoshin
74934c2f668SLeonid Yegoshin case mm_sdp_func:
75034c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
75134c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
75234c2f668SLeonid Yegoshin if (reg == 31)
75334c2f668SLeonid Yegoshin goto sigbus;
75434c2f668SLeonid Yegoshin
75545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 16))
75634c2f668SLeonid Yegoshin goto sigbus;
75734c2f668SLeonid Yegoshin
75834c2f668SLeonid Yegoshin value = regs->regs[reg];
75934c2f668SLeonid Yegoshin StoreDW(addr, value, res);
76034c2f668SLeonid Yegoshin if (res)
76134c2f668SLeonid Yegoshin goto fault;
76234c2f668SLeonid Yegoshin addr += 8;
76334c2f668SLeonid Yegoshin value = regs->regs[reg + 1];
76434c2f668SLeonid Yegoshin StoreDW(addr, value, res);
76534c2f668SLeonid Yegoshin if (res)
76634c2f668SLeonid Yegoshin goto fault;
76734c2f668SLeonid Yegoshin goto success;
76834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
76934c2f668SLeonid Yegoshin
77034c2f668SLeonid Yegoshin goto sigill;
77134c2f668SLeonid Yegoshin
77234c2f668SLeonid Yegoshin case mm_lwm32_func:
77334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
77434c2f668SLeonid Yegoshin rvar = reg & 0xf;
77534c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
77634c2f668SLeonid Yegoshin goto sigill;
77734c2f668SLeonid Yegoshin if (reg & 0x10) {
77845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * (rvar + 1)))
77934c2f668SLeonid Yegoshin goto sigbus;
78034c2f668SLeonid Yegoshin } else {
78145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
78234c2f668SLeonid Yegoshin goto sigbus;
78334c2f668SLeonid Yegoshin }
78434c2f668SLeonid Yegoshin if (rvar == 9)
78534c2f668SLeonid Yegoshin rvar = 8;
78634c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
78734c2f668SLeonid Yegoshin LoadW(addr, value, res);
78834c2f668SLeonid Yegoshin if (res)
78934c2f668SLeonid Yegoshin goto fault;
79034c2f668SLeonid Yegoshin addr += 4;
79134c2f668SLeonid Yegoshin regs->regs[i] = value;
79234c2f668SLeonid Yegoshin }
79334c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
79434c2f668SLeonid Yegoshin LoadW(addr, value, res);
79534c2f668SLeonid Yegoshin if (res)
79634c2f668SLeonid Yegoshin goto fault;
79734c2f668SLeonid Yegoshin addr += 4;
79834c2f668SLeonid Yegoshin regs->regs[30] = value;
79934c2f668SLeonid Yegoshin }
80034c2f668SLeonid Yegoshin if (reg & 0x10) {
80134c2f668SLeonid Yegoshin LoadW(addr, value, res);
80234c2f668SLeonid Yegoshin if (res)
80334c2f668SLeonid Yegoshin goto fault;
80434c2f668SLeonid Yegoshin regs->regs[31] = value;
80534c2f668SLeonid Yegoshin }
80634c2f668SLeonid Yegoshin goto success;
80734c2f668SLeonid Yegoshin
80834c2f668SLeonid Yegoshin case mm_swm32_func:
80934c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
81034c2f668SLeonid Yegoshin rvar = reg & 0xf;
81134c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
81234c2f668SLeonid Yegoshin goto sigill;
81334c2f668SLeonid Yegoshin if (reg & 0x10) {
81445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * (rvar + 1)))
81534c2f668SLeonid Yegoshin goto sigbus;
81634c2f668SLeonid Yegoshin } else {
81745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
81834c2f668SLeonid Yegoshin goto sigbus;
81934c2f668SLeonid Yegoshin }
82034c2f668SLeonid Yegoshin if (rvar == 9)
82134c2f668SLeonid Yegoshin rvar = 8;
82234c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
82334c2f668SLeonid Yegoshin value = regs->regs[i];
82434c2f668SLeonid Yegoshin StoreW(addr, value, res);
82534c2f668SLeonid Yegoshin if (res)
82634c2f668SLeonid Yegoshin goto fault;
82734c2f668SLeonid Yegoshin addr += 4;
82834c2f668SLeonid Yegoshin }
82934c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
83034c2f668SLeonid Yegoshin value = regs->regs[30];
83134c2f668SLeonid Yegoshin StoreW(addr, value, res);
83234c2f668SLeonid Yegoshin if (res)
83334c2f668SLeonid Yegoshin goto fault;
83434c2f668SLeonid Yegoshin addr += 4;
83534c2f668SLeonid Yegoshin }
83634c2f668SLeonid Yegoshin if (reg & 0x10) {
83734c2f668SLeonid Yegoshin value = regs->regs[31];
83834c2f668SLeonid Yegoshin StoreW(addr, value, res);
83934c2f668SLeonid Yegoshin if (res)
84034c2f668SLeonid Yegoshin goto fault;
84134c2f668SLeonid Yegoshin }
84234c2f668SLeonid Yegoshin goto success;
84334c2f668SLeonid Yegoshin
84434c2f668SLeonid Yegoshin case mm_ldm_func:
84534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
84634c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
84734c2f668SLeonid Yegoshin rvar = reg & 0xf;
84834c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
84934c2f668SLeonid Yegoshin goto sigill;
85034c2f668SLeonid Yegoshin if (reg & 0x10) {
85145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * (rvar + 1)))
85234c2f668SLeonid Yegoshin goto sigbus;
85334c2f668SLeonid Yegoshin } else {
85445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * rvar))
85534c2f668SLeonid Yegoshin goto sigbus;
85634c2f668SLeonid Yegoshin }
85734c2f668SLeonid Yegoshin if (rvar == 9)
85834c2f668SLeonid Yegoshin rvar = 8;
85934c2f668SLeonid Yegoshin
86034c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
86134c2f668SLeonid Yegoshin LoadDW(addr, value, res);
86234c2f668SLeonid Yegoshin if (res)
86334c2f668SLeonid Yegoshin goto fault;
86434c2f668SLeonid Yegoshin addr += 4;
86534c2f668SLeonid Yegoshin regs->regs[i] = value;
86634c2f668SLeonid Yegoshin }
86734c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
86834c2f668SLeonid Yegoshin LoadDW(addr, value, res);
86934c2f668SLeonid Yegoshin if (res)
87034c2f668SLeonid Yegoshin goto fault;
87134c2f668SLeonid Yegoshin addr += 8;
87234c2f668SLeonid Yegoshin regs->regs[30] = value;
87334c2f668SLeonid Yegoshin }
87434c2f668SLeonid Yegoshin if (reg & 0x10) {
87534c2f668SLeonid Yegoshin LoadDW(addr, value, res);
87634c2f668SLeonid Yegoshin if (res)
87734c2f668SLeonid Yegoshin goto fault;
87834c2f668SLeonid Yegoshin regs->regs[31] = value;
87934c2f668SLeonid Yegoshin }
88034c2f668SLeonid Yegoshin goto success;
88134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
88234c2f668SLeonid Yegoshin
88334c2f668SLeonid Yegoshin goto sigill;
88434c2f668SLeonid Yegoshin
88534c2f668SLeonid Yegoshin case mm_sdm_func:
88634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
88734c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
88834c2f668SLeonid Yegoshin rvar = reg & 0xf;
88934c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
89034c2f668SLeonid Yegoshin goto sigill;
89134c2f668SLeonid Yegoshin if (reg & 0x10) {
89245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * (rvar + 1)))
89334c2f668SLeonid Yegoshin goto sigbus;
89434c2f668SLeonid Yegoshin } else {
89545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * rvar))
89634c2f668SLeonid Yegoshin goto sigbus;
89734c2f668SLeonid Yegoshin }
89834c2f668SLeonid Yegoshin if (rvar == 9)
89934c2f668SLeonid Yegoshin rvar = 8;
90034c2f668SLeonid Yegoshin
90134c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
90234c2f668SLeonid Yegoshin value = regs->regs[i];
90334c2f668SLeonid Yegoshin StoreDW(addr, value, res);
90434c2f668SLeonid Yegoshin if (res)
90534c2f668SLeonid Yegoshin goto fault;
90634c2f668SLeonid Yegoshin addr += 8;
90734c2f668SLeonid Yegoshin }
90834c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
90934c2f668SLeonid Yegoshin value = regs->regs[30];
91034c2f668SLeonid Yegoshin StoreDW(addr, value, res);
91134c2f668SLeonid Yegoshin if (res)
91234c2f668SLeonid Yegoshin goto fault;
91334c2f668SLeonid Yegoshin addr += 8;
91434c2f668SLeonid Yegoshin }
91534c2f668SLeonid Yegoshin if (reg & 0x10) {
91634c2f668SLeonid Yegoshin value = regs->regs[31];
91734c2f668SLeonid Yegoshin StoreDW(addr, value, res);
91834c2f668SLeonid Yegoshin if (res)
91934c2f668SLeonid Yegoshin goto fault;
92034c2f668SLeonid Yegoshin }
92134c2f668SLeonid Yegoshin goto success;
92234c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
92334c2f668SLeonid Yegoshin
92434c2f668SLeonid Yegoshin goto sigill;
92534c2f668SLeonid Yegoshin
92634c2f668SLeonid Yegoshin /* LWC2, SWC2, LDC2, SDC2 are not serviced */
92734c2f668SLeonid Yegoshin }
92834c2f668SLeonid Yegoshin
92934c2f668SLeonid Yegoshin goto sigbus;
93034c2f668SLeonid Yegoshin
93134c2f668SLeonid Yegoshin case mm_pool32c_op:
93234c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) {
93334c2f668SLeonid Yegoshin case mm_lwu_func:
93434c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
93534c2f668SLeonid Yegoshin goto loadWU;
93634c2f668SLeonid Yegoshin }
93734c2f668SLeonid Yegoshin
93834c2f668SLeonid Yegoshin /* LL,SC,LLD,SCD are not serviced */
93934c2f668SLeonid Yegoshin goto sigbus;
94034c2f668SLeonid Yegoshin
94185164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
94234c2f668SLeonid Yegoshin case mm_pool32f_op:
94334c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) {
94434c2f668SLeonid Yegoshin case mm_lwxc1_func:
94534c2f668SLeonid Yegoshin case mm_swxc1_func:
94634c2f668SLeonid Yegoshin case mm_ldxc1_func:
94734c2f668SLeonid Yegoshin case mm_sdxc1_func:
94834c2f668SLeonid Yegoshin goto fpu_emul;
94934c2f668SLeonid Yegoshin }
95034c2f668SLeonid Yegoshin
95134c2f668SLeonid Yegoshin goto sigbus;
95234c2f668SLeonid Yegoshin
95334c2f668SLeonid Yegoshin case mm_ldc132_op:
95434c2f668SLeonid Yegoshin case mm_sdc132_op:
95534c2f668SLeonid Yegoshin case mm_lwc132_op:
95685164fd8SPaul Burton case mm_swc132_op: {
95785164fd8SPaul Burton void __user *fault_addr = NULL;
95885164fd8SPaul Burton
95934c2f668SLeonid Yegoshin fpu_emul:
96034c2f668SLeonid Yegoshin /* roll back jump/branch */
96134c2f668SLeonid Yegoshin regs->cp0_epc = origpc;
96234c2f668SLeonid Yegoshin regs->regs[31] = orig31;
96334c2f668SLeonid Yegoshin
96434c2f668SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs);
96534c2f668SLeonid Yegoshin BUG_ON(!used_math());
96634c2f668SLeonid Yegoshin BUG_ON(!is_fpu_owner());
96734c2f668SLeonid Yegoshin
96834c2f668SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
96934c2f668SLeonid Yegoshin &fault_addr);
97034c2f668SLeonid Yegoshin own_fpu(1); /* restore FPU state */
97134c2f668SLeonid Yegoshin
97234c2f668SLeonid Yegoshin /* If something went wrong, signal */
973304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0);
97434c2f668SLeonid Yegoshin
97534c2f668SLeonid Yegoshin if (res == 0)
97634c2f668SLeonid Yegoshin goto success;
97734c2f668SLeonid Yegoshin return;
97885164fd8SPaul Burton }
97985164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
98034c2f668SLeonid Yegoshin
98134c2f668SLeonid Yegoshin case mm_lh32_op:
98234c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
98334c2f668SLeonid Yegoshin goto loadHW;
98434c2f668SLeonid Yegoshin
98534c2f668SLeonid Yegoshin case mm_lhu32_op:
98634c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
98734c2f668SLeonid Yegoshin goto loadHWU;
98834c2f668SLeonid Yegoshin
98934c2f668SLeonid Yegoshin case mm_lw32_op:
99034c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
99134c2f668SLeonid Yegoshin goto loadW;
99234c2f668SLeonid Yegoshin
99334c2f668SLeonid Yegoshin case mm_sh32_op:
99434c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
99534c2f668SLeonid Yegoshin goto storeHW;
99634c2f668SLeonid Yegoshin
99734c2f668SLeonid Yegoshin case mm_sw32_op:
99834c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
99934c2f668SLeonid Yegoshin goto storeW;
100034c2f668SLeonid Yegoshin
100134c2f668SLeonid Yegoshin case mm_ld32_op:
100234c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
100334c2f668SLeonid Yegoshin goto loadDW;
100434c2f668SLeonid Yegoshin
100534c2f668SLeonid Yegoshin case mm_sd32_op:
100634c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
100734c2f668SLeonid Yegoshin goto storeDW;
100834c2f668SLeonid Yegoshin
100934c2f668SLeonid Yegoshin case mm_pool16c_op:
101034c2f668SLeonid Yegoshin switch (insn.mm16_m_format.func) {
101134c2f668SLeonid Yegoshin case mm_lwm16_op:
101234c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist;
101334c2f668SLeonid Yegoshin rvar = reg + 1;
101445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
101534c2f668SLeonid Yegoshin goto sigbus;
101634c2f668SLeonid Yegoshin
101734c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
101834c2f668SLeonid Yegoshin LoadW(addr, value, res);
101934c2f668SLeonid Yegoshin if (res)
102034c2f668SLeonid Yegoshin goto fault;
102134c2f668SLeonid Yegoshin addr += 4;
102234c2f668SLeonid Yegoshin regs->regs[i] = value;
102334c2f668SLeonid Yegoshin }
102434c2f668SLeonid Yegoshin LoadW(addr, value, res);
102534c2f668SLeonid Yegoshin if (res)
102634c2f668SLeonid Yegoshin goto fault;
102734c2f668SLeonid Yegoshin regs->regs[31] = value;
102834c2f668SLeonid Yegoshin
102934c2f668SLeonid Yegoshin goto success;
103034c2f668SLeonid Yegoshin
103134c2f668SLeonid Yegoshin case mm_swm16_op:
103234c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist;
103334c2f668SLeonid Yegoshin rvar = reg + 1;
103445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
103534c2f668SLeonid Yegoshin goto sigbus;
103634c2f668SLeonid Yegoshin
103734c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
103834c2f668SLeonid Yegoshin value = regs->regs[i];
103934c2f668SLeonid Yegoshin StoreW(addr, value, res);
104034c2f668SLeonid Yegoshin if (res)
104134c2f668SLeonid Yegoshin goto fault;
104234c2f668SLeonid Yegoshin addr += 4;
104334c2f668SLeonid Yegoshin }
104434c2f668SLeonid Yegoshin value = regs->regs[31];
104534c2f668SLeonid Yegoshin StoreW(addr, value, res);
104634c2f668SLeonid Yegoshin if (res)
104734c2f668SLeonid Yegoshin goto fault;
104834c2f668SLeonid Yegoshin
104934c2f668SLeonid Yegoshin goto success;
105034c2f668SLeonid Yegoshin
105134c2f668SLeonid Yegoshin }
105234c2f668SLeonid Yegoshin
105334c2f668SLeonid Yegoshin goto sigbus;
105434c2f668SLeonid Yegoshin
105534c2f668SLeonid Yegoshin case mm_lhu16_op:
105634c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt];
105734c2f668SLeonid Yegoshin goto loadHWU;
105834c2f668SLeonid Yegoshin
105934c2f668SLeonid Yegoshin case mm_lw16_op:
106034c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt];
106134c2f668SLeonid Yegoshin goto loadW;
106234c2f668SLeonid Yegoshin
106334c2f668SLeonid Yegoshin case mm_sh16_op:
106434c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt];
106534c2f668SLeonid Yegoshin goto storeHW;
106634c2f668SLeonid Yegoshin
106734c2f668SLeonid Yegoshin case mm_sw16_op:
106834c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt];
106934c2f668SLeonid Yegoshin goto storeW;
107034c2f668SLeonid Yegoshin
107134c2f668SLeonid Yegoshin case mm_lwsp16_op:
107234c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt;
107334c2f668SLeonid Yegoshin goto loadW;
107434c2f668SLeonid Yegoshin
107534c2f668SLeonid Yegoshin case mm_swsp16_op:
107634c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt;
107734c2f668SLeonid Yegoshin goto storeW;
107834c2f668SLeonid Yegoshin
107934c2f668SLeonid Yegoshin case mm_lwgp16_op:
108034c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_r3_format.rt];
108134c2f668SLeonid Yegoshin goto loadW;
108234c2f668SLeonid Yegoshin
108334c2f668SLeonid Yegoshin default:
108434c2f668SLeonid Yegoshin goto sigill;
108534c2f668SLeonid Yegoshin }
108634c2f668SLeonid Yegoshin
108734c2f668SLeonid Yegoshin loadHW:
108845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
108934c2f668SLeonid Yegoshin goto sigbus;
109034c2f668SLeonid Yegoshin
109134c2f668SLeonid Yegoshin LoadHW(addr, value, res);
109234c2f668SLeonid Yegoshin if (res)
109334c2f668SLeonid Yegoshin goto fault;
109434c2f668SLeonid Yegoshin regs->regs[reg] = value;
109534c2f668SLeonid Yegoshin goto success;
109634c2f668SLeonid Yegoshin
109734c2f668SLeonid Yegoshin loadHWU:
109845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
109934c2f668SLeonid Yegoshin goto sigbus;
110034c2f668SLeonid Yegoshin
110134c2f668SLeonid Yegoshin LoadHWU(addr, value, res);
110234c2f668SLeonid Yegoshin if (res)
110334c2f668SLeonid Yegoshin goto fault;
110434c2f668SLeonid Yegoshin regs->regs[reg] = value;
110534c2f668SLeonid Yegoshin goto success;
110634c2f668SLeonid Yegoshin
110734c2f668SLeonid Yegoshin loadW:
110845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
110934c2f668SLeonid Yegoshin goto sigbus;
111034c2f668SLeonid Yegoshin
111134c2f668SLeonid Yegoshin LoadW(addr, value, res);
111234c2f668SLeonid Yegoshin if (res)
111334c2f668SLeonid Yegoshin goto fault;
111434c2f668SLeonid Yegoshin regs->regs[reg] = value;
111534c2f668SLeonid Yegoshin goto success;
111634c2f668SLeonid Yegoshin
111734c2f668SLeonid Yegoshin loadWU:
111834c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
111934c2f668SLeonid Yegoshin /*
112034c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But
112134c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency
112234c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr
112334c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit
112434c2f668SLeonid Yegoshin * instructions on 32-bit kernels.
112534c2f668SLeonid Yegoshin */
112645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
112734c2f668SLeonid Yegoshin goto sigbus;
112834c2f668SLeonid Yegoshin
112934c2f668SLeonid Yegoshin LoadWU(addr, value, res);
113034c2f668SLeonid Yegoshin if (res)
113134c2f668SLeonid Yegoshin goto fault;
113234c2f668SLeonid Yegoshin regs->regs[reg] = value;
113334c2f668SLeonid Yegoshin goto success;
113434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
113534c2f668SLeonid Yegoshin
113634c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */
113734c2f668SLeonid Yegoshin goto sigill;
113834c2f668SLeonid Yegoshin
113934c2f668SLeonid Yegoshin loadDW:
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 LoadDW(addr, value, res);
115234c2f668SLeonid Yegoshin if (res)
115334c2f668SLeonid Yegoshin goto fault;
115434c2f668SLeonid Yegoshin regs->regs[reg] = value;
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 storeHW:
116245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
116334c2f668SLeonid Yegoshin goto sigbus;
116434c2f668SLeonid Yegoshin
116534c2f668SLeonid Yegoshin value = regs->regs[reg];
116634c2f668SLeonid Yegoshin StoreHW(addr, value, res);
116734c2f668SLeonid Yegoshin if (res)
116834c2f668SLeonid Yegoshin goto fault;
116934c2f668SLeonid Yegoshin goto success;
117034c2f668SLeonid Yegoshin
117134c2f668SLeonid Yegoshin storeW:
117245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
117334c2f668SLeonid Yegoshin goto sigbus;
117434c2f668SLeonid Yegoshin
117534c2f668SLeonid Yegoshin value = regs->regs[reg];
117634c2f668SLeonid Yegoshin StoreW(addr, value, res);
117734c2f668SLeonid Yegoshin if (res)
117834c2f668SLeonid Yegoshin goto fault;
117934c2f668SLeonid Yegoshin goto success;
118034c2f668SLeonid Yegoshin
118134c2f668SLeonid Yegoshin storeDW:
118234c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
118334c2f668SLeonid Yegoshin /*
118434c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But
118534c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency
118634c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr
118734c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit
118834c2f668SLeonid Yegoshin * instructions on 32-bit kernels.
118934c2f668SLeonid Yegoshin */
119045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
119134c2f668SLeonid Yegoshin goto sigbus;
119234c2f668SLeonid Yegoshin
119334c2f668SLeonid Yegoshin value = regs->regs[reg];
119434c2f668SLeonid Yegoshin StoreDW(addr, value, res);
119534c2f668SLeonid Yegoshin if (res)
119634c2f668SLeonid Yegoshin goto fault;
119734c2f668SLeonid Yegoshin goto success;
119834c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
119934c2f668SLeonid Yegoshin
120034c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */
120134c2f668SLeonid Yegoshin goto sigill;
120234c2f668SLeonid Yegoshin
120334c2f668SLeonid Yegoshin success:
120434c2f668SLeonid Yegoshin regs->cp0_epc = contpc; /* advance or branch */
120534c2f668SLeonid Yegoshin
120634c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
120734c2f668SLeonid Yegoshin unaligned_instructions++;
120834c2f668SLeonid Yegoshin #endif
120934c2f668SLeonid Yegoshin return;
121034c2f668SLeonid Yegoshin
121134c2f668SLeonid Yegoshin fault:
121234c2f668SLeonid Yegoshin /* roll back jump/branch */
121334c2f668SLeonid Yegoshin regs->cp0_epc = origpc;
121434c2f668SLeonid Yegoshin regs->regs[31] = orig31;
121534c2f668SLeonid Yegoshin /* Did we have an exception handler installed? */
121634c2f668SLeonid Yegoshin if (fixup_exception(regs))
121734c2f668SLeonid Yegoshin return;
121834c2f668SLeonid Yegoshin
121934c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs);
12203cf5d076SEric W. Biederman force_sig(SIGSEGV);
122134c2f668SLeonid Yegoshin
122234c2f668SLeonid Yegoshin return;
122334c2f668SLeonid Yegoshin
122434c2f668SLeonid Yegoshin sigbus:
122534c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs);
12263cf5d076SEric W. Biederman force_sig(SIGBUS);
122734c2f668SLeonid Yegoshin
122834c2f668SLeonid Yegoshin return;
122934c2f668SLeonid Yegoshin
123034c2f668SLeonid Yegoshin sigill:
123134c2f668SLeonid Yegoshin die_if_kernel
123234c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs);
12333cf5d076SEric W. Biederman force_sig(SIGILL);
12341da177e4SLinus Torvalds }
12351da177e4SLinus Torvalds
emulate_load_store_MIPS16e(struct pt_regs * regs,void __user * addr)1236451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1237451b001bSSteven J. Hill {
1238451b001bSSteven J. Hill unsigned long value;
1239451b001bSSteven J. Hill unsigned int res;
1240451b001bSSteven J. Hill int reg;
1241451b001bSSteven J. Hill unsigned long orig31;
1242451b001bSSteven J. Hill u16 __user *pc16;
1243451b001bSSteven J. Hill unsigned long origpc;
1244451b001bSSteven J. Hill union mips16e_instruction mips16inst, oldinst;
1245f3235d32SMaciej W. Rozycki unsigned int opcode;
1246f3235d32SMaciej W. Rozycki int extended = 0;
124745deb5faSThomas Bogendoerfer bool user = user_mode(regs);
1248451b001bSSteven J. Hill
1249451b001bSSteven J. Hill origpc = regs->cp0_epc;
1250451b001bSSteven J. Hill orig31 = regs->regs[31];
1251451b001bSSteven J. Hill pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1252451b001bSSteven J. Hill /*
1253451b001bSSteven J. Hill * This load never faults.
1254451b001bSSteven J. Hill */
1255451b001bSSteven J. Hill __get_user(mips16inst.full, pc16);
1256451b001bSSteven J. Hill oldinst = mips16inst;
1257451b001bSSteven J. Hill
1258451b001bSSteven J. Hill /* skip EXTEND instruction */
1259451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1260f3235d32SMaciej W. Rozycki extended = 1;
1261451b001bSSteven J. Hill pc16++;
1262451b001bSSteven J. Hill __get_user(mips16inst.full, pc16);
1263451b001bSSteven J. Hill } else if (delay_slot(regs)) {
1264451b001bSSteven J. Hill /* skip jump instructions */
1265451b001bSSteven J. Hill /* JAL/JALX are 32 bits but have OPCODE in first short int */
1266451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_jal_op)
1267451b001bSSteven J. Hill pc16++;
1268451b001bSSteven J. Hill pc16++;
1269451b001bSSteven J. Hill if (get_user(mips16inst.full, pc16))
1270451b001bSSteven J. Hill goto sigbus;
1271451b001bSSteven J. Hill }
1272451b001bSSteven J. Hill
1273f3235d32SMaciej W. Rozycki opcode = mips16inst.ri.opcode;
1274f3235d32SMaciej W. Rozycki switch (opcode) {
1275451b001bSSteven J. Hill case MIPS16e_i64_op: /* I64 or RI64 instruction */
1276451b001bSSteven J. Hill switch (mips16inst.i64.func) { /* I64/RI64 func field check */
1277451b001bSSteven J. Hill case MIPS16e_ldpc_func:
1278451b001bSSteven J. Hill case MIPS16e_ldsp_func:
1279451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry];
1280451b001bSSteven J. Hill goto loadDW;
1281451b001bSSteven J. Hill
1282451b001bSSteven J. Hill case MIPS16e_sdsp_func:
1283451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry];
1284451b001bSSteven J. Hill goto writeDW;
1285451b001bSSteven J. Hill
1286451b001bSSteven J. Hill case MIPS16e_sdrasp_func:
1287451b001bSSteven J. Hill reg = 29; /* GPRSP */
1288451b001bSSteven J. Hill goto writeDW;
1289451b001bSSteven J. Hill }
1290451b001bSSteven J. Hill
1291451b001bSSteven J. Hill goto sigbus;
1292451b001bSSteven J. Hill
1293451b001bSSteven J. Hill case MIPS16e_swsp_op:
1294f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx];
1295f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2)
1296f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) {
1297f3235d32SMaciej W. Rozycki case 0: /* SWSP */
1298f3235d32SMaciej W. Rozycki case 1: /* SWGP */
1299f3235d32SMaciej W. Rozycki break;
1300f3235d32SMaciej W. Rozycki case 2: /* SHGP */
1301f3235d32SMaciej W. Rozycki opcode = MIPS16e_sh_op;
1302f3235d32SMaciej W. Rozycki break;
1303f3235d32SMaciej W. Rozycki default:
1304f3235d32SMaciej W. Rozycki goto sigbus;
1305f3235d32SMaciej W. Rozycki }
1306f3235d32SMaciej W. Rozycki break;
1307f3235d32SMaciej W. Rozycki
1308451b001bSSteven J. Hill case MIPS16e_lwpc_op:
1309f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx];
1310f3235d32SMaciej W. Rozycki break;
1311f3235d32SMaciej W. Rozycki
1312451b001bSSteven J. Hill case MIPS16e_lwsp_op:
1313451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri.rx];
1314f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2)
1315f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) {
1316f3235d32SMaciej W. Rozycki case 0: /* LWSP */
1317f3235d32SMaciej W. Rozycki case 1: /* LWGP */
1318f3235d32SMaciej W. Rozycki break;
1319f3235d32SMaciej W. Rozycki case 2: /* LHGP */
1320f3235d32SMaciej W. Rozycki opcode = MIPS16e_lh_op;
1321f3235d32SMaciej W. Rozycki break;
1322f3235d32SMaciej W. Rozycki case 4: /* LHUGP */
1323f3235d32SMaciej W. Rozycki opcode = MIPS16e_lhu_op;
1324f3235d32SMaciej W. Rozycki break;
1325f3235d32SMaciej W. Rozycki default:
1326f3235d32SMaciej W. Rozycki goto sigbus;
1327f3235d32SMaciej W. Rozycki }
1328451b001bSSteven J. Hill break;
1329451b001bSSteven J. Hill
1330451b001bSSteven J. Hill case MIPS16e_i8_op:
1331451b001bSSteven J. Hill if (mips16inst.i8.func != MIPS16e_swrasp_func)
1332451b001bSSteven J. Hill goto sigbus;
1333451b001bSSteven J. Hill reg = 29; /* GPRSP */
1334451b001bSSteven J. Hill break;
1335451b001bSSteven J. Hill
1336451b001bSSteven J. Hill default:
1337451b001bSSteven J. Hill reg = reg16to32[mips16inst.rri.ry];
1338451b001bSSteven J. Hill break;
1339451b001bSSteven J. Hill }
1340451b001bSSteven J. Hill
1341f3235d32SMaciej W. Rozycki switch (opcode) {
1342451b001bSSteven J. Hill
1343451b001bSSteven J. Hill case MIPS16e_lb_op:
1344451b001bSSteven J. Hill case MIPS16e_lbu_op:
1345451b001bSSteven J. Hill case MIPS16e_sb_op:
1346451b001bSSteven J. Hill goto sigbus;
1347451b001bSSteven J. Hill
1348451b001bSSteven J. Hill case MIPS16e_lh_op:
134945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
1350451b001bSSteven J. Hill goto sigbus;
1351451b001bSSteven J. Hill
1352451b001bSSteven J. Hill LoadHW(addr, value, res);
1353451b001bSSteven J. Hill if (res)
1354451b001bSSteven J. Hill goto fault;
1355451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1356451b001bSSteven J. Hill regs->regs[reg] = value;
1357451b001bSSteven J. Hill break;
1358451b001bSSteven J. Hill
1359451b001bSSteven J. Hill case MIPS16e_lhu_op:
136045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
1361451b001bSSteven J. Hill goto sigbus;
1362451b001bSSteven J. Hill
1363451b001bSSteven J. Hill LoadHWU(addr, value, res);
1364451b001bSSteven J. Hill if (res)
1365451b001bSSteven J. Hill goto fault;
1366451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1367451b001bSSteven J. Hill regs->regs[reg] = value;
1368451b001bSSteven J. Hill break;
1369451b001bSSteven J. Hill
1370451b001bSSteven J. Hill case MIPS16e_lw_op:
1371451b001bSSteven J. Hill case MIPS16e_lwpc_op:
1372451b001bSSteven J. Hill case MIPS16e_lwsp_op:
137345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
1374451b001bSSteven J. Hill goto sigbus;
1375451b001bSSteven J. Hill
1376451b001bSSteven J. Hill LoadW(addr, value, res);
1377451b001bSSteven J. Hill if (res)
1378451b001bSSteven J. Hill goto fault;
1379451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1380451b001bSSteven J. Hill regs->regs[reg] = value;
1381451b001bSSteven J. Hill break;
1382451b001bSSteven J. Hill
1383451b001bSSteven J. Hill case MIPS16e_lwu_op:
1384451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1385451b001bSSteven J. Hill /*
1386451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But
1387451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency
1388451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr
1389451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit
1390451b001bSSteven J. Hill * instructions on 32-bit kernels.
1391451b001bSSteven J. Hill */
139245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
1393451b001bSSteven J. Hill goto sigbus;
1394451b001bSSteven J. Hill
1395451b001bSSteven J. Hill LoadWU(addr, value, res);
1396451b001bSSteven J. Hill if (res)
1397451b001bSSteven J. Hill goto fault;
1398451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1399451b001bSSteven J. Hill regs->regs[reg] = value;
1400451b001bSSteven J. Hill break;
1401451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1402451b001bSSteven J. Hill
1403451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */
1404451b001bSSteven J. Hill goto sigill;
1405451b001bSSteven J. Hill
1406451b001bSSteven J. Hill case MIPS16e_ld_op:
1407451b001bSSteven J. Hill loadDW:
1408451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1409451b001bSSteven J. Hill /*
1410451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But
1411451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency
1412451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr
1413451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit
1414451b001bSSteven J. Hill * instructions on 32-bit kernels.
1415451b001bSSteven J. Hill */
141645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
1417451b001bSSteven J. Hill goto sigbus;
1418451b001bSSteven J. Hill
1419451b001bSSteven J. Hill LoadDW(addr, value, res);
1420451b001bSSteven J. Hill if (res)
1421451b001bSSteven J. Hill goto fault;
1422451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1423451b001bSSteven J. Hill regs->regs[reg] = value;
1424451b001bSSteven J. Hill break;
1425451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1426451b001bSSteven J. Hill
1427451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */
1428451b001bSSteven J. Hill goto sigill;
1429451b001bSSteven J. Hill
1430451b001bSSteven J. Hill case MIPS16e_sh_op:
143145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
1432451b001bSSteven J. Hill goto sigbus;
1433451b001bSSteven J. Hill
1434451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1435451b001bSSteven J. Hill value = regs->regs[reg];
1436451b001bSSteven J. Hill StoreHW(addr, value, res);
1437451b001bSSteven J. Hill if (res)
1438451b001bSSteven J. Hill goto fault;
1439451b001bSSteven J. Hill break;
1440451b001bSSteven J. Hill
1441451b001bSSteven J. Hill case MIPS16e_sw_op:
1442451b001bSSteven J. Hill case MIPS16e_swsp_op:
1443451b001bSSteven J. Hill case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */
144445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
1445451b001bSSteven J. Hill goto sigbus;
1446451b001bSSteven J. Hill
1447451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1448451b001bSSteven J. Hill value = regs->regs[reg];
1449451b001bSSteven J. Hill StoreW(addr, value, res);
1450451b001bSSteven J. Hill if (res)
1451451b001bSSteven J. Hill goto fault;
1452451b001bSSteven J. Hill break;
1453451b001bSSteven J. Hill
1454451b001bSSteven J. Hill case MIPS16e_sd_op:
1455451b001bSSteven J. Hill writeDW:
1456451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1457451b001bSSteven J. Hill /*
1458451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But
1459451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency
1460451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr
1461451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit
1462451b001bSSteven J. Hill * instructions on 32-bit kernels.
1463451b001bSSteven J. Hill */
146445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
1465451b001bSSteven J. Hill goto sigbus;
1466451b001bSSteven J. Hill
1467451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1468451b001bSSteven J. Hill value = regs->regs[reg];
1469451b001bSSteven J. Hill StoreDW(addr, value, res);
1470451b001bSSteven J. Hill if (res)
1471451b001bSSteven J. Hill goto fault;
1472451b001bSSteven J. Hill break;
1473451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1474451b001bSSteven J. Hill
1475451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */
1476451b001bSSteven J. Hill goto sigill;
1477451b001bSSteven J. Hill
1478451b001bSSteven J. Hill default:
1479451b001bSSteven J. Hill /*
1480451b001bSSteven J. Hill * Pheeee... We encountered an yet unknown instruction or
1481451b001bSSteven J. Hill * cache coherence problem. Die sucker, die ...
1482451b001bSSteven J. Hill */
1483451b001bSSteven J. Hill goto sigill;
1484451b001bSSteven J. Hill }
1485451b001bSSteven J. Hill
1486451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
1487451b001bSSteven J. Hill unaligned_instructions++;
1488451b001bSSteven J. Hill #endif
1489451b001bSSteven J. Hill
1490451b001bSSteven J. Hill return;
1491451b001bSSteven J. Hill
1492451b001bSSteven J. Hill fault:
1493451b001bSSteven J. Hill /* roll back jump/branch */
1494451b001bSSteven J. Hill regs->cp0_epc = origpc;
1495451b001bSSteven J. Hill regs->regs[31] = orig31;
1496451b001bSSteven J. Hill /* Did we have an exception handler installed? */
1497451b001bSSteven J. Hill if (fixup_exception(regs))
1498451b001bSSteven J. Hill return;
1499451b001bSSteven J. Hill
1500451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs);
15013cf5d076SEric W. Biederman force_sig(SIGSEGV);
1502451b001bSSteven J. Hill
1503451b001bSSteven J. Hill return;
1504451b001bSSteven J. Hill
1505451b001bSSteven J. Hill sigbus:
1506451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs);
15073cf5d076SEric W. Biederman force_sig(SIGBUS);
1508451b001bSSteven J. Hill
1509451b001bSSteven J. Hill return;
1510451b001bSSteven J. Hill
1511451b001bSSteven J. Hill sigill:
1512451b001bSSteven J. Hill die_if_kernel
1513451b001bSSteven J. Hill ("Unhandled kernel unaligned access or invalid instruction", regs);
15143cf5d076SEric W. Biederman force_sig(SIGILL);
1515451b001bSSteven J. Hill }
1516fc192e50STony Wu
do_ade(struct pt_regs * regs)15171da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
15181da177e4SLinus Torvalds {
1519c3fc5cd5SRalf Baechle enum ctx_state prev_state;
15207cba4128SThomas Bogendoerfer unsigned int *pc;
15211da177e4SLinus Torvalds
1522c3fc5cd5SRalf Baechle prev_state = exception_enter();
15237f788d2dSDeng-Cheng Zhu perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1524a8b0ca17SPeter Zijlstra 1, regs, regs->cp0_badvaddr);
1525429124d9SThomas Bogendoerfer
1526429124d9SThomas Bogendoerfer #ifdef CONFIG_64BIT
1527429124d9SThomas Bogendoerfer /*
1528429124d9SThomas Bogendoerfer * check, if we are hitting space between CPU implemented maximum
1529429124d9SThomas Bogendoerfer * virtual user address and 64bit maximum virtual user address
1530429124d9SThomas Bogendoerfer * and do exception handling to get EFAULTs for get_user/put_user
1531429124d9SThomas Bogendoerfer */
1532429124d9SThomas Bogendoerfer if ((regs->cp0_badvaddr >= (1UL << cpu_vmbits)) &&
1533429124d9SThomas Bogendoerfer (regs->cp0_badvaddr < XKSSEG)) {
1534429124d9SThomas Bogendoerfer if (fixup_exception(regs)) {
1535429124d9SThomas Bogendoerfer current->thread.cp0_baduaddr = regs->cp0_badvaddr;
1536429124d9SThomas Bogendoerfer return;
1537429124d9SThomas Bogendoerfer }
1538429124d9SThomas Bogendoerfer goto sigbus;
1539429124d9SThomas Bogendoerfer }
1540429124d9SThomas Bogendoerfer #endif
1541429124d9SThomas Bogendoerfer
15421da177e4SLinus Torvalds /*
15431da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction?
15441da177e4SLinus Torvalds */
154534c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == regs->cp0_epc)
15461da177e4SLinus Torvalds goto sigbus;
15471da177e4SLinus Torvalds
1548293c5bd1SRalf Baechle if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
15491da177e4SLinus Torvalds goto sigbus;
15506312e0eeSAtsushi Nemoto if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
15516312e0eeSAtsushi Nemoto goto sigbus;
15521da177e4SLinus Torvalds
15531da177e4SLinus Torvalds /*
15541da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception.
15551da177e4SLinus Torvalds * This is all so but ugly ...
15561da177e4SLinus Torvalds */
155734c2f668SLeonid Yegoshin
155834c2f668SLeonid Yegoshin /*
155934c2f668SLeonid Yegoshin * Are we running in microMIPS mode?
156034c2f668SLeonid Yegoshin */
156134c2f668SLeonid Yegoshin if (get_isa16_mode(regs->cp0_epc)) {
156234c2f668SLeonid Yegoshin /*
156334c2f668SLeonid Yegoshin * Did we catch a fault trying to load an instruction in
156434c2f668SLeonid Yegoshin * 16-bit mode?
156534c2f668SLeonid Yegoshin */
156634c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
156734c2f668SLeonid Yegoshin goto sigbus;
156834c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW)
156934c2f668SLeonid Yegoshin show_registers(regs);
157034c2f668SLeonid Yegoshin
157134c2f668SLeonid Yegoshin if (cpu_has_mmips) {
157234c2f668SLeonid Yegoshin emulate_load_store_microMIPS(regs,
157334c2f668SLeonid Yegoshin (void __user *)regs->cp0_badvaddr);
157434c2f668SLeonid Yegoshin return;
157534c2f668SLeonid Yegoshin }
157634c2f668SLeonid Yegoshin
1577451b001bSSteven J. Hill if (cpu_has_mips16) {
1578451b001bSSteven J. Hill emulate_load_store_MIPS16e(regs,
1579451b001bSSteven J. Hill (void __user *)regs->cp0_badvaddr);
1580451b001bSSteven J. Hill return;
1581451b001bSSteven J. Hill }
1582451b001bSSteven J. Hill
158334c2f668SLeonid Yegoshin goto sigbus;
158434c2f668SLeonid Yegoshin }
158534c2f668SLeonid Yegoshin
158634c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW)
158734c2f668SLeonid Yegoshin show_registers(regs);
15887cba4128SThomas Bogendoerfer pc = (unsigned int *)exception_epc(regs);
158934c2f668SLeonid Yegoshin
15907f18f151SRalf Baechle emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
15911da177e4SLinus Torvalds
15921da177e4SLinus Torvalds return;
15931da177e4SLinus Torvalds
15941da177e4SLinus Torvalds sigbus:
15951da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs);
15963cf5d076SEric W. Biederman force_sig(SIGBUS);
15971da177e4SLinus Torvalds
15981da177e4SLinus Torvalds /*
15991da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc
16001da177e4SLinus Torvalds */
1601c3fc5cd5SRalf Baechle exception_exit(prev_state);
16021da177e4SLinus Torvalds }
16036312e0eeSAtsushi Nemoto
16046312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
debugfs_unaligned(void)16056312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
16066312e0eeSAtsushi Nemoto {
1607d8140426SGreg Kroah-Hartman debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir,
1608d8140426SGreg Kroah-Hartman &unaligned_instructions);
1609d8140426SGreg Kroah-Hartman debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
16106312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_action);
16116312e0eeSAtsushi Nemoto return 0;
16126312e0eeSAtsushi Nemoto }
16138d6b591cSRalf Baechle arch_initcall(debugfs_unaligned);
16146312e0eeSAtsushi Nemoto #endif
1615