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
emulate_load_store_insn(struct pt_regs * regs,void __user * addr,unsigned int * pc)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 */
163*6673c276SSiarhei Volkau #ifdef CONFIG_MACH_INGENIC
164*6673c276SSiarhei Volkau case spec2_op:
165*6673c276SSiarhei Volkau if (insn.mxu_lx_format.func != mxu_lx_op)
166*6673c276SSiarhei Volkau goto sigbus; /* other MXU instructions we don't care */
167*6673c276SSiarhei Volkau
168*6673c276SSiarhei Volkau switch (insn.mxu_lx_format.op) {
169*6673c276SSiarhei Volkau case mxu_lxw_op:
170*6673c276SSiarhei Volkau if (user && !access_ok(addr, 4))
171*6673c276SSiarhei Volkau goto sigbus;
172*6673c276SSiarhei Volkau LoadW(addr, value, res);
173*6673c276SSiarhei Volkau if (res)
174*6673c276SSiarhei Volkau goto fault;
175*6673c276SSiarhei Volkau compute_return_epc(regs);
176*6673c276SSiarhei Volkau regs->regs[insn.mxu_lx_format.rd] = value;
177*6673c276SSiarhei Volkau break;
178*6673c276SSiarhei Volkau case mxu_lxh_op:
179*6673c276SSiarhei Volkau if (user && !access_ok(addr, 2))
180*6673c276SSiarhei Volkau goto sigbus;
181*6673c276SSiarhei Volkau LoadHW(addr, value, res);
182*6673c276SSiarhei Volkau if (res)
183*6673c276SSiarhei Volkau goto fault;
184*6673c276SSiarhei Volkau compute_return_epc(regs);
185*6673c276SSiarhei Volkau regs->regs[insn.dsp_format.rd] = value;
186*6673c276SSiarhei Volkau break;
187*6673c276SSiarhei Volkau case mxu_lxhu_op:
188*6673c276SSiarhei Volkau if (user && !access_ok(addr, 2))
189*6673c276SSiarhei Volkau goto sigbus;
190*6673c276SSiarhei Volkau LoadHWU(addr, value, res);
191*6673c276SSiarhei Volkau if (res)
192*6673c276SSiarhei Volkau goto fault;
193*6673c276SSiarhei Volkau compute_return_epc(regs);
194*6673c276SSiarhei Volkau regs->regs[insn.dsp_format.rd] = value;
195*6673c276SSiarhei Volkau break;
196*6673c276SSiarhei Volkau case mxu_lxb_op:
197*6673c276SSiarhei Volkau case mxu_lxbu_op:
198*6673c276SSiarhei Volkau goto sigbus;
199*6673c276SSiarhei Volkau default:
200*6673c276SSiarhei Volkau goto sigill;
201*6673c276SSiarhei Volkau }
202*6673c276SSiarhei Volkau break;
203*6673c276SSiarhei Volkau #endif
204c1771216SLeonid Yegoshin case spec3_op:
2053f88ec63SMiodrag Dinic if (insn.dsp_format.func == lx_op) {
2063f88ec63SMiodrag Dinic switch (insn.dsp_format.op) {
2073f88ec63SMiodrag Dinic case lwx_op:
20845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
2093f88ec63SMiodrag Dinic goto sigbus;
2103f88ec63SMiodrag Dinic LoadW(addr, value, res);
2113f88ec63SMiodrag Dinic if (res)
2123f88ec63SMiodrag Dinic goto fault;
2133f88ec63SMiodrag Dinic compute_return_epc(regs);
2143f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value;
2153f88ec63SMiodrag Dinic break;
2163f88ec63SMiodrag Dinic case lhx_op:
21745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
2183f88ec63SMiodrag Dinic goto sigbus;
2193f88ec63SMiodrag Dinic LoadHW(addr, value, res);
2203f88ec63SMiodrag Dinic if (res)
2213f88ec63SMiodrag Dinic goto fault;
2223f88ec63SMiodrag Dinic compute_return_epc(regs);
2233f88ec63SMiodrag Dinic regs->regs[insn.dsp_format.rd] = value;
2243f88ec63SMiodrag Dinic break;
2253f88ec63SMiodrag Dinic default:
2263f88ec63SMiodrag Dinic goto sigill;
2273f88ec63SMiodrag Dinic }
2283f88ec63SMiodrag Dinic }
2293f88ec63SMiodrag Dinic #ifdef CONFIG_EVA
2303f88ec63SMiodrag Dinic else {
231c1771216SLeonid Yegoshin /*
2323f88ec63SMiodrag Dinic * we can land here only from kernel accessing user
2333f88ec63SMiodrag Dinic * memory, so we need to "switch" the address limit to
2343f88ec63SMiodrag Dinic * user space, so that address check can work properly.
235c1771216SLeonid Yegoshin */
236c1771216SLeonid Yegoshin switch (insn.spec3_format.func) {
237c1771216SLeonid Yegoshin case lhe_op:
23845deb5faSThomas Bogendoerfer if (!access_ok(addr, 2))
239c1771216SLeonid Yegoshin goto sigbus;
240eeb53895SMarkos Chandras LoadHWE(addr, value, res);
24145deb5faSThomas Bogendoerfer if (res)
242c1771216SLeonid Yegoshin goto fault;
243c1771216SLeonid Yegoshin compute_return_epc(regs);
244c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value;
245c1771216SLeonid Yegoshin break;
246c1771216SLeonid Yegoshin case lwe_op:
24745deb5faSThomas Bogendoerfer if (!access_ok(addr, 4))
248c1771216SLeonid Yegoshin goto sigbus;
249eeb53895SMarkos Chandras LoadWE(addr, value, res);
25045deb5faSThomas Bogendoerfer if (res)
251c1771216SLeonid Yegoshin goto fault;
252c1771216SLeonid Yegoshin compute_return_epc(regs);
253c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value;
254c1771216SLeonid Yegoshin break;
255c1771216SLeonid Yegoshin case lhue_op:
25645deb5faSThomas Bogendoerfer if (!access_ok(addr, 2))
257c1771216SLeonid Yegoshin goto sigbus;
258eeb53895SMarkos Chandras LoadHWUE(addr, value, res);
25945deb5faSThomas Bogendoerfer if (res)
260c1771216SLeonid Yegoshin goto fault;
261c1771216SLeonid Yegoshin compute_return_epc(regs);
262c1771216SLeonid Yegoshin regs->regs[insn.spec3_format.rt] = value;
263c1771216SLeonid Yegoshin break;
264c1771216SLeonid Yegoshin case she_op:
26545deb5faSThomas Bogendoerfer if (!access_ok(addr, 2))
266c1771216SLeonid Yegoshin goto sigbus;
267c1771216SLeonid Yegoshin compute_return_epc(regs);
268c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt];
269eeb53895SMarkos Chandras StoreHWE(addr, value, res);
27045deb5faSThomas Bogendoerfer if (res)
271c1771216SLeonid Yegoshin goto fault;
272c1771216SLeonid Yegoshin break;
273c1771216SLeonid Yegoshin case swe_op:
27445deb5faSThomas Bogendoerfer if (!access_ok(addr, 4))
275c1771216SLeonid Yegoshin goto sigbus;
276c1771216SLeonid Yegoshin compute_return_epc(regs);
277c1771216SLeonid Yegoshin value = regs->regs[insn.spec3_format.rt];
278eeb53895SMarkos Chandras StoreWE(addr, value, res);
27945deb5faSThomas Bogendoerfer if (res)
280c1771216SLeonid Yegoshin goto fault;
281c1771216SLeonid Yegoshin break;
282c1771216SLeonid Yegoshin default:
283c1771216SLeonid Yegoshin goto sigill;
284c1771216SLeonid Yegoshin }
2853f88ec63SMiodrag Dinic }
286c1771216SLeonid Yegoshin #endif
2873f88ec63SMiodrag Dinic break;
2881da177e4SLinus Torvalds case lh_op:
28945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
2901da177e4SLinus Torvalds goto sigbus;
2911da177e4SLinus Torvalds
29245deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
2936eae3548SMarkos Chandras LoadHWE(addr, value, res);
29445deb5faSThomas Bogendoerfer else
2956eae3548SMarkos Chandras LoadHW(addr, value, res);
2966eae3548SMarkos Chandras
2971da177e4SLinus Torvalds if (res)
2981da177e4SLinus Torvalds goto fault;
2997f18f151SRalf Baechle compute_return_epc(regs);
3007f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3011da177e4SLinus Torvalds break;
3021da177e4SLinus Torvalds
3031da177e4SLinus Torvalds case lw_op:
30445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
3051da177e4SLinus Torvalds goto sigbus;
3061da177e4SLinus Torvalds
30745deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
3086eae3548SMarkos Chandras LoadWE(addr, value, res);
30945deb5faSThomas Bogendoerfer else
3106eae3548SMarkos Chandras LoadW(addr, value, res);
3116eae3548SMarkos Chandras
3121da177e4SLinus Torvalds if (res)
3131da177e4SLinus Torvalds goto fault;
3147f18f151SRalf Baechle compute_return_epc(regs);
3157f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3161da177e4SLinus Torvalds break;
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds case lhu_op:
31945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
3201da177e4SLinus Torvalds goto sigbus;
3211da177e4SLinus Torvalds
32245deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
3236eae3548SMarkos Chandras LoadHWUE(addr, value, res);
32445deb5faSThomas Bogendoerfer else
3256eae3548SMarkos Chandras LoadHWU(addr, value, res);
3266eae3548SMarkos Chandras
3271da177e4SLinus Torvalds if (res)
3281da177e4SLinus Torvalds goto fault;
3297f18f151SRalf Baechle compute_return_epc(regs);
3307f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3311da177e4SLinus Torvalds break;
3321da177e4SLinus Torvalds
3331da177e4SLinus Torvalds case lwu_op:
334875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3351da177e4SLinus Torvalds /*
3361da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But
3371da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency
3381da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr
3391da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit
3401da177e4SLinus Torvalds * instructions on 32-bit kernels.
3411da177e4SLinus Torvalds */
34245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
3431da177e4SLinus Torvalds goto sigbus;
3441da177e4SLinus Torvalds
34534c2f668SLeonid Yegoshin LoadWU(addr, value, res);
3461da177e4SLinus Torvalds if (res)
3471da177e4SLinus Torvalds goto fault;
3487f18f151SRalf Baechle compute_return_epc(regs);
3497f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3501da177e4SLinus Torvalds break;
351875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3521da177e4SLinus Torvalds
3531da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */
3541da177e4SLinus Torvalds goto sigill;
3551da177e4SLinus Torvalds
3561da177e4SLinus Torvalds case ld_op:
357875d43e7SRalf Baechle #ifdef CONFIG_64BIT
3581da177e4SLinus Torvalds /*
3591da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But
3601da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency
3611da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr
3621da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit
3631da177e4SLinus Torvalds * instructions on 32-bit kernels.
3641da177e4SLinus Torvalds */
36545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
3661da177e4SLinus Torvalds goto sigbus;
3671da177e4SLinus Torvalds
36834c2f668SLeonid Yegoshin LoadDW(addr, value, res);
3691da177e4SLinus Torvalds if (res)
3701da177e4SLinus Torvalds goto fault;
3717f18f151SRalf Baechle compute_return_epc(regs);
3727f18f151SRalf Baechle regs->regs[insn.i_format.rt] = value;
3731da177e4SLinus Torvalds break;
374875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
3751da177e4SLinus Torvalds
3761da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */
3771da177e4SLinus Torvalds goto sigill;
3781da177e4SLinus Torvalds
3791da177e4SLinus Torvalds case sh_op:
38045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
3811da177e4SLinus Torvalds goto sigbus;
3821da177e4SLinus Torvalds
38334c2f668SLeonid Yegoshin compute_return_epc(regs);
3841da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt];
3856eae3548SMarkos Chandras
38645deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
3876eae3548SMarkos Chandras StoreHWE(addr, value, res);
38845deb5faSThomas Bogendoerfer else
3896eae3548SMarkos Chandras StoreHW(addr, value, res);
3906eae3548SMarkos Chandras
3911da177e4SLinus Torvalds if (res)
3921da177e4SLinus Torvalds goto fault;
3931da177e4SLinus Torvalds break;
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds case sw_op:
39645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
3971da177e4SLinus Torvalds goto sigbus;
3981da177e4SLinus Torvalds
39934c2f668SLeonid Yegoshin compute_return_epc(regs);
4001da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt];
4016eae3548SMarkos Chandras
40245deb5faSThomas Bogendoerfer if (IS_ENABLED(CONFIG_EVA) && user)
4036eae3548SMarkos Chandras StoreWE(addr, value, res);
40445deb5faSThomas Bogendoerfer else
4056eae3548SMarkos Chandras StoreW(addr, value, res);
4066eae3548SMarkos Chandras
4071da177e4SLinus Torvalds if (res)
4081da177e4SLinus Torvalds goto fault;
4091da177e4SLinus Torvalds break;
4101da177e4SLinus Torvalds
4111da177e4SLinus Torvalds case sd_op:
412875d43e7SRalf Baechle #ifdef CONFIG_64BIT
4131da177e4SLinus Torvalds /*
4141da177e4SLinus Torvalds * A 32-bit kernel might be running on a 64-bit processor. But
4151da177e4SLinus Torvalds * if we're on a 32-bit processor and an i-cache incoherency
4161da177e4SLinus Torvalds * or race makes us see a 64-bit instruction here the sdl/sdr
4171da177e4SLinus Torvalds * would blow up, so for now we don't handle unaligned 64-bit
4181da177e4SLinus Torvalds * instructions on 32-bit kernels.
4191da177e4SLinus Torvalds */
42045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
4211da177e4SLinus Torvalds goto sigbus;
4221da177e4SLinus Torvalds
42334c2f668SLeonid Yegoshin compute_return_epc(regs);
4241da177e4SLinus Torvalds value = regs->regs[insn.i_format.rt];
42534c2f668SLeonid Yegoshin StoreDW(addr, value, res);
4261da177e4SLinus Torvalds if (res)
4271da177e4SLinus Torvalds goto fault;
4281da177e4SLinus Torvalds break;
429875d43e7SRalf Baechle #endif /* CONFIG_64BIT */
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds /* Cannot handle 64-bit instructions in 32-bit kernel */
4321da177e4SLinus Torvalds goto sigill;
4331da177e4SLinus Torvalds
43485164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
43585164fd8SPaul Burton
4361da177e4SLinus Torvalds case lwc1_op:
4371da177e4SLinus Torvalds case ldc1_op:
4381da177e4SLinus Torvalds case swc1_op:
4391da177e4SLinus Torvalds case sdc1_op:
44085164fd8SPaul Burton case cop1x_op: {
44185164fd8SPaul Burton void __user *fault_addr = NULL;
44285164fd8SPaul Burton
443102cedc3SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs);
444102cedc3SLeonid Yegoshin BUG_ON(!used_math());
445102cedc3SLeonid Yegoshin
446102cedc3SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
447102cedc3SLeonid Yegoshin &fault_addr);
448102cedc3SLeonid Yegoshin own_fpu(1); /* Restore FPU state. */
449102cedc3SLeonid Yegoshin
450102cedc3SLeonid Yegoshin /* Signal if something went wrong. */
451304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0);
452102cedc3SLeonid Yegoshin
453102cedc3SLeonid Yegoshin if (res == 0)
454102cedc3SLeonid Yegoshin break;
455102cedc3SLeonid Yegoshin return;
45685164fd8SPaul Burton }
45785164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
4581da177e4SLinus Torvalds
45985164fd8SPaul Burton #ifdef CONFIG_CPU_HAS_MSA
46085164fd8SPaul Burton
46185164fd8SPaul Burton case msa_op: {
46285164fd8SPaul Burton unsigned int wd, preempted;
46385164fd8SPaul Burton enum msa_2b_fmt df;
46485164fd8SPaul Burton union fpureg *fpr;
46585164fd8SPaul Burton
466e4aa1f15SLeonid Yegoshin if (!cpu_has_msa)
467e4aa1f15SLeonid Yegoshin goto sigill;
468e4aa1f15SLeonid Yegoshin
469e4aa1f15SLeonid Yegoshin /*
470e4aa1f15SLeonid Yegoshin * If we've reached this point then userland should have taken
471e4aa1f15SLeonid Yegoshin * the MSA disabled exception & initialised vector context at
472e4aa1f15SLeonid Yegoshin * some point in the past.
473e4aa1f15SLeonid Yegoshin */
474e4aa1f15SLeonid Yegoshin BUG_ON(!thread_msa_context_live());
475e4aa1f15SLeonid Yegoshin
476e4aa1f15SLeonid Yegoshin df = insn.msa_mi10_format.df;
477e4aa1f15SLeonid Yegoshin wd = insn.msa_mi10_format.wd;
478e4aa1f15SLeonid Yegoshin fpr = ¤t->thread.fpu.fpr[wd];
479e4aa1f15SLeonid Yegoshin
480e4aa1f15SLeonid Yegoshin switch (insn.msa_mi10_format.func) {
481e4aa1f15SLeonid Yegoshin case msa_ld_op:
48296d4f267SLinus Torvalds if (!access_ok(addr, sizeof(*fpr)))
483e4aa1f15SLeonid Yegoshin goto sigbus;
484e4aa1f15SLeonid Yegoshin
485fa8ff601SPaul Burton do {
486e4aa1f15SLeonid Yegoshin /*
487fa8ff601SPaul Burton * If we have live MSA context keep track of
488fa8ff601SPaul Burton * whether we get preempted in order to avoid
489fa8ff601SPaul Burton * the register context we load being clobbered
490fa8ff601SPaul Burton * by the live context as it's saved during
491fa8ff601SPaul Burton * preemption. If we don't have live context
492fa8ff601SPaul Burton * then it can't be saved to clobber the value
493fa8ff601SPaul Burton * we load.
494e4aa1f15SLeonid Yegoshin */
495fa8ff601SPaul Burton preempted = test_thread_flag(TIF_USEDMSA);
496e4aa1f15SLeonid Yegoshin
497e4aa1f15SLeonid Yegoshin res = __copy_from_user_inatomic(fpr, addr,
498e4aa1f15SLeonid Yegoshin sizeof(*fpr));
499e4aa1f15SLeonid Yegoshin if (res)
500e4aa1f15SLeonid Yegoshin goto fault;
501e4aa1f15SLeonid Yegoshin
502e4aa1f15SLeonid Yegoshin /*
503fa8ff601SPaul Burton * Update the hardware register if it is in use
504fa8ff601SPaul Burton * by the task in this quantum, in order to
505fa8ff601SPaul Burton * avoid having to save & restore the whole
506fa8ff601SPaul Burton * vector context.
507e4aa1f15SLeonid Yegoshin */
508fa8ff601SPaul Burton preempt_disable();
509fa8ff601SPaul Burton if (test_thread_flag(TIF_USEDMSA)) {
510e4aa1f15SLeonid Yegoshin write_msa_wr(wd, fpr, df);
511fa8ff601SPaul Burton preempted = 0;
512fa8ff601SPaul Burton }
513e4aa1f15SLeonid Yegoshin preempt_enable();
514fa8ff601SPaul Burton } while (preempted);
515e4aa1f15SLeonid Yegoshin break;
516e4aa1f15SLeonid Yegoshin
517e4aa1f15SLeonid Yegoshin case msa_st_op:
51896d4f267SLinus Torvalds if (!access_ok(addr, sizeof(*fpr)))
519e4aa1f15SLeonid Yegoshin goto sigbus;
520e4aa1f15SLeonid Yegoshin
521e4aa1f15SLeonid Yegoshin /*
522e4aa1f15SLeonid Yegoshin * Update from the hardware register if it is in use by
523e4aa1f15SLeonid Yegoshin * the task in this quantum, in order to avoid having to
524e4aa1f15SLeonid Yegoshin * save & restore the whole vector context.
525e4aa1f15SLeonid Yegoshin */
526e4aa1f15SLeonid Yegoshin preempt_disable();
527e4aa1f15SLeonid Yegoshin if (test_thread_flag(TIF_USEDMSA))
528e4aa1f15SLeonid Yegoshin read_msa_wr(wd, fpr, df);
529e4aa1f15SLeonid Yegoshin preempt_enable();
530e4aa1f15SLeonid Yegoshin
531e4aa1f15SLeonid Yegoshin res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr));
532e4aa1f15SLeonid Yegoshin if (res)
533e4aa1f15SLeonid Yegoshin goto fault;
534e4aa1f15SLeonid Yegoshin break;
535e4aa1f15SLeonid Yegoshin
536e4aa1f15SLeonid Yegoshin default:
537e4aa1f15SLeonid Yegoshin goto sigbus;
538e4aa1f15SLeonid Yegoshin }
539e4aa1f15SLeonid Yegoshin
540e4aa1f15SLeonid Yegoshin compute_return_epc(regs);
541e4aa1f15SLeonid Yegoshin break;
54285164fd8SPaul Burton }
54385164fd8SPaul Burton #endif /* CONFIG_CPU_HAS_MSA */
544e4aa1f15SLeonid Yegoshin
5450593a44cSLeonid Yegoshin #ifndef CONFIG_CPU_MIPSR6
5461da177e4SLinus Torvalds /*
54769f3a7deSRalf Baechle * COP2 is available to implementor for application specific use.
54869f3a7deSRalf Baechle * It's up to applications to register a notifier chain and do
54969f3a7deSRalf Baechle * whatever they have to do, including possible sending of signals.
5500593a44cSLeonid Yegoshin *
5510593a44cSLeonid Yegoshin * This instruction has been reallocated in Release 6
5521da177e4SLinus Torvalds */
55369f3a7deSRalf Baechle case lwc2_op:
55469f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LWC2_OP, regs);
55569f3a7deSRalf Baechle break;
55669f3a7deSRalf Baechle
55769f3a7deSRalf Baechle case ldc2_op:
55869f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_LDC2_OP, regs);
55969f3a7deSRalf Baechle break;
56069f3a7deSRalf Baechle
56169f3a7deSRalf Baechle case swc2_op:
56269f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SWC2_OP, regs);
56369f3a7deSRalf Baechle break;
56469f3a7deSRalf Baechle
56569f3a7deSRalf Baechle case sdc2_op:
56669f3a7deSRalf Baechle cu2_notifier_call_chain(CU2_SDC2_OP, regs);
56769f3a7deSRalf Baechle break;
5680593a44cSLeonid Yegoshin #endif
5691da177e4SLinus Torvalds default:
5701da177e4SLinus Torvalds /*
5711da177e4SLinus Torvalds * Pheeee... We encountered an yet unknown instruction or
5721da177e4SLinus Torvalds * cache coherence problem. Die sucker, die ...
5731da177e4SLinus Torvalds */
5741da177e4SLinus Torvalds goto sigill;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds
5776312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
5781da177e4SLinus Torvalds unaligned_instructions++;
5791da177e4SLinus Torvalds #endif
5801da177e4SLinus Torvalds
5817f18f151SRalf Baechle return;
5821da177e4SLinus Torvalds
5831da177e4SLinus Torvalds fault:
58434c2f668SLeonid Yegoshin /* roll back jump/branch */
58534c2f668SLeonid Yegoshin regs->cp0_epc = origpc;
58634c2f668SLeonid Yegoshin regs->regs[31] = orig31;
5871da177e4SLinus Torvalds /* Did we have an exception handler installed? */
5881da177e4SLinus Torvalds if (fixup_exception(regs))
5897f18f151SRalf Baechle return;
5901da177e4SLinus Torvalds
5911da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs);
5923cf5d076SEric W. Biederman force_sig(SIGSEGV);
5931da177e4SLinus Torvalds
5947f18f151SRalf Baechle return;
5951da177e4SLinus Torvalds
5961da177e4SLinus Torvalds sigbus:
5971da177e4SLinus Torvalds die_if_kernel("Unhandled kernel unaligned access", regs);
5983cf5d076SEric W. Biederman force_sig(SIGBUS);
5991da177e4SLinus Torvalds
6007f18f151SRalf Baechle return;
6011da177e4SLinus Torvalds
6021da177e4SLinus Torvalds sigill:
60334c2f668SLeonid Yegoshin die_if_kernel
60434c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs);
6053cf5d076SEric W. Biederman force_sig(SIGILL);
60634c2f668SLeonid Yegoshin }
60734c2f668SLeonid Yegoshin
60834c2f668SLeonid Yegoshin /* Recode table from 16-bit register notation to 32-bit GPR. */
60934c2f668SLeonid Yegoshin const int reg16to32[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
61034c2f668SLeonid Yegoshin
61134c2f668SLeonid Yegoshin /* Recode table from 16-bit STORE register notation to 32-bit GPR. */
612b7fc2cc5SPaul Burton static const int reg16to32st[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
61334c2f668SLeonid Yegoshin
emulate_load_store_microMIPS(struct pt_regs * regs,void __user * addr)61474338805SDavid Daney static void emulate_load_store_microMIPS(struct pt_regs *regs,
61574338805SDavid Daney void __user *addr)
61634c2f668SLeonid Yegoshin {
61734c2f668SLeonid Yegoshin unsigned long value;
61834c2f668SLeonid Yegoshin unsigned int res;
61934c2f668SLeonid Yegoshin int i;
62034c2f668SLeonid Yegoshin unsigned int reg = 0, rvar;
62134c2f668SLeonid Yegoshin unsigned long orig31;
62234c2f668SLeonid Yegoshin u16 __user *pc16;
62334c2f668SLeonid Yegoshin u16 halfword;
62434c2f668SLeonid Yegoshin unsigned int word;
62534c2f668SLeonid Yegoshin unsigned long origpc, contpc;
62634c2f668SLeonid Yegoshin union mips_instruction insn;
62734c2f668SLeonid Yegoshin struct mm_decoded_insn mminsn;
62845deb5faSThomas Bogendoerfer bool user = user_mode(regs);
62934c2f668SLeonid Yegoshin
63034c2f668SLeonid Yegoshin origpc = regs->cp0_epc;
63134c2f668SLeonid Yegoshin orig31 = regs->regs[31];
63234c2f668SLeonid Yegoshin
63334c2f668SLeonid Yegoshin mminsn.micro_mips_mode = 1;
63434c2f668SLeonid Yegoshin
63534c2f668SLeonid Yegoshin /*
63634c2f668SLeonid Yegoshin * This load never faults.
63734c2f668SLeonid Yegoshin */
63834c2f668SLeonid Yegoshin pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
63934c2f668SLeonid Yegoshin __get_user(halfword, pc16);
64034c2f668SLeonid Yegoshin pc16++;
64134c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 2;
64234c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16);
64334c2f668SLeonid Yegoshin mminsn.pc_inc = 2;
64434c2f668SLeonid Yegoshin
64534c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) {
64634c2f668SLeonid Yegoshin __get_user(halfword, pc16);
64734c2f668SLeonid Yegoshin pc16++;
64834c2f668SLeonid Yegoshin contpc = regs->cp0_epc + 4;
64934c2f668SLeonid Yegoshin mminsn.pc_inc = 4;
65034c2f668SLeonid Yegoshin word |= halfword;
65134c2f668SLeonid Yegoshin }
65234c2f668SLeonid Yegoshin mminsn.insn = word;
65334c2f668SLeonid Yegoshin
65434c2f668SLeonid Yegoshin if (get_user(halfword, pc16))
65534c2f668SLeonid Yegoshin goto fault;
65634c2f668SLeonid Yegoshin mminsn.next_pc_inc = 2;
65734c2f668SLeonid Yegoshin word = ((unsigned int)halfword << 16);
65834c2f668SLeonid Yegoshin
65934c2f668SLeonid Yegoshin if (!mm_insn_16bit(halfword)) {
66034c2f668SLeonid Yegoshin pc16++;
66134c2f668SLeonid Yegoshin if (get_user(halfword, pc16))
66234c2f668SLeonid Yegoshin goto fault;
66334c2f668SLeonid Yegoshin mminsn.next_pc_inc = 4;
66434c2f668SLeonid Yegoshin word |= halfword;
66534c2f668SLeonid Yegoshin }
66634c2f668SLeonid Yegoshin mminsn.next_insn = word;
66734c2f668SLeonid Yegoshin
66834c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.insn);
66934c2f668SLeonid Yegoshin if (mm_isBranchInstr(regs, mminsn, &contpc))
67034c2f668SLeonid Yegoshin insn = (union mips_instruction)(mminsn.next_insn);
67134c2f668SLeonid Yegoshin
67234c2f668SLeonid Yegoshin /* Parse instruction to find what to do */
67334c2f668SLeonid Yegoshin
67434c2f668SLeonid Yegoshin switch (insn.mm_i_format.opcode) {
67534c2f668SLeonid Yegoshin
67634c2f668SLeonid Yegoshin case mm_pool32a_op:
67734c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) {
67834c2f668SLeonid Yegoshin case mm_lwxs_op:
67934c2f668SLeonid Yegoshin reg = insn.mm_x_format.rd;
68034c2f668SLeonid Yegoshin goto loadW;
68134c2f668SLeonid Yegoshin }
68234c2f668SLeonid Yegoshin
68334c2f668SLeonid Yegoshin goto sigbus;
68434c2f668SLeonid Yegoshin
68534c2f668SLeonid Yegoshin case mm_pool32b_op:
68634c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) {
68734c2f668SLeonid Yegoshin case mm_lwp_func:
68834c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
68934c2f668SLeonid Yegoshin if (reg == 31)
69034c2f668SLeonid Yegoshin goto sigbus;
69134c2f668SLeonid Yegoshin
69245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
69334c2f668SLeonid Yegoshin goto sigbus;
69434c2f668SLeonid Yegoshin
69534c2f668SLeonid Yegoshin LoadW(addr, value, res);
69634c2f668SLeonid Yegoshin if (res)
69734c2f668SLeonid Yegoshin goto fault;
69834c2f668SLeonid Yegoshin regs->regs[reg] = value;
69934c2f668SLeonid Yegoshin addr += 4;
70034c2f668SLeonid Yegoshin LoadW(addr, value, res);
70134c2f668SLeonid Yegoshin if (res)
70234c2f668SLeonid Yegoshin goto fault;
70334c2f668SLeonid Yegoshin regs->regs[reg + 1] = value;
70434c2f668SLeonid Yegoshin goto success;
70534c2f668SLeonid Yegoshin
70634c2f668SLeonid Yegoshin case mm_swp_func:
70734c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
70834c2f668SLeonid Yegoshin if (reg == 31)
70934c2f668SLeonid Yegoshin goto sigbus;
71034c2f668SLeonid Yegoshin
71145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
71234c2f668SLeonid Yegoshin goto sigbus;
71334c2f668SLeonid Yegoshin
71434c2f668SLeonid Yegoshin value = regs->regs[reg];
71534c2f668SLeonid Yegoshin StoreW(addr, value, res);
71634c2f668SLeonid Yegoshin if (res)
71734c2f668SLeonid Yegoshin goto fault;
71834c2f668SLeonid Yegoshin addr += 4;
71934c2f668SLeonid Yegoshin value = regs->regs[reg + 1];
72034c2f668SLeonid Yegoshin StoreW(addr, value, res);
72134c2f668SLeonid Yegoshin if (res)
72234c2f668SLeonid Yegoshin goto fault;
72334c2f668SLeonid Yegoshin goto success;
72434c2f668SLeonid Yegoshin
72534c2f668SLeonid Yegoshin case mm_ldp_func:
72634c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
72734c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
72834c2f668SLeonid Yegoshin if (reg == 31)
72934c2f668SLeonid Yegoshin goto sigbus;
73034c2f668SLeonid Yegoshin
73145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 16))
73234c2f668SLeonid Yegoshin goto sigbus;
73334c2f668SLeonid Yegoshin
73434c2f668SLeonid Yegoshin LoadDW(addr, value, res);
73534c2f668SLeonid Yegoshin if (res)
73634c2f668SLeonid Yegoshin goto fault;
73734c2f668SLeonid Yegoshin regs->regs[reg] = value;
73834c2f668SLeonid Yegoshin addr += 8;
73934c2f668SLeonid Yegoshin LoadDW(addr, value, res);
74034c2f668SLeonid Yegoshin if (res)
74134c2f668SLeonid Yegoshin goto fault;
74234c2f668SLeonid Yegoshin regs->regs[reg + 1] = value;
74334c2f668SLeonid Yegoshin goto success;
74434c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
74534c2f668SLeonid Yegoshin
74634c2f668SLeonid Yegoshin goto sigill;
74734c2f668SLeonid Yegoshin
74834c2f668SLeonid Yegoshin case mm_sdp_func:
74934c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
75034c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
75134c2f668SLeonid Yegoshin if (reg == 31)
75234c2f668SLeonid Yegoshin goto sigbus;
75334c2f668SLeonid Yegoshin
75445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 16))
75534c2f668SLeonid Yegoshin goto sigbus;
75634c2f668SLeonid Yegoshin
75734c2f668SLeonid Yegoshin value = regs->regs[reg];
75834c2f668SLeonid Yegoshin StoreDW(addr, value, res);
75934c2f668SLeonid Yegoshin if (res)
76034c2f668SLeonid Yegoshin goto fault;
76134c2f668SLeonid Yegoshin addr += 8;
76234c2f668SLeonid Yegoshin value = regs->regs[reg + 1];
76334c2f668SLeonid Yegoshin StoreDW(addr, value, res);
76434c2f668SLeonid Yegoshin if (res)
76534c2f668SLeonid Yegoshin goto fault;
76634c2f668SLeonid Yegoshin goto success;
76734c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
76834c2f668SLeonid Yegoshin
76934c2f668SLeonid Yegoshin goto sigill;
77034c2f668SLeonid Yegoshin
77134c2f668SLeonid Yegoshin case mm_lwm32_func:
77234c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
77334c2f668SLeonid Yegoshin rvar = reg & 0xf;
77434c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
77534c2f668SLeonid Yegoshin goto sigill;
77634c2f668SLeonid Yegoshin if (reg & 0x10) {
77745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * (rvar + 1)))
77834c2f668SLeonid Yegoshin goto sigbus;
77934c2f668SLeonid Yegoshin } else {
78045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
78134c2f668SLeonid Yegoshin goto sigbus;
78234c2f668SLeonid Yegoshin }
78334c2f668SLeonid Yegoshin if (rvar == 9)
78434c2f668SLeonid Yegoshin rvar = 8;
78534c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
78634c2f668SLeonid Yegoshin LoadW(addr, value, res);
78734c2f668SLeonid Yegoshin if (res)
78834c2f668SLeonid Yegoshin goto fault;
78934c2f668SLeonid Yegoshin addr += 4;
79034c2f668SLeonid Yegoshin regs->regs[i] = value;
79134c2f668SLeonid Yegoshin }
79234c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
79334c2f668SLeonid Yegoshin LoadW(addr, value, res);
79434c2f668SLeonid Yegoshin if (res)
79534c2f668SLeonid Yegoshin goto fault;
79634c2f668SLeonid Yegoshin addr += 4;
79734c2f668SLeonid Yegoshin regs->regs[30] = value;
79834c2f668SLeonid Yegoshin }
79934c2f668SLeonid Yegoshin if (reg & 0x10) {
80034c2f668SLeonid Yegoshin LoadW(addr, value, res);
80134c2f668SLeonid Yegoshin if (res)
80234c2f668SLeonid Yegoshin goto fault;
80334c2f668SLeonid Yegoshin regs->regs[31] = value;
80434c2f668SLeonid Yegoshin }
80534c2f668SLeonid Yegoshin goto success;
80634c2f668SLeonid Yegoshin
80734c2f668SLeonid Yegoshin case mm_swm32_func:
80834c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
80934c2f668SLeonid Yegoshin rvar = reg & 0xf;
81034c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
81134c2f668SLeonid Yegoshin goto sigill;
81234c2f668SLeonid Yegoshin if (reg & 0x10) {
81345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * (rvar + 1)))
81434c2f668SLeonid Yegoshin goto sigbus;
81534c2f668SLeonid Yegoshin } else {
81645deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
81734c2f668SLeonid Yegoshin goto sigbus;
81834c2f668SLeonid Yegoshin }
81934c2f668SLeonid Yegoshin if (rvar == 9)
82034c2f668SLeonid Yegoshin rvar = 8;
82134c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
82234c2f668SLeonid Yegoshin value = regs->regs[i];
82334c2f668SLeonid Yegoshin StoreW(addr, value, res);
82434c2f668SLeonid Yegoshin if (res)
82534c2f668SLeonid Yegoshin goto fault;
82634c2f668SLeonid Yegoshin addr += 4;
82734c2f668SLeonid Yegoshin }
82834c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
82934c2f668SLeonid Yegoshin value = regs->regs[30];
83034c2f668SLeonid Yegoshin StoreW(addr, value, res);
83134c2f668SLeonid Yegoshin if (res)
83234c2f668SLeonid Yegoshin goto fault;
83334c2f668SLeonid Yegoshin addr += 4;
83434c2f668SLeonid Yegoshin }
83534c2f668SLeonid Yegoshin if (reg & 0x10) {
83634c2f668SLeonid Yegoshin value = regs->regs[31];
83734c2f668SLeonid Yegoshin StoreW(addr, value, res);
83834c2f668SLeonid Yegoshin if (res)
83934c2f668SLeonid Yegoshin goto fault;
84034c2f668SLeonid Yegoshin }
84134c2f668SLeonid Yegoshin goto success;
84234c2f668SLeonid Yegoshin
84334c2f668SLeonid Yegoshin case mm_ldm_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 LoadDW(addr, value, res);
86134c2f668SLeonid Yegoshin if (res)
86234c2f668SLeonid Yegoshin goto fault;
86334c2f668SLeonid Yegoshin addr += 4;
86434c2f668SLeonid Yegoshin regs->regs[i] = value;
86534c2f668SLeonid Yegoshin }
86634c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
86734c2f668SLeonid Yegoshin LoadDW(addr, value, res);
86834c2f668SLeonid Yegoshin if (res)
86934c2f668SLeonid Yegoshin goto fault;
87034c2f668SLeonid Yegoshin addr += 8;
87134c2f668SLeonid Yegoshin regs->regs[30] = value;
87234c2f668SLeonid Yegoshin }
87334c2f668SLeonid Yegoshin if (reg & 0x10) {
87434c2f668SLeonid Yegoshin LoadDW(addr, value, res);
87534c2f668SLeonid Yegoshin if (res)
87634c2f668SLeonid Yegoshin goto fault;
87734c2f668SLeonid Yegoshin regs->regs[31] = value;
87834c2f668SLeonid Yegoshin }
87934c2f668SLeonid Yegoshin goto success;
88034c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
88134c2f668SLeonid Yegoshin
88234c2f668SLeonid Yegoshin goto sigill;
88334c2f668SLeonid Yegoshin
88434c2f668SLeonid Yegoshin case mm_sdm_func:
88534c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
88634c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
88734c2f668SLeonid Yegoshin rvar = reg & 0xf;
88834c2f668SLeonid Yegoshin if ((rvar > 9) || !reg)
88934c2f668SLeonid Yegoshin goto sigill;
89034c2f668SLeonid Yegoshin if (reg & 0x10) {
89145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * (rvar + 1)))
89234c2f668SLeonid Yegoshin goto sigbus;
89334c2f668SLeonid Yegoshin } else {
89445deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8 * rvar))
89534c2f668SLeonid Yegoshin goto sigbus;
89634c2f668SLeonid Yegoshin }
89734c2f668SLeonid Yegoshin if (rvar == 9)
89834c2f668SLeonid Yegoshin rvar = 8;
89934c2f668SLeonid Yegoshin
90034c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
90134c2f668SLeonid Yegoshin value = regs->regs[i];
90234c2f668SLeonid Yegoshin StoreDW(addr, value, res);
90334c2f668SLeonid Yegoshin if (res)
90434c2f668SLeonid Yegoshin goto fault;
90534c2f668SLeonid Yegoshin addr += 8;
90634c2f668SLeonid Yegoshin }
90734c2f668SLeonid Yegoshin if ((reg & 0xf) == 9) {
90834c2f668SLeonid Yegoshin value = regs->regs[30];
90934c2f668SLeonid Yegoshin StoreDW(addr, value, res);
91034c2f668SLeonid Yegoshin if (res)
91134c2f668SLeonid Yegoshin goto fault;
91234c2f668SLeonid Yegoshin addr += 8;
91334c2f668SLeonid Yegoshin }
91434c2f668SLeonid Yegoshin if (reg & 0x10) {
91534c2f668SLeonid Yegoshin value = regs->regs[31];
91634c2f668SLeonid Yegoshin StoreDW(addr, value, res);
91734c2f668SLeonid Yegoshin if (res)
91834c2f668SLeonid Yegoshin goto fault;
91934c2f668SLeonid Yegoshin }
92034c2f668SLeonid Yegoshin goto success;
92134c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
92234c2f668SLeonid Yegoshin
92334c2f668SLeonid Yegoshin goto sigill;
92434c2f668SLeonid Yegoshin
92534c2f668SLeonid Yegoshin /* LWC2, SWC2, LDC2, SDC2 are not serviced */
92634c2f668SLeonid Yegoshin }
92734c2f668SLeonid Yegoshin
92834c2f668SLeonid Yegoshin goto sigbus;
92934c2f668SLeonid Yegoshin
93034c2f668SLeonid Yegoshin case mm_pool32c_op:
93134c2f668SLeonid Yegoshin switch (insn.mm_m_format.func) {
93234c2f668SLeonid Yegoshin case mm_lwu_func:
93334c2f668SLeonid Yegoshin reg = insn.mm_m_format.rd;
93434c2f668SLeonid Yegoshin goto loadWU;
93534c2f668SLeonid Yegoshin }
93634c2f668SLeonid Yegoshin
93734c2f668SLeonid Yegoshin /* LL,SC,LLD,SCD are not serviced */
93834c2f668SLeonid Yegoshin goto sigbus;
93934c2f668SLeonid Yegoshin
94085164fd8SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT
94134c2f668SLeonid Yegoshin case mm_pool32f_op:
94234c2f668SLeonid Yegoshin switch (insn.mm_x_format.func) {
94334c2f668SLeonid Yegoshin case mm_lwxc1_func:
94434c2f668SLeonid Yegoshin case mm_swxc1_func:
94534c2f668SLeonid Yegoshin case mm_ldxc1_func:
94634c2f668SLeonid Yegoshin case mm_sdxc1_func:
94734c2f668SLeonid Yegoshin goto fpu_emul;
94834c2f668SLeonid Yegoshin }
94934c2f668SLeonid Yegoshin
95034c2f668SLeonid Yegoshin goto sigbus;
95134c2f668SLeonid Yegoshin
95234c2f668SLeonid Yegoshin case mm_ldc132_op:
95334c2f668SLeonid Yegoshin case mm_sdc132_op:
95434c2f668SLeonid Yegoshin case mm_lwc132_op:
95585164fd8SPaul Burton case mm_swc132_op: {
95685164fd8SPaul Burton void __user *fault_addr = NULL;
95785164fd8SPaul Burton
95834c2f668SLeonid Yegoshin fpu_emul:
95934c2f668SLeonid Yegoshin /* roll back jump/branch */
96034c2f668SLeonid Yegoshin regs->cp0_epc = origpc;
96134c2f668SLeonid Yegoshin regs->regs[31] = orig31;
96234c2f668SLeonid Yegoshin
96334c2f668SLeonid Yegoshin die_if_kernel("Unaligned FP access in kernel code", regs);
96434c2f668SLeonid Yegoshin BUG_ON(!used_math());
96534c2f668SLeonid Yegoshin BUG_ON(!is_fpu_owner());
96634c2f668SLeonid Yegoshin
96734c2f668SLeonid Yegoshin res = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1,
96834c2f668SLeonid Yegoshin &fault_addr);
96934c2f668SLeonid Yegoshin own_fpu(1); /* restore FPU state */
97034c2f668SLeonid Yegoshin
97134c2f668SLeonid Yegoshin /* If something went wrong, signal */
972304acb71SMaciej W. Rozycki process_fpemu_return(res, fault_addr, 0);
97334c2f668SLeonid Yegoshin
97434c2f668SLeonid Yegoshin if (res == 0)
97534c2f668SLeonid Yegoshin goto success;
97634c2f668SLeonid Yegoshin return;
97785164fd8SPaul Burton }
97885164fd8SPaul Burton #endif /* CONFIG_MIPS_FP_SUPPORT */
97934c2f668SLeonid Yegoshin
98034c2f668SLeonid Yegoshin case mm_lh32_op:
98134c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
98234c2f668SLeonid Yegoshin goto loadHW;
98334c2f668SLeonid Yegoshin
98434c2f668SLeonid Yegoshin case mm_lhu32_op:
98534c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
98634c2f668SLeonid Yegoshin goto loadHWU;
98734c2f668SLeonid Yegoshin
98834c2f668SLeonid Yegoshin case mm_lw32_op:
98934c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
99034c2f668SLeonid Yegoshin goto loadW;
99134c2f668SLeonid Yegoshin
99234c2f668SLeonid Yegoshin case mm_sh32_op:
99334c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
99434c2f668SLeonid Yegoshin goto storeHW;
99534c2f668SLeonid Yegoshin
99634c2f668SLeonid Yegoshin case mm_sw32_op:
99734c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
99834c2f668SLeonid Yegoshin goto storeW;
99934c2f668SLeonid Yegoshin
100034c2f668SLeonid Yegoshin case mm_ld32_op:
100134c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
100234c2f668SLeonid Yegoshin goto loadDW;
100334c2f668SLeonid Yegoshin
100434c2f668SLeonid Yegoshin case mm_sd32_op:
100534c2f668SLeonid Yegoshin reg = insn.mm_i_format.rt;
100634c2f668SLeonid Yegoshin goto storeDW;
100734c2f668SLeonid Yegoshin
100834c2f668SLeonid Yegoshin case mm_pool16c_op:
100934c2f668SLeonid Yegoshin switch (insn.mm16_m_format.func) {
101034c2f668SLeonid Yegoshin case mm_lwm16_op:
101134c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist;
101234c2f668SLeonid Yegoshin rvar = reg + 1;
101345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
101434c2f668SLeonid Yegoshin goto sigbus;
101534c2f668SLeonid Yegoshin
101634c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
101734c2f668SLeonid Yegoshin LoadW(addr, value, res);
101834c2f668SLeonid Yegoshin if (res)
101934c2f668SLeonid Yegoshin goto fault;
102034c2f668SLeonid Yegoshin addr += 4;
102134c2f668SLeonid Yegoshin regs->regs[i] = value;
102234c2f668SLeonid Yegoshin }
102334c2f668SLeonid Yegoshin LoadW(addr, value, res);
102434c2f668SLeonid Yegoshin if (res)
102534c2f668SLeonid Yegoshin goto fault;
102634c2f668SLeonid Yegoshin regs->regs[31] = value;
102734c2f668SLeonid Yegoshin
102834c2f668SLeonid Yegoshin goto success;
102934c2f668SLeonid Yegoshin
103034c2f668SLeonid Yegoshin case mm_swm16_op:
103134c2f668SLeonid Yegoshin reg = insn.mm16_m_format.rlist;
103234c2f668SLeonid Yegoshin rvar = reg + 1;
103345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4 * rvar))
103434c2f668SLeonid Yegoshin goto sigbus;
103534c2f668SLeonid Yegoshin
103634c2f668SLeonid Yegoshin for (i = 16; rvar; rvar--, i++) {
103734c2f668SLeonid Yegoshin value = regs->regs[i];
103834c2f668SLeonid Yegoshin StoreW(addr, value, res);
103934c2f668SLeonid Yegoshin if (res)
104034c2f668SLeonid Yegoshin goto fault;
104134c2f668SLeonid Yegoshin addr += 4;
104234c2f668SLeonid Yegoshin }
104334c2f668SLeonid Yegoshin value = regs->regs[31];
104434c2f668SLeonid Yegoshin StoreW(addr, value, res);
104534c2f668SLeonid Yegoshin if (res)
104634c2f668SLeonid Yegoshin goto fault;
104734c2f668SLeonid Yegoshin
104834c2f668SLeonid Yegoshin goto success;
104934c2f668SLeonid Yegoshin
105034c2f668SLeonid Yegoshin }
105134c2f668SLeonid Yegoshin
105234c2f668SLeonid Yegoshin goto sigbus;
105334c2f668SLeonid Yegoshin
105434c2f668SLeonid Yegoshin case mm_lhu16_op:
105534c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt];
105634c2f668SLeonid Yegoshin goto loadHWU;
105734c2f668SLeonid Yegoshin
105834c2f668SLeonid Yegoshin case mm_lw16_op:
105934c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_rb_format.rt];
106034c2f668SLeonid Yegoshin goto loadW;
106134c2f668SLeonid Yegoshin
106234c2f668SLeonid Yegoshin case mm_sh16_op:
106334c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt];
106434c2f668SLeonid Yegoshin goto storeHW;
106534c2f668SLeonid Yegoshin
106634c2f668SLeonid Yegoshin case mm_sw16_op:
106734c2f668SLeonid Yegoshin reg = reg16to32st[insn.mm16_rb_format.rt];
106834c2f668SLeonid Yegoshin goto storeW;
106934c2f668SLeonid Yegoshin
107034c2f668SLeonid Yegoshin case mm_lwsp16_op:
107134c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt;
107234c2f668SLeonid Yegoshin goto loadW;
107334c2f668SLeonid Yegoshin
107434c2f668SLeonid Yegoshin case mm_swsp16_op:
107534c2f668SLeonid Yegoshin reg = insn.mm16_r5_format.rt;
107634c2f668SLeonid Yegoshin goto storeW;
107734c2f668SLeonid Yegoshin
107834c2f668SLeonid Yegoshin case mm_lwgp16_op:
107934c2f668SLeonid Yegoshin reg = reg16to32[insn.mm16_r3_format.rt];
108034c2f668SLeonid Yegoshin goto loadW;
108134c2f668SLeonid Yegoshin
108234c2f668SLeonid Yegoshin default:
108334c2f668SLeonid Yegoshin goto sigill;
108434c2f668SLeonid Yegoshin }
108534c2f668SLeonid Yegoshin
108634c2f668SLeonid Yegoshin loadHW:
108745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
108834c2f668SLeonid Yegoshin goto sigbus;
108934c2f668SLeonid Yegoshin
109034c2f668SLeonid Yegoshin LoadHW(addr, value, res);
109134c2f668SLeonid Yegoshin if (res)
109234c2f668SLeonid Yegoshin goto fault;
109334c2f668SLeonid Yegoshin regs->regs[reg] = value;
109434c2f668SLeonid Yegoshin goto success;
109534c2f668SLeonid Yegoshin
109634c2f668SLeonid Yegoshin loadHWU:
109745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
109834c2f668SLeonid Yegoshin goto sigbus;
109934c2f668SLeonid Yegoshin
110034c2f668SLeonid Yegoshin LoadHWU(addr, value, res);
110134c2f668SLeonid Yegoshin if (res)
110234c2f668SLeonid Yegoshin goto fault;
110334c2f668SLeonid Yegoshin regs->regs[reg] = value;
110434c2f668SLeonid Yegoshin goto success;
110534c2f668SLeonid Yegoshin
110634c2f668SLeonid Yegoshin loadW:
110745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
110834c2f668SLeonid Yegoshin goto sigbus;
110934c2f668SLeonid Yegoshin
111034c2f668SLeonid Yegoshin LoadW(addr, value, res);
111134c2f668SLeonid Yegoshin if (res)
111234c2f668SLeonid Yegoshin goto fault;
111334c2f668SLeonid Yegoshin regs->regs[reg] = value;
111434c2f668SLeonid Yegoshin goto success;
111534c2f668SLeonid Yegoshin
111634c2f668SLeonid Yegoshin loadWU:
111734c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
111834c2f668SLeonid Yegoshin /*
111934c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But
112034c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency
112134c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr
112234c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit
112334c2f668SLeonid Yegoshin * instructions on 32-bit kernels.
112434c2f668SLeonid Yegoshin */
112545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
112634c2f668SLeonid Yegoshin goto sigbus;
112734c2f668SLeonid Yegoshin
112834c2f668SLeonid Yegoshin LoadWU(addr, value, res);
112934c2f668SLeonid Yegoshin if (res)
113034c2f668SLeonid Yegoshin goto fault;
113134c2f668SLeonid Yegoshin regs->regs[reg] = value;
113234c2f668SLeonid Yegoshin goto success;
113334c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
113434c2f668SLeonid Yegoshin
113534c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */
113634c2f668SLeonid Yegoshin goto sigill;
113734c2f668SLeonid Yegoshin
113834c2f668SLeonid Yegoshin loadDW:
113934c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
114034c2f668SLeonid Yegoshin /*
114134c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But
114234c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency
114334c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr
114434c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit
114534c2f668SLeonid Yegoshin * instructions on 32-bit kernels.
114634c2f668SLeonid Yegoshin */
114745deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
114834c2f668SLeonid Yegoshin goto sigbus;
114934c2f668SLeonid Yegoshin
115034c2f668SLeonid Yegoshin LoadDW(addr, value, res);
115134c2f668SLeonid Yegoshin if (res)
115234c2f668SLeonid Yegoshin goto fault;
115334c2f668SLeonid Yegoshin regs->regs[reg] = value;
115434c2f668SLeonid Yegoshin goto success;
115534c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
115634c2f668SLeonid Yegoshin
115734c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */
115834c2f668SLeonid Yegoshin goto sigill;
115934c2f668SLeonid Yegoshin
116034c2f668SLeonid Yegoshin storeHW:
116145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
116234c2f668SLeonid Yegoshin goto sigbus;
116334c2f668SLeonid Yegoshin
116434c2f668SLeonid Yegoshin value = regs->regs[reg];
116534c2f668SLeonid Yegoshin StoreHW(addr, value, res);
116634c2f668SLeonid Yegoshin if (res)
116734c2f668SLeonid Yegoshin goto fault;
116834c2f668SLeonid Yegoshin goto success;
116934c2f668SLeonid Yegoshin
117034c2f668SLeonid Yegoshin storeW:
117145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
117234c2f668SLeonid Yegoshin goto sigbus;
117334c2f668SLeonid Yegoshin
117434c2f668SLeonid Yegoshin value = regs->regs[reg];
117534c2f668SLeonid Yegoshin StoreW(addr, value, res);
117634c2f668SLeonid Yegoshin if (res)
117734c2f668SLeonid Yegoshin goto fault;
117834c2f668SLeonid Yegoshin goto success;
117934c2f668SLeonid Yegoshin
118034c2f668SLeonid Yegoshin storeDW:
118134c2f668SLeonid Yegoshin #ifdef CONFIG_64BIT
118234c2f668SLeonid Yegoshin /*
118334c2f668SLeonid Yegoshin * A 32-bit kernel might be running on a 64-bit processor. But
118434c2f668SLeonid Yegoshin * if we're on a 32-bit processor and an i-cache incoherency
118534c2f668SLeonid Yegoshin * or race makes us see a 64-bit instruction here the sdl/sdr
118634c2f668SLeonid Yegoshin * would blow up, so for now we don't handle unaligned 64-bit
118734c2f668SLeonid Yegoshin * instructions on 32-bit kernels.
118834c2f668SLeonid Yegoshin */
118945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
119034c2f668SLeonid Yegoshin goto sigbus;
119134c2f668SLeonid Yegoshin
119234c2f668SLeonid Yegoshin value = regs->regs[reg];
119334c2f668SLeonid Yegoshin StoreDW(addr, value, res);
119434c2f668SLeonid Yegoshin if (res)
119534c2f668SLeonid Yegoshin goto fault;
119634c2f668SLeonid Yegoshin goto success;
119734c2f668SLeonid Yegoshin #endif /* CONFIG_64BIT */
119834c2f668SLeonid Yegoshin
119934c2f668SLeonid Yegoshin /* Cannot handle 64-bit instructions in 32-bit kernel */
120034c2f668SLeonid Yegoshin goto sigill;
120134c2f668SLeonid Yegoshin
120234c2f668SLeonid Yegoshin success:
120334c2f668SLeonid Yegoshin regs->cp0_epc = contpc; /* advance or branch */
120434c2f668SLeonid Yegoshin
120534c2f668SLeonid Yegoshin #ifdef CONFIG_DEBUG_FS
120634c2f668SLeonid Yegoshin unaligned_instructions++;
120734c2f668SLeonid Yegoshin #endif
120834c2f668SLeonid Yegoshin return;
120934c2f668SLeonid Yegoshin
121034c2f668SLeonid Yegoshin fault:
121134c2f668SLeonid Yegoshin /* roll back jump/branch */
121234c2f668SLeonid Yegoshin regs->cp0_epc = origpc;
121334c2f668SLeonid Yegoshin regs->regs[31] = orig31;
121434c2f668SLeonid Yegoshin /* Did we have an exception handler installed? */
121534c2f668SLeonid Yegoshin if (fixup_exception(regs))
121634c2f668SLeonid Yegoshin return;
121734c2f668SLeonid Yegoshin
121834c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs);
12193cf5d076SEric W. Biederman force_sig(SIGSEGV);
122034c2f668SLeonid Yegoshin
122134c2f668SLeonid Yegoshin return;
122234c2f668SLeonid Yegoshin
122334c2f668SLeonid Yegoshin sigbus:
122434c2f668SLeonid Yegoshin die_if_kernel("Unhandled kernel unaligned access", regs);
12253cf5d076SEric W. Biederman force_sig(SIGBUS);
122634c2f668SLeonid Yegoshin
122734c2f668SLeonid Yegoshin return;
122834c2f668SLeonid Yegoshin
122934c2f668SLeonid Yegoshin sigill:
123034c2f668SLeonid Yegoshin die_if_kernel
123134c2f668SLeonid Yegoshin ("Unhandled kernel unaligned access or invalid instruction", regs);
12323cf5d076SEric W. Biederman force_sig(SIGILL);
12331da177e4SLinus Torvalds }
12341da177e4SLinus Torvalds
emulate_load_store_MIPS16e(struct pt_regs * regs,void __user * addr)1235451b001bSSteven J. Hill static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
1236451b001bSSteven J. Hill {
1237451b001bSSteven J. Hill unsigned long value;
1238451b001bSSteven J. Hill unsigned int res;
1239451b001bSSteven J. Hill int reg;
1240451b001bSSteven J. Hill unsigned long orig31;
1241451b001bSSteven J. Hill u16 __user *pc16;
1242451b001bSSteven J. Hill unsigned long origpc;
1243451b001bSSteven J. Hill union mips16e_instruction mips16inst, oldinst;
1244f3235d32SMaciej W. Rozycki unsigned int opcode;
1245f3235d32SMaciej W. Rozycki int extended = 0;
124645deb5faSThomas Bogendoerfer bool user = user_mode(regs);
1247451b001bSSteven J. Hill
1248451b001bSSteven J. Hill origpc = regs->cp0_epc;
1249451b001bSSteven J. Hill orig31 = regs->regs[31];
1250451b001bSSteven J. Hill pc16 = (unsigned short __user *)msk_isa16_mode(origpc);
1251451b001bSSteven J. Hill /*
1252451b001bSSteven J. Hill * This load never faults.
1253451b001bSSteven J. Hill */
1254451b001bSSteven J. Hill __get_user(mips16inst.full, pc16);
1255451b001bSSteven J. Hill oldinst = mips16inst;
1256451b001bSSteven J. Hill
1257451b001bSSteven J. Hill /* skip EXTEND instruction */
1258451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_extend_op) {
1259f3235d32SMaciej W. Rozycki extended = 1;
1260451b001bSSteven J. Hill pc16++;
1261451b001bSSteven J. Hill __get_user(mips16inst.full, pc16);
1262451b001bSSteven J. Hill } else if (delay_slot(regs)) {
1263451b001bSSteven J. Hill /* skip jump instructions */
1264451b001bSSteven J. Hill /* JAL/JALX are 32 bits but have OPCODE in first short int */
1265451b001bSSteven J. Hill if (mips16inst.ri.opcode == MIPS16e_jal_op)
1266451b001bSSteven J. Hill pc16++;
1267451b001bSSteven J. Hill pc16++;
1268451b001bSSteven J. Hill if (get_user(mips16inst.full, pc16))
1269451b001bSSteven J. Hill goto sigbus;
1270451b001bSSteven J. Hill }
1271451b001bSSteven J. Hill
1272f3235d32SMaciej W. Rozycki opcode = mips16inst.ri.opcode;
1273f3235d32SMaciej W. Rozycki switch (opcode) {
1274451b001bSSteven J. Hill case MIPS16e_i64_op: /* I64 or RI64 instruction */
1275451b001bSSteven J. Hill switch (mips16inst.i64.func) { /* I64/RI64 func field check */
1276451b001bSSteven J. Hill case MIPS16e_ldpc_func:
1277451b001bSSteven J. Hill case MIPS16e_ldsp_func:
1278451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry];
1279451b001bSSteven J. Hill goto loadDW;
1280451b001bSSteven J. Hill
1281451b001bSSteven J. Hill case MIPS16e_sdsp_func:
1282451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri64.ry];
1283451b001bSSteven J. Hill goto writeDW;
1284451b001bSSteven J. Hill
1285451b001bSSteven J. Hill case MIPS16e_sdrasp_func:
1286451b001bSSteven J. Hill reg = 29; /* GPRSP */
1287451b001bSSteven J. Hill goto writeDW;
1288451b001bSSteven J. Hill }
1289451b001bSSteven J. Hill
1290451b001bSSteven J. Hill goto sigbus;
1291451b001bSSteven J. Hill
1292451b001bSSteven J. Hill case MIPS16e_swsp_op:
1293f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx];
1294f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2)
1295f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) {
1296f3235d32SMaciej W. Rozycki case 0: /* SWSP */
1297f3235d32SMaciej W. Rozycki case 1: /* SWGP */
1298f3235d32SMaciej W. Rozycki break;
1299f3235d32SMaciej W. Rozycki case 2: /* SHGP */
1300f3235d32SMaciej W. Rozycki opcode = MIPS16e_sh_op;
1301f3235d32SMaciej W. Rozycki break;
1302f3235d32SMaciej W. Rozycki default:
1303f3235d32SMaciej W. Rozycki goto sigbus;
1304f3235d32SMaciej W. Rozycki }
1305f3235d32SMaciej W. Rozycki break;
1306f3235d32SMaciej W. Rozycki
1307451b001bSSteven J. Hill case MIPS16e_lwpc_op:
1308f3235d32SMaciej W. Rozycki reg = reg16to32[mips16inst.ri.rx];
1309f3235d32SMaciej W. Rozycki break;
1310f3235d32SMaciej W. Rozycki
1311451b001bSSteven J. Hill case MIPS16e_lwsp_op:
1312451b001bSSteven J. Hill reg = reg16to32[mips16inst.ri.rx];
1313f3235d32SMaciej W. Rozycki if (extended && cpu_has_mips16e2)
1314f3235d32SMaciej W. Rozycki switch (mips16inst.ri.imm >> 5) {
1315f3235d32SMaciej W. Rozycki case 0: /* LWSP */
1316f3235d32SMaciej W. Rozycki case 1: /* LWGP */
1317f3235d32SMaciej W. Rozycki break;
1318f3235d32SMaciej W. Rozycki case 2: /* LHGP */
1319f3235d32SMaciej W. Rozycki opcode = MIPS16e_lh_op;
1320f3235d32SMaciej W. Rozycki break;
1321f3235d32SMaciej W. Rozycki case 4: /* LHUGP */
1322f3235d32SMaciej W. Rozycki opcode = MIPS16e_lhu_op;
1323f3235d32SMaciej W. Rozycki break;
1324f3235d32SMaciej W. Rozycki default:
1325f3235d32SMaciej W. Rozycki goto sigbus;
1326f3235d32SMaciej W. Rozycki }
1327451b001bSSteven J. Hill break;
1328451b001bSSteven J. Hill
1329451b001bSSteven J. Hill case MIPS16e_i8_op:
1330451b001bSSteven J. Hill if (mips16inst.i8.func != MIPS16e_swrasp_func)
1331451b001bSSteven J. Hill goto sigbus;
1332451b001bSSteven J. Hill reg = 29; /* GPRSP */
1333451b001bSSteven J. Hill break;
1334451b001bSSteven J. Hill
1335451b001bSSteven J. Hill default:
1336451b001bSSteven J. Hill reg = reg16to32[mips16inst.rri.ry];
1337451b001bSSteven J. Hill break;
1338451b001bSSteven J. Hill }
1339451b001bSSteven J. Hill
1340f3235d32SMaciej W. Rozycki switch (opcode) {
1341451b001bSSteven J. Hill
1342451b001bSSteven J. Hill case MIPS16e_lb_op:
1343451b001bSSteven J. Hill case MIPS16e_lbu_op:
1344451b001bSSteven J. Hill case MIPS16e_sb_op:
1345451b001bSSteven J. Hill goto sigbus;
1346451b001bSSteven J. Hill
1347451b001bSSteven J. Hill case MIPS16e_lh_op:
134845deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
1349451b001bSSteven J. Hill goto sigbus;
1350451b001bSSteven J. Hill
1351451b001bSSteven J. Hill LoadHW(addr, value, res);
1352451b001bSSteven J. Hill if (res)
1353451b001bSSteven J. Hill goto fault;
1354451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1355451b001bSSteven J. Hill regs->regs[reg] = value;
1356451b001bSSteven J. Hill break;
1357451b001bSSteven J. Hill
1358451b001bSSteven J. Hill case MIPS16e_lhu_op:
135945deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
1360451b001bSSteven J. Hill goto sigbus;
1361451b001bSSteven J. Hill
1362451b001bSSteven J. Hill LoadHWU(addr, value, res);
1363451b001bSSteven J. Hill if (res)
1364451b001bSSteven J. Hill goto fault;
1365451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1366451b001bSSteven J. Hill regs->regs[reg] = value;
1367451b001bSSteven J. Hill break;
1368451b001bSSteven J. Hill
1369451b001bSSteven J. Hill case MIPS16e_lw_op:
1370451b001bSSteven J. Hill case MIPS16e_lwpc_op:
1371451b001bSSteven J. Hill case MIPS16e_lwsp_op:
137245deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
1373451b001bSSteven J. Hill goto sigbus;
1374451b001bSSteven J. Hill
1375451b001bSSteven J. Hill LoadW(addr, value, res);
1376451b001bSSteven J. Hill if (res)
1377451b001bSSteven J. Hill goto fault;
1378451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1379451b001bSSteven J. Hill regs->regs[reg] = value;
1380451b001bSSteven J. Hill break;
1381451b001bSSteven J. Hill
1382451b001bSSteven J. Hill case MIPS16e_lwu_op:
1383451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1384451b001bSSteven J. Hill /*
1385451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But
1386451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency
1387451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr
1388451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit
1389451b001bSSteven J. Hill * instructions on 32-bit kernels.
1390451b001bSSteven J. Hill */
139145deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
1392451b001bSSteven J. Hill goto sigbus;
1393451b001bSSteven J. Hill
1394451b001bSSteven J. Hill LoadWU(addr, value, res);
1395451b001bSSteven J. Hill if (res)
1396451b001bSSteven J. Hill goto fault;
1397451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1398451b001bSSteven J. Hill regs->regs[reg] = value;
1399451b001bSSteven J. Hill break;
1400451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1401451b001bSSteven J. Hill
1402451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */
1403451b001bSSteven J. Hill goto sigill;
1404451b001bSSteven J. Hill
1405451b001bSSteven J. Hill case MIPS16e_ld_op:
1406451b001bSSteven J. Hill loadDW:
1407451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1408451b001bSSteven J. Hill /*
1409451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But
1410451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency
1411451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr
1412451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit
1413451b001bSSteven J. Hill * instructions on 32-bit kernels.
1414451b001bSSteven J. Hill */
141545deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
1416451b001bSSteven J. Hill goto sigbus;
1417451b001bSSteven J. Hill
1418451b001bSSteven J. Hill LoadDW(addr, value, res);
1419451b001bSSteven J. Hill if (res)
1420451b001bSSteven J. Hill goto fault;
1421451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1422451b001bSSteven J. Hill regs->regs[reg] = value;
1423451b001bSSteven J. Hill break;
1424451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1425451b001bSSteven J. Hill
1426451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */
1427451b001bSSteven J. Hill goto sigill;
1428451b001bSSteven J. Hill
1429451b001bSSteven J. Hill case MIPS16e_sh_op:
143045deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 2))
1431451b001bSSteven J. Hill goto sigbus;
1432451b001bSSteven J. Hill
1433451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1434451b001bSSteven J. Hill value = regs->regs[reg];
1435451b001bSSteven J. Hill StoreHW(addr, value, res);
1436451b001bSSteven J. Hill if (res)
1437451b001bSSteven J. Hill goto fault;
1438451b001bSSteven J. Hill break;
1439451b001bSSteven J. Hill
1440451b001bSSteven J. Hill case MIPS16e_sw_op:
1441451b001bSSteven J. Hill case MIPS16e_swsp_op:
1442451b001bSSteven J. Hill case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */
144345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 4))
1444451b001bSSteven J. Hill goto sigbus;
1445451b001bSSteven J. Hill
1446451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1447451b001bSSteven J. Hill value = regs->regs[reg];
1448451b001bSSteven J. Hill StoreW(addr, value, res);
1449451b001bSSteven J. Hill if (res)
1450451b001bSSteven J. Hill goto fault;
1451451b001bSSteven J. Hill break;
1452451b001bSSteven J. Hill
1453451b001bSSteven J. Hill case MIPS16e_sd_op:
1454451b001bSSteven J. Hill writeDW:
1455451b001bSSteven J. Hill #ifdef CONFIG_64BIT
1456451b001bSSteven J. Hill /*
1457451b001bSSteven J. Hill * A 32-bit kernel might be running on a 64-bit processor. But
1458451b001bSSteven J. Hill * if we're on a 32-bit processor and an i-cache incoherency
1459451b001bSSteven J. Hill * or race makes us see a 64-bit instruction here the sdl/sdr
1460451b001bSSteven J. Hill * would blow up, so for now we don't handle unaligned 64-bit
1461451b001bSSteven J. Hill * instructions on 32-bit kernels.
1462451b001bSSteven J. Hill */
146345deb5faSThomas Bogendoerfer if (user && !access_ok(addr, 8))
1464451b001bSSteven J. Hill goto sigbus;
1465451b001bSSteven J. Hill
1466451b001bSSteven J. Hill MIPS16e_compute_return_epc(regs, &oldinst);
1467451b001bSSteven J. Hill value = regs->regs[reg];
1468451b001bSSteven J. Hill StoreDW(addr, value, res);
1469451b001bSSteven J. Hill if (res)
1470451b001bSSteven J. Hill goto fault;
1471451b001bSSteven J. Hill break;
1472451b001bSSteven J. Hill #endif /* CONFIG_64BIT */
1473451b001bSSteven J. Hill
1474451b001bSSteven J. Hill /* Cannot handle 64-bit instructions in 32-bit kernel */
1475451b001bSSteven J. Hill goto sigill;
1476451b001bSSteven J. Hill
1477451b001bSSteven J. Hill default:
1478451b001bSSteven J. Hill /*
1479451b001bSSteven J. Hill * Pheeee... We encountered an yet unknown instruction or
1480451b001bSSteven J. Hill * cache coherence problem. Die sucker, die ...
1481451b001bSSteven J. Hill */
1482451b001bSSteven J. Hill goto sigill;
1483451b001bSSteven J. Hill }
1484451b001bSSteven J. Hill
1485451b001bSSteven J. Hill #ifdef CONFIG_DEBUG_FS
1486451b001bSSteven J. Hill unaligned_instructions++;
1487451b001bSSteven J. Hill #endif
1488451b001bSSteven J. Hill
1489451b001bSSteven J. Hill return;
1490451b001bSSteven J. Hill
1491451b001bSSteven J. Hill fault:
1492451b001bSSteven J. Hill /* roll back jump/branch */
1493451b001bSSteven J. Hill regs->cp0_epc = origpc;
1494451b001bSSteven J. Hill regs->regs[31] = orig31;
1495451b001bSSteven J. Hill /* Did we have an exception handler installed? */
1496451b001bSSteven J. Hill if (fixup_exception(regs))
1497451b001bSSteven J. Hill return;
1498451b001bSSteven J. Hill
1499451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs);
15003cf5d076SEric W. Biederman force_sig(SIGSEGV);
1501451b001bSSteven J. Hill
1502451b001bSSteven J. Hill return;
1503451b001bSSteven J. Hill
1504451b001bSSteven J. Hill sigbus:
1505451b001bSSteven J. Hill die_if_kernel("Unhandled kernel unaligned access", regs);
15063cf5d076SEric W. Biederman force_sig(SIGBUS);
1507451b001bSSteven J. Hill
1508451b001bSSteven J. Hill return;
1509451b001bSSteven J. Hill
1510451b001bSSteven J. Hill sigill:
1511451b001bSSteven J. Hill die_if_kernel
1512451b001bSSteven J. Hill ("Unhandled kernel unaligned access or invalid instruction", regs);
15133cf5d076SEric W. Biederman force_sig(SIGILL);
1514451b001bSSteven J. Hill }
1515fc192e50STony Wu
do_ade(struct pt_regs * regs)15161da177e4SLinus Torvalds asmlinkage void do_ade(struct pt_regs *regs)
15171da177e4SLinus Torvalds {
1518c3fc5cd5SRalf Baechle enum ctx_state prev_state;
15197cba4128SThomas Bogendoerfer unsigned int *pc;
15201da177e4SLinus Torvalds
1521c3fc5cd5SRalf Baechle prev_state = exception_enter();
15227f788d2dSDeng-Cheng Zhu perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1523a8b0ca17SPeter Zijlstra 1, regs, regs->cp0_badvaddr);
1524429124d9SThomas Bogendoerfer
1525429124d9SThomas Bogendoerfer #ifdef CONFIG_64BIT
1526429124d9SThomas Bogendoerfer /*
1527429124d9SThomas Bogendoerfer * check, if we are hitting space between CPU implemented maximum
1528429124d9SThomas Bogendoerfer * virtual user address and 64bit maximum virtual user address
1529429124d9SThomas Bogendoerfer * and do exception handling to get EFAULTs for get_user/put_user
1530429124d9SThomas Bogendoerfer */
1531429124d9SThomas Bogendoerfer if ((regs->cp0_badvaddr >= (1UL << cpu_vmbits)) &&
1532429124d9SThomas Bogendoerfer (regs->cp0_badvaddr < XKSSEG)) {
1533429124d9SThomas Bogendoerfer if (fixup_exception(regs)) {
1534429124d9SThomas Bogendoerfer current->thread.cp0_baduaddr = regs->cp0_badvaddr;
1535429124d9SThomas Bogendoerfer return;
1536429124d9SThomas Bogendoerfer }
1537429124d9SThomas Bogendoerfer goto sigbus;
1538429124d9SThomas Bogendoerfer }
1539429124d9SThomas Bogendoerfer #endif
1540429124d9SThomas Bogendoerfer
15411da177e4SLinus Torvalds /*
15421da177e4SLinus Torvalds * Did we catch a fault trying to load an instruction?
15431da177e4SLinus Torvalds */
154434c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == regs->cp0_epc)
15451da177e4SLinus Torvalds goto sigbus;
15461da177e4SLinus Torvalds
1547293c5bd1SRalf Baechle if (user_mode(regs) && !test_thread_flag(TIF_FIXADE))
15481da177e4SLinus Torvalds goto sigbus;
15496312e0eeSAtsushi Nemoto if (unaligned_action == UNALIGNED_ACTION_SIGNAL)
15506312e0eeSAtsushi Nemoto goto sigbus;
15511da177e4SLinus Torvalds
15521da177e4SLinus Torvalds /*
15531da177e4SLinus Torvalds * Do branch emulation only if we didn't forward the exception.
15541da177e4SLinus Torvalds * This is all so but ugly ...
15551da177e4SLinus Torvalds */
155634c2f668SLeonid Yegoshin
155734c2f668SLeonid Yegoshin /*
155834c2f668SLeonid Yegoshin * Are we running in microMIPS mode?
155934c2f668SLeonid Yegoshin */
156034c2f668SLeonid Yegoshin if (get_isa16_mode(regs->cp0_epc)) {
156134c2f668SLeonid Yegoshin /*
156234c2f668SLeonid Yegoshin * Did we catch a fault trying to load an instruction in
156334c2f668SLeonid Yegoshin * 16-bit mode?
156434c2f668SLeonid Yegoshin */
156534c2f668SLeonid Yegoshin if (regs->cp0_badvaddr == msk_isa16_mode(regs->cp0_epc))
156634c2f668SLeonid Yegoshin goto sigbus;
156734c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW)
156834c2f668SLeonid Yegoshin show_registers(regs);
156934c2f668SLeonid Yegoshin
157034c2f668SLeonid Yegoshin if (cpu_has_mmips) {
157134c2f668SLeonid Yegoshin emulate_load_store_microMIPS(regs,
157234c2f668SLeonid Yegoshin (void __user *)regs->cp0_badvaddr);
157334c2f668SLeonid Yegoshin return;
157434c2f668SLeonid Yegoshin }
157534c2f668SLeonid Yegoshin
1576451b001bSSteven J. Hill if (cpu_has_mips16) {
1577451b001bSSteven J. Hill emulate_load_store_MIPS16e(regs,
1578451b001bSSteven J. Hill (void __user *)regs->cp0_badvaddr);
1579451b001bSSteven J. Hill return;
1580451b001bSSteven J. Hill }
1581451b001bSSteven J. Hill
158234c2f668SLeonid Yegoshin goto sigbus;
158334c2f668SLeonid Yegoshin }
158434c2f668SLeonid Yegoshin
158534c2f668SLeonid Yegoshin if (unaligned_action == UNALIGNED_ACTION_SHOW)
158634c2f668SLeonid Yegoshin show_registers(regs);
15877cba4128SThomas Bogendoerfer pc = (unsigned int *)exception_epc(regs);
158834c2f668SLeonid Yegoshin
15897f18f151SRalf Baechle emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
15901da177e4SLinus Torvalds
15911da177e4SLinus Torvalds return;
15921da177e4SLinus Torvalds
15931da177e4SLinus Torvalds sigbus:
15941da177e4SLinus Torvalds die_if_kernel("Kernel unaligned instruction access", regs);
15953cf5d076SEric W. Biederman force_sig(SIGBUS);
15961da177e4SLinus Torvalds
15971da177e4SLinus Torvalds /*
15981da177e4SLinus Torvalds * XXX On return from the signal handler we should advance the epc
15991da177e4SLinus Torvalds */
1600c3fc5cd5SRalf Baechle exception_exit(prev_state);
16011da177e4SLinus Torvalds }
16026312e0eeSAtsushi Nemoto
16036312e0eeSAtsushi Nemoto #ifdef CONFIG_DEBUG_FS
debugfs_unaligned(void)16046312e0eeSAtsushi Nemoto static int __init debugfs_unaligned(void)
16056312e0eeSAtsushi Nemoto {
1606d8140426SGreg Kroah-Hartman debugfs_create_u32("unaligned_instructions", S_IRUGO, mips_debugfs_dir,
1607d8140426SGreg Kroah-Hartman &unaligned_instructions);
1608d8140426SGreg Kroah-Hartman debugfs_create_u32("unaligned_action", S_IRUGO | S_IWUSR,
16096312e0eeSAtsushi Nemoto mips_debugfs_dir, &unaligned_action);
16106312e0eeSAtsushi Nemoto return 0;
16116312e0eeSAtsushi Nemoto }
16128d6b591cSRalf Baechle arch_initcall(debugfs_unaligned);
16136312e0eeSAtsushi Nemoto #endif
1614