16b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt/*
26b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt * 'traps.c' handles hardware traps and faults after we have saved some
36b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt * state in 'entry.S'.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  SuperH version: Copyright (C) 1999 Niibe Yutaka
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                  Copyright (C) 2000 Philipp Rumpf
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                  Copyright (C) 2000 David Howells
8ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt *                  Copyright (C) 2002 - 2010 Paul Mundt
96b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt *
106b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt * This file is subject to the terms and conditions of the GNU General Public
116b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt * License.  See the file "COPYING" in the main directory of this archive
126b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt * for more details.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
16ba84be2338d3a2b6020d39279335bb06fcd332e1Russell King#include <linux/hardirq.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kallsyms.h>
211f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt#include <linux/io.h>
22fa69151173b1fc6fa3ced0edd5c2ea83b5d32bc1Paul Mundt#include <linux/bug.h>
239b8c90eb0d916f6802f8bbac79f61aca6ac533e8Paul Mundt#include <linux/debug_locks.h>
24b118ca572db5af832c6fc1af7b301105378d1a08Paul Mundt#include <linux/kdebug.h>
25e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt#include <linux/kexec.h>
26dc34d312c7b25d5d0f54c16d143a9526936e5d38Paul Mundt#include <linux/limits.h>
27af67c3a9e68ee0a9e30ee8582577408adba0e299Paul Mundt#include <linux/sysfs.h>
28a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt#include <linux/uaccess.h>
29ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt#include <linux/perf_event.h>
30a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt#include <asm/alignment.h>
31fad0f90134197259b5a935c69d7556ee847f242cAndrew Morton#include <asm/fpu.h>
32d39f5450146ff39f66cfde9d5184420627d0ac51Chris Smith#include <asm/kprobes.h>
33e839ca528718e68cad32a307dc9aabf01ef3eb05David Howells#include <asm/traps.h>
34e839ca528718e68cad32a307dc9aabf01ef3eb05David Howells#include <asm/bl_bit.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_SH2
370983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato# define TRAP_RESERVED_INST	4
380983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato# define TRAP_ILLEGAL_SLOT_INST	6
390983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato# define TRAP_ADDRESS_ERROR	9
400983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato# ifdef CONFIG_CPU_SH2A
41cd89436e54b29a07a383ee82f2f718d8c9d24cc4Peter Griffin#  define TRAP_UBC		12
426e80f5e8c4c685eb7bc34c3916e3d986b03f9981Yoshinori Sato#  define TRAP_FPU_ERROR	13
430983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#  define TRAP_DIVZERO_ERROR	17
440983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#  define TRAP_DIVOVF_ERROR	18
450983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato# endif
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TRAP_RESERVED_INST	12
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TRAP_ILLEGAL_SLOT_INST	13
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
516b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundtstatic void dump_mem(const char *str, unsigned long bottom, unsigned long top)
526b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt{
536b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	unsigned long p;
546b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	int i;
556b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
566b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
576b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
586b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	for (p = bottom & ~31; p < top; ) {
596b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		printk("%04lx: ", p & 0xffff);
606b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
616b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		for (i = 0; i < 8; i++, p += 4) {
626b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt			unsigned int val;
636b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
646b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt			if (p < bottom || p >= top)
656b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt				printk("         ");
666b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt			else {
676b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt				if (__get_user(val, (unsigned int __user *)p)) {
686b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt					printk("\n");
696b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt					return;
706b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt				}
716b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt				printk("%08x ", val);
726b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt			}
736b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		}
746b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		printk("\n");
756b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	}
766b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt}
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
783a2e117e220f000f95187ea1e1bbe83b0ed5fdfbPaul Mundtstatic DEFINE_SPINLOCK(die_lock);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid die(const char * str, struct pt_regs * regs, long err)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int die_counter;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
845527398218aae85f37552a69fad163fa500c39e4Paul Mundt	oops_enter();
855527398218aae85f37552a69fad163fa500c39e4Paul Mundt
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&die_lock);
87af67c3a9e68ee0a9e30ee8582577408adba0e299Paul Mundt	console_verbose();
886b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	bust_spinlocks(1);
896b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
916b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	print_modules();
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_regs(regs);
936b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
9419c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan	printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
9519c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan			task_pid_nr(current), task_stack_page(current) + 1);
966b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
976b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	if (!user_mode(regs) || in_interrupt())
986b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
99b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy			 (unsigned long)task_stack_page(current));
1006b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
101c9306f0efbfbe65a6e9212082f1d1fc19fdc3094Paul Mundt	notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
102c9306f0efbfbe65a6e9212082f1d1fc19fdc3094Paul Mundt
1036b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	bust_spinlocks(0);
104bcdcd8e725b923ad7c0de809680d5d5658a7bf8cPavel Emelianov	add_taint(TAINT_DIE);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&die_lock);
106af67c3a9e68ee0a9e30ee8582577408adba0e299Paul Mundt	oops_exit();
107e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt
108e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt	if (kexec_should_crash(current))
109e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt		crash_kexec(regs);
110e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt
111e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt	if (in_interrupt())
112e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt		panic("Fatal exception in interrupt");
113e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt
114e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt	if (panic_on_oops)
115e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt		panic("Fatal exception");
116e113276624104d9c3b25f333d8dd999b804d980aPaul Mundt
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_exit(SIGSEGV);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1206b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundtstatic inline void die_if_kernel(const char *str, struct pt_regs *regs,
1216b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt				 long err)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!user_mode(regs))
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		die(str, regs, err);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try and fix up kernelspace address errors
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - userspace errors just cause EFAULT to be returned, resulting in SEGV
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - kernel/userspace interfaces cause a jump to an appropriate handler
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - other kernel errors are bad
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1332afb447f33c29cb000a494396559f8005d3e33c1SUGIOKA Toshinobustatic void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1356b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	if (!user_mode(regs)) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		const struct exception_table_entry *fixup;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fixup = search_exception_tables(regs->pc);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fixup) {
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			regs->pc = fixup->fixup;
1402afb447f33c29cb000a494396559f8005d3e33c1SUGIOKA Toshinobu			return;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
142b344e24a8e8ceda83d1285d22e3e5baf4f5e42d3Matt Fleming
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		die(str, regs, err);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14786c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Dammstatic inline void sign_extend(unsigned int count, unsigned char *dst)
14886c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm{
14986c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#ifdef __LITTLE_ENDIAN__
1504252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm	if ((count == 1) && dst[0] & 0x80) {
1514252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm		dst[1] = 0xff;
1524252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm		dst[2] = 0xff;
1534252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm		dst[3] = 0xff;
1544252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm	}
15586c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm	if ((count == 2) && dst[1] & 0x80) {
15686c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm		dst[2] = 0xff;
15786c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm		dst[3] = 0xff;
15886c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm	}
15986c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#else
1604252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm	if ((count == 1) && dst[3] & 0x80) {
1614252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm		dst[2] = 0xff;
1624252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm		dst[1] = 0xff;
16386c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm		dst[0] = 0xff;
1644252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm	}
1654252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm	if ((count == 2) && dst[2] & 0x80) {
16686c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm		dst[1] = 0xff;
1674252c659a4e7f4260e4bdc87538578236c51ab2dMagnus Damm		dst[0] = 0xff;
16886c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm	}
16986c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#endif
17086c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm}
17186c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm
172e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Dammstatic struct mem_access user_mem_access = {
173e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm	copy_from_user,
174e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm	copy_to_user,
175e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm};
176e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle an instruction that does an unaligned memory access by emulating the
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * desired behaviour
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - note that PC _may not_ point to the faulting instruction
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (if that instruction is in a branch delay slot)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - return 0 if emulation okay, -EFAULT on existential error
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1842bcfffa42309b6f73042c62459bf5207762a271dPaul Mundtstatic int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
185e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm				struct mem_access *ma)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret, index, count;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *rm, *rn;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *src, *dst;
190fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt	unsigned char __user *srcu, *dstu;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = (instruction>>8)&15;	/* 0x0F00 */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rn = &regs->regs[index];
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = (instruction>>4)&15;	/* 0x00F0 */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rm = &regs->regs[index];
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = 1<<(instruction&3);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2007436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik	switch (count) {
201a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt	case 1: inc_unaligned_byte_access(); break;
202a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt	case 2: inc_unaligned_word_access(); break;
203a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt	case 4: inc_unaligned_dword_access(); break;
204a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt	case 8: inc_unaligned_multi_access(); break;
2057436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik	}
2067436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -EFAULT;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (instruction>>12) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0: /* mov.[bwl] to/from memory via r0+rn */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (instruction & 8) {
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* from memory */
212fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			srcu = (unsigned char __user *)*rm;
213fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			srcu += regs->regs[0];
214fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			dst = (unsigned char *)rn;
215fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			*(unsigned long *)dst = 0;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21786c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#if !defined(__LITTLE_ENDIAN__)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dst += 4-count;
21986c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#endif
220fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			if (ma->from(dst, srcu, count))
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fetch_fault;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22386c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm			sign_extend(count, dst);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* to memory */
226fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			src = (unsigned char *)rm;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__LITTLE_ENDIAN__)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			src += 4-count;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
230fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			dstu = (unsigned char __user *)*rn;
231fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			dstu += regs->regs[0];
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
233fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			if (ma->to(dstu, src, count))
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fetch_fault;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1: /* mov.l Rm,@(disp,Rn) */
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src = (unsigned char*) rm;
241fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		dstu = (unsigned char __user *)*rn;
242fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		dstu += (instruction&0x000F)<<2;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		if (ma->to(dstu, src, 4))
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fetch_fault;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
247b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		break;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (instruction & 4)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rn -= count;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src = (unsigned char*) rm;
253fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		dstu = (unsigned char __user *)*rn;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__LITTLE_ENDIAN__)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		src += 4-count;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
257fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		if (ma->to(dstu, src, count))
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fetch_fault;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 5: /* mov.l @(disp,Rm),Rn */
263fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		srcu = (unsigned char __user *)*rm;
264fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		srcu += (instruction & 0x000F) << 2;
265fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		dst = (unsigned char *)rn;
266fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		*(unsigned long *)dst = 0;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		if (ma->from(dst, srcu, 4))
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fetch_fault;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
271b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		break;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 6:	/* mov.[bwl] from memory, possibly with post-increment */
274fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		srcu = (unsigned char __user *)*rm;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (instruction & 4)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*rm += count;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dst = (unsigned char*) rn;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*(unsigned long*)dst = 0;
279b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy
28086c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#if !defined(__LITTLE_ENDIAN__)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dst += 4-count;
28286c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm#endif
283fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		if (ma->from(dst, srcu, count))
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fetch_fault;
28586c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm		sign_extend(count, dst);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch ((instruction&0xFF00)>>8) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x81: /* mov.w R0,@(disp,Rn) */
292fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			src = (unsigned char *) &regs->regs[0];
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__LITTLE_ENDIAN__)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			src += 2;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
296fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			dstu = (unsigned char __user *)*rm; /* called Rn in the spec */
297fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			dstu += (instruction & 0x000F) << 1;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
299fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			if (ma->to(dstu, src, 2))
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fetch_fault;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = 0;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x85: /* mov.w @(disp,Rm),R0 */
305fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			srcu = (unsigned char __user *)*rm;
306fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			srcu += (instruction & 0x000F) << 1;
307fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			dst = (unsigned char *) &regs->regs[0];
308fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			*(unsigned long *)dst = 0;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__LITTLE_ENDIAN__)
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dst += 2;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
313fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt			if (ma->from(dst, srcu, 2))
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fetch_fault;
31586c0179c9307bd600a96a44d623814c33bdbe0f0Magnus Damm			sign_extend(2, dst);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = 0;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
32034f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
32134f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy	case 9: /* mov.w @(disp,PC),Rn */
32234f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		srcu = (unsigned char __user *)regs->pc;
32334f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		srcu += 4;
32434f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		srcu += (instruction & 0x00FF) << 1;
32534f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		dst = (unsigned char *)rn;
32634f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		*(unsigned long *)dst = 0;
32734f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
32834f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy#if !defined(__LITTLE_ENDIAN__)
32934f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		dst += 2;
33034f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy#endif
33134f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
33234f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		if (ma->from(dst, srcu, 2))
33334f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy			goto fetch_fault;
33434f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		sign_extend(2, dst);
33534f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		ret = 0;
33634f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		break;
33734f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
33834f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy	case 0xd: /* mov.l @(disp,PC),Rn */
33934f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		srcu = (unsigned char __user *)(regs->pc & ~0x3);
34034f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		srcu += 4;
34134f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		srcu += (instruction & 0x00FF) << 2;
34234f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		dst = (unsigned char *)rn;
34334f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		*(unsigned long *)dst = 0;
34434f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
34534f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		if (ma->from(dst, srcu, 4))
34634f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy			goto fetch_fault;
34734f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		ret = 0;
34834f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		break;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fetch_fault:
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Argh. Address not only misaligned but also non-existent.
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Raise an EFAULT and see if it's trapped
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3562afb447f33c29cb000a494396559f8005d3e33c1SUGIOKA Toshinobu	die_if_no_fixup("Fault in unaligned fixup", regs, 0);
3572afb447f33c29cb000a494396559f8005d3e33c1SUGIOKA Toshinobu	return -EFAULT;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * emulate the instruction in the delay slot
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - fetches the instruction from PC+2
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
364e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Dammstatic inline int handle_delayslot(struct pt_regs *regs,
3652bcfffa42309b6f73042c62459bf5207762a271dPaul Mundt				   insn_size_t old_instruction,
366e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm				   struct mem_access *ma)
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3682bcfffa42309b6f73042c62459bf5207762a271dPaul Mundt	insn_size_t instruction;
369fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt	void __user *addr = (void __user *)(regs->pc +
370fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		instruction_size(old_instruction));
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3724b5a9ef5279aed2c34d92fee62cf6d0c6ffacbaaMagnus Damm	if (copy_from_user(&instruction, addr, sizeof(instruction))) {
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* the instruction-fetch faulted */
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (user_mode(regs))
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* kernel */
378b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		die("delay-slot-insn faulting in handle_unaligned_delayslot",
379b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		    regs, 0);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
382e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm	return handle_unaligned_ins(instruction, regs, ma);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle an instruction that does an unaligned memory access
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - have to be careful of branch delay-slot instructions that fault
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  SH3:
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - if the branch would be taken PC points to the branch
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - if the branch would not be taken, PC points to delay-slot
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  SH4:
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - PC always points to delayed branch
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Macros to determine offset from current PC for branch instructions */
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Explicit type coercion is used to force sign extension where needed */
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4012bcfffa42309b6f73042c62459bf5207762a271dPaul Mundtint handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
402ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt			    struct mem_access *ma, int expected,
403ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt			    unsigned long address)
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int rm;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret, index;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40823c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt	/*
40923c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt	 * XXX: We can't handle mixed 16/32-bit instructions yet
41023c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt	 */
41123c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt	if (instruction_size(instruction) != 2)
41223c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt		return -EINVAL;
41323c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	index = (instruction>>8)&15;	/* 0x0F00 */
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rm = regs->regs[index];
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
417ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	/*
418ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	 * Log the unexpected fixups, and then pass them on to perf.
419ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	 *
420ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	 * We intentionally don't report the expected cases to perf as
421ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	 * otherwise the trapped I/O case will skew the results too much
422ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	 * to be useful.
423ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	 */
424ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	if (!expected) {
425a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		unaligned_fixups_notify(current, instruction, regs);
426a8b0ca17b80e92faab46ee7179ba9e99ccb61233Peter Zijlstra		perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1,
427ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt			      regs, address);
428ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt	}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -EFAULT;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (instruction&0xF000) {
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0000:
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (instruction==0x000B) {
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* rts */
435e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pc = regs->pr;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if ((instruction&0x00FF)==0x0023) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* braf @Rm */
441e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0)
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pc += rm + 4;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if ((instruction&0x00FF)==0x0003) {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* bsrf @Rm */
447e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0) {
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pr = regs->pc + 4;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pc += rm + 4;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* mov.[bwl] to/from memory via r0+rn */
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto simple;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x1000: /* mov.l Rm,@(disp,Rn) */
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto simple;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto simple;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x4000:
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((instruction&0x00FF)==0x002B) {
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* jmp @Rm */
468e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pc = rm;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if ((instruction&0x00FF)==0x000B) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* jsr @Rm */
474e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0) {
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pr = regs->pc + 4;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				regs->pc = rm;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* mov.[bwl] to/from memory via r0+rn */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto simple;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x5000: /* mov.l @(disp,Rm),Rn */
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto simple;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto simple;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (instruction&0x0F00) {
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0100: /* mov.w R0,@(disp,Rm) */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto simple;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0500: /* mov.w @(disp,Rm),R0 */
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto simple;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0B00: /* bf   lab - no delayslot*/
4990710b91c516ffd448db6e80e9026f11778a80d45Phil Edworthy			ret = 0;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0F00: /* bf/s lab */
502e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0) {
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((regs->sr & 0x00000001) != 0)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					regs->pc += 4; /* next after slot */
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					regs->pc += SH_PC_8BIT_OFFSET(instruction);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0900: /* bt   lab - no delayslot */
5130710b91c516ffd448db6e80e9026f11778a80d45Phil Edworthy			ret = 0;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0D00: /* bt/s lab */
516e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm			ret = handle_delayslot(regs, instruction, ma);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret==0) {
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((regs->sr & 0x00000001) == 0)
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					regs->pc += 4; /* next after slot */
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					regs->pc += SH_PC_8BIT_OFFSET(instruction);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52934f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy	case 0x9000: /* mov.w @(disp,Rm),Rn */
53034f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		goto simple;
53134f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xA000: /* bra label */
533e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm		ret = handle_delayslot(regs, instruction, ma);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret==0)
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			regs->pc += SH_PC_12BIT_OFFSET(instruction);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0xB000: /* bsr label */
539e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm		ret = handle_delayslot(regs, instruction, ma);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret==0) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			regs->pr = regs->pc + 4;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			regs->pc += SH_PC_12BIT_OFFSET(instruction);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
54534f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy
54634f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy	case 0xD000: /* mov.l @(disp,Rm),Rn */
54734f7145a63211eb7ecfcafa6c2a8db5646baf953Phil Edworthy		goto simple;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* handle non-delay-slot instruction */
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simple:
553e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm	ret = handle_unaligned_ins(instruction, regs, ma);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret==0)
55553f983a90d7908bcece51f86180c7c9b575a1e4dPaul Mundt		regs->pc += instruction_size(instruction);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
560b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy * Handle various address error exceptions:
561b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy *  - instruction address error:
562b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy *       misaligned PC
563b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy *       PC >= 0x80000000 in user mode
564b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy *  - data address error (read and write)
565b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy *       misaligned data access
566b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy *       access to >= 0x80000000 is user mode
567b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy * Unfortuntaly we can't distinguish between instruction address error
568e868d61272caa648214046a096e5a6bfc068dc8cSimon Arlott * and data address errors caused by read accesses.
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
570f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefyasmlinkage void do_address_error(struct pt_regs *regs,
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 unsigned long writeaccess,
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 unsigned long address)
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5740983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	unsigned long error_code = 0;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mm_segment_t oldfs;
576b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy	siginfo_t info;
5772bcfffa42309b6f73042c62459bf5207762a271dPaul Mundt	insn_size_t instruction;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tmp;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5800983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	/* Intentional ifdef */
5810983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#ifdef CONFIG_CPU_HAS_SR_RB
5824c59e2942e92d2d776bcd038604a5c3c1d56d3acPaul Mundt	error_code = lookup_exception_vector();
5830983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#endif
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oldfs = get_fs();
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (user_mode(regs)) {
588b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		int si_code = BUS_ADRERR;
589a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		unsigned int user_action;
590b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq_enable();
592a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		inc_unaligned_user_access();
5937436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik
5945a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik		set_fs(USER_DS);
59523c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt		if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1),
59623c4c82171008c8b18d8627c9741cdd577631ceaPaul Mundt				   sizeof(instruction))) {
5975a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik			set_fs(oldfs);
5985a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik			goto uspace_segv;
5995a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik		}
6005a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik		set_fs(oldfs);
6015a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik
6027436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik		/* shout about userspace fixups */
603a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		unaligned_fixups_notify(current, instruction, regs);
6047436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik
605a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		user_action = unaligned_user_action();
606a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		if (user_action & UM_FIXUP)
6077436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik			goto fixup;
608a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		if (user_action & UM_SIGNAL)
6097436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik			goto uspace_segv;
6107436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik		else {
6117436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik			/* ignore */
6125a0ab35e43a6e3c69893c0091fe6a78ea8b3e443Andre Draszik			regs->pc += instruction_size(instruction);
6137436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik			return;
6147436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik		}
6157436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik
6167436cde6b2ca71049051620c68c26522bb3403bfAndre Draszikfixup:
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* bad PC is not something we can fix */
618b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		if (regs->pc & 1) {
619b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy			si_code = BUS_ADRALN;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto uspace_segv;
621b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_fs(USER_DS);
624e7cc9a7340b8ec018caa9eb1d035fdaef1f2fc51Magnus Damm		tmp = handle_unaligned_access(instruction, regs,
625ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt					      &user_mem_access, 0,
626ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt					      address);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_fs(oldfs);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
629a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		if (tmp == 0)
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return; /* sorted */
631b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefyuspace_segv:
632b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
633b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		       "access (PC %lx PR %lx)\n", current->comm, regs->pc,
634b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		       regs->pr);
635b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy
636b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		info.si_signo = SIGBUS;
637b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		info.si_errno = 0;
638b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		info.si_code = si_code;
639e08f457c7c0cc7720f28349f8780ea752c063441Paul Mundt		info.si_addr = (void __user *)address;
640b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy		force_sig_info(SIGBUS, &info, current);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
642a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		inc_unaligned_kernel_access();
6437436cde6b2ca71049051620c68c26522bb3403bfAndre Draszik
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regs->pc & 1)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			die("unaligned program counter", regs, error_code);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_fs(KERNEL_DS);
648fa43972fab24a3c050e880a7831f9378c6cebc0bPaul Mundt		if (copy_from_user(&instruction, (void __user *)(regs->pc),
6494b5a9ef5279aed2c34d92fee62cf6d0c6ffacbaaMagnus Damm				   sizeof(instruction))) {
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Argh. Fault on the instruction itself.
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   This should never happen non-SMP
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*/
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_fs(oldfs);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			die("insn faulting in do_address_error", regs, 0);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
657a99eae5417a09e0be66bf574a9a79a2a7388c967Paul Mundt		unaligned_fixups_notify(current, instruction, regs);
65840258ee97d0d5e5c30a3d4b7acaf294fe82cd23fPaul Mundt
659ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt		handle_unaligned_access(instruction, regs, &user_mem_access,
660ace2dc7d12693545b67f15ab8cdb3d255c937713Paul Mundt					0, address);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_fs(oldfs);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SH_DSP
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	SH-DSP support gerg@snapgear.com.
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint is_dsp_inst(struct pt_regs *regs)
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
671882c12c4e1a95e55227f06dbb99eca90f237c018Paul Mundt	unsigned short inst = 0;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
673f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	/*
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Safe guard if DSP mode is already enabled or we're lacking
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the DSP altogether.
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
67711c1965687b0a472add948d4240dfe65a2fcb298Paul Mundt	if (!(current_cpu_data.flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	get_user(inst, ((unsigned short *) regs->pc));
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inst &= 0xf000;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check for any type of DSP or support instruction */
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((inst == 0xf000) || (inst == 0x4000))
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_dsp_inst(regs)	(0)
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SH_DSP */
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6940983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#ifdef CONFIG_CPU_SH2A
6950983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Satoasmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
6960983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato				unsigned long r6, unsigned long r7,
697f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy				struct pt_regs __regs)
6980983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato{
6990983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	siginfo_t info;
7000983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
7010983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	switch (r4) {
7020983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	case TRAP_DIVZERO_ERROR:
7030983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato		info.si_code = FPE_INTDIV;
7040983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato		break;
7050983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	case TRAP_DIVOVF_ERROR:
7060983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato		info.si_code = FPE_INTOVF;
7070983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato		break;
7080983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	}
7090983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
7100983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	force_sig_info(SIGFPE, &info, current);
7110983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato}
7120983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#endif
7130983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
7144b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHIIasmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
7154b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII				unsigned long r6, unsigned long r7,
716f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy				struct pt_regs __regs)
7174b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII{
718f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
7194b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	unsigned long error_code;
7204b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	struct task_struct *tsk = current;
7214b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
7224b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#ifdef CONFIG_SH_FPU_EMU
7230983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	unsigned short inst = 0;
7244b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	int err;
7254b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
726f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	get_user(inst, (unsigned short*)regs->pc);
7274b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
728f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	err = do_fpu_inst(inst, regs);
7294b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	if (!err) {
73053f983a90d7908bcece51f86180c7c9b575a1e4dPaul Mundt		regs->pc += instruction_size(inst);
7314b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return;
7324b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7334b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	/* not a FPU inst. */
7344b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#endif
7354b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
7364b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#ifdef CONFIG_SH_DSP
7374b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	/* Check if it's a DSP instruction */
738b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy	if (is_dsp_inst(regs)) {
7394b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		/* Enable DSP mode, and restart instruction. */
740f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy		regs->sr |= SR_DSP;
74101ab10393c510342ec4ce85df11ccfa3df06bbb2Michael Trimarchi		/* Save DSP mode */
74201ab10393c510342ec4ce85df11ccfa3df06bbb2Michael Trimarchi		tsk->thread.dsp_status.status |= SR_DSP;
7434b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return;
7444b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7454b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#endif
7464b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
7474c59e2942e92d2d776bcd038604a5c3c1d56d3acPaul Mundt	error_code = lookup_exception_vector();
7480983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
7494b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	local_irq_enable();
7504b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	force_sig(SIGILL, tsk);
751f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	die_if_no_fixup("reserved instruction", regs, error_code);
7524b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII}
7534b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
7544b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#ifdef CONFIG_SH_FPU_EMU
755edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundtstatic int emulate_branch(unsigned short inst, struct pt_regs *regs)
7564b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII{
7574b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	/*
7584b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * bfs: 8fxx: PC+=d*2+4;
7594b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * bts: 8dxx: PC+=d*2+4;
7604b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * bra: axxx: PC+=D*2+4;
7614b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * bsr: bxxx: PC+=D*2+4  after PR=PC+4;
7624b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * braf:0x23: PC+=Rn*2+4;
7634b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
7644b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * jmp: 4x2b: PC=Rn;
7654b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * jsr: 4x0b: PC=Rn      after PR=PC+4;
7664b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * rts: 000b: PC=PR;
7674b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 */
768edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	if (((inst & 0xf000) == 0xb000)  ||	/* bsr */
769edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	    ((inst & 0xf0ff) == 0x0003)  ||	/* bsrf */
770edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	    ((inst & 0xf0ff) == 0x400b))	/* jsr */
771edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt		regs->pr = regs->pc + 4;
772edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt
773edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	if ((inst & 0xfd00) == 0x8d00) {	/* bfs, bts */
7744b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		regs->pc += SH_PC_8BIT_OFFSET(inst);
7754b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return 0;
7764b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7774b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
778edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	if ((inst & 0xe000) == 0xa000) {	/* bra, bsr */
7794b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		regs->pc += SH_PC_12BIT_OFFSET(inst);
7804b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return 0;
7814b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7824b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
783edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	if ((inst & 0xf0df) == 0x0003) {	/* braf, bsrf */
7844b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
7854b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return 0;
7864b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7874b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
788edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	if ((inst & 0xf0df) == 0x400b) {	/* jmp, jsr */
7894b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		regs->pc = regs->regs[(inst & 0x0f00) >> 8];
7904b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return 0;
7914b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7924b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
793edfd6da0405520b147ab1473ad183a5b32be7082Paul Mundt	if ((inst & 0xffff) == 0x000b) {	/* rts */
7944b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		regs->pc = regs->pr;
7954b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		return 0;
7964b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
7974b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
7984b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	return 1;
7994b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII}
8004b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#endif
8014b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
8024b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHIIasmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
8034b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII				unsigned long r6, unsigned long r7,
804f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy				struct pt_regs __regs)
8054b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII{
806f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
807b3d765f5df5707e2b3676768b6877db5d8db76a2Paul Mundt	unsigned long inst;
8084b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	struct task_struct *tsk = current;
809d39f5450146ff39f66cfde9d5184420627d0ac51Chris Smith
810d39f5450146ff39f66cfde9d5184420627d0ac51Chris Smith	if (kprobe_handle_illslot(regs->pc) == 0)
811d39f5450146ff39f66cfde9d5184420627d0ac51Chris Smith		return;
812d39f5450146ff39f66cfde9d5184420627d0ac51Chris Smith
8134b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#ifdef CONFIG_SH_FPU_EMU
814f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	get_user(inst, (unsigned short *)regs->pc + 1);
815f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	if (!do_fpu_inst(inst, regs)) {
816f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy		get_user(inst, (unsigned short *)regs->pc);
817f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy		if (!emulate_branch(inst, regs))
8184b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII			return;
8194b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII		/* fault in branch.*/
8204b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	}
8214b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	/* not a FPU inst. */
8224b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#endif
8234b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII
8244c59e2942e92d2d776bcd038604a5c3c1d56d3acPaul Mundt	inst = lookup_exception_vector();
8250983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
8264b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	local_irq_enable();
8274b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	force_sig(SIGILL, tsk);
828b3d765f5df5707e2b3676768b6877db5d8db76a2Paul Mundt	die_if_no_fixup("illegal slot instruction", regs, inst);
8294b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII}
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   unsigned long r6, unsigned long r7,
833f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy				   struct pt_regs __regs)
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
835f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long ex;
8370983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
8384c59e2942e92d2d776bcd038604a5c3c1d56d3acPaul Mundt	ex = lookup_exception_vector();
839f0bc814cfbc212683c882e58b3d1afec6b3e3aa3Stuart Menefy	die_if_kernel("exception", regs, ex);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
842aba1030a7e529ec9fe47a8cfc06d12a39180fa71Paul Mundtvoid __cpuinit per_cpu_trap_init(void)
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	extern void *vbr_base;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NOTE: The VBR value should be at P1
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   (or P2, virtural "fixed" address space).
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   It's definitely should not in physical address.  */
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	asm volatile("ldc	%0, vbr"
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     : /* no output */
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     : "r" (&vbr_base)
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     : "memory");
85468a1aed7039e5a94a8e60e23fdf676738c36086aMagnus Damm
85568a1aed7039e5a94a8e60e23fdf676738c36086aMagnus Damm	/* disable exception blocking now when the vbr has been setup */
85668a1aed7039e5a94a8e60e23fdf676738c36086aMagnus Damm	clear_bl_bit();
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundtvoid *set_exception_table_vec(unsigned int vec, void *handler)
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	extern void *exception_handling_table[];
8621f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	void *old_handler;
863b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy
8641f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	old_handler = exception_handling_table[vec];
8651f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	exception_handling_table[vec] = handler;
8661f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	return old_handler;
8671f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt}
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundtvoid __init trap_init(void)
8701f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt{
8711f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
8721f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	set_exception_table_vec(TRAP_ILLEGAL_SLOT_INST, do_illegal_slot_inst);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8744b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
8754b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII    defined(CONFIG_SH_FPU_EMU)
8764b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	/*
8774b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * For SH-4 lacking an FPU, treat floating point instructions as
8784b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * reserved. They'll be handled in the math-emu case, or faulted on
8794b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 * otherwise.
8804b565680d16300acab0ff167e24f0ea289a6bd5dTakashi YOSHII	 */
8811f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	set_exception_table_evt(0x800, do_reserved_inst);
8821f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt	set_exception_table_evt(0x820, do_illegal_slot_inst);
8831f666587dbf6bc660b23d8dd8abb6c572ce3eae5Paul Mundt#elif defined(CONFIG_SH_FPU)
88474d99a5e262229ee865f6f68528d10b82471ead6Paul Mundt	set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
88574d99a5e262229ee865f6f68528d10b82471ead6Paul Mundt	set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8870983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato
8880983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#ifdef CONFIG_CPU_SH2
8895a4f7c66be981c6b5f44a4d66a14ea6ac9b7b6b0Paul Mundt	set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
8900983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#endif
8910983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#ifdef CONFIG_CPU_SH2A
8920983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
8930983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato	set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
8946e80f5e8c4c685eb7bc34c3916e3d986b03f9981Yoshinori Sato#ifdef CONFIG_SH_FPU
8956e80f5e8c4c685eb7bc34c3916e3d986b03f9981Yoshinori Sato	set_exception_table_vec(TRAP_FPU_ERROR, fpu_error_trap_handler);
8966e80f5e8c4c685eb7bc34c3916e3d986b03f9981Yoshinori Sato#endif
8970983b31849bbe1fe82520947acc1bec97c457d4bYoshinori Sato#endif
898b5a1bcbee434b843c8850a968d9a6c7541f1be9dStuart Menefy
899cd89436e54b29a07a383ee82f2f718d8c9d24cc4Peter Griffin#ifdef TRAP_UBC
900c4761815ab49feca904776dec464046bc7138d3aPaul Mundt	set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
901cd89436e54b29a07a383ee82f2f718d8c9d24cc4Peter Griffin#endif
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9046b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundtvoid show_stack(struct task_struct *tsk, unsigned long *sp)
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9066b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	unsigned long stack;
9076b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
9086b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	if (!tsk)
9096b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		tsk = current;
9106b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	if (tsk == current)
9116b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		sp = (unsigned long *)current_stack_pointer;
9126b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	else
9136b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		sp = (unsigned long *)tsk->thread.sp;
9146b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt
9156b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	stack = (unsigned long)sp;
9166b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	dump_mem("Stack: ", stack, THREAD_SIZE +
9176b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt		 (unsigned long)task_stack_page(tsk));
9186b0022305f80cf249de69e746f6f5ccf7ffc5b7cPaul Mundt	show_trace(tsk, sp, NULL);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dump_stack(void)
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_stack(NULL, NULL);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dump_stack);
926