11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* traps.c: high-level exception handler for FR-V
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by David Howells (dhowells@redhat.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/user.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/linkage.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
21402344012ebe696d9353bbf056889ddaaec83079David Howells#include <linux/module.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2384e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells#include <asm/asm-offsets.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/fpu.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/siginfo.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid show_backtrace(struct pt_regs *, unsigned long);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern asmlinkage void __break_hijack_kernel_event(void);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instruction access error
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Insn Access Error --\n"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "EPCR0 : %08lx\n"
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR0  : %08lx\n",
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      epcr0, esr0);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_signo	= SIGSEGV;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code	= SEGV_ACCERR;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno	= 0;
51ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	info.si_addr	= (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(info.si_signo, &info, current);
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end insn_access_error() */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handler for:
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - illegal instruction
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - privileged instruction
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - unsupported trap
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - debug exceptions
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Illegal Instruction --\n"
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "EPCR0 : %08lx\n"
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR0  : %08lx\n"
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESFR1 : %08lx\n",
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      epcr0, esr0, esfr1);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno	= 0;
75ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	info.si_addr	= (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (__frame->tbr & TBR_TT) {
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TBR_TT_ILLEGAL_INSTR:
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_signo	= SIGILL;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_code	= ILL_ILLOPC;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TBR_TT_PRIV_INSTR:
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_signo	= SIGILL;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_code	= ILL_PRVOPC;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TBR_TT_TRAP2 ... TBR_TT_TRAP126:
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_signo	= SIGILL;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_code	= ILL_ILLTRP;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* GDB uses "tira gr0, #1" as a breakpoint instruction.  */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TBR_TT_TRAP1:
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TBR_TT_BREAK:
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_signo	= SIGTRAP;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info.si_code	=
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(__frame->__status & REG__STATUS_STEPPED) ? TRAP_TRACE : TRAP_BRKPT;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(info.si_signo, &info, current);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end illegal_instruction() */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
104e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells * handle atomic operations with errors
105e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells * - arguments in gr8, gr9, gr10
106e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells * - original memory value placed in gr5
107e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells * - replacement memory value placed in gr9
108e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells */
109e31c243f984628d02f045dc4b622f1e2827860dcDavid Howellsasmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
110e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				 unsigned long esr0)
111e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells{
112e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	static DEFINE_SPINLOCK(atomic_op_lock);
113ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	unsigned long x, y, z;
114ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	unsigned long __user *p;
115e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	mm_segment_t oldfs;
116e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	siginfo_t info;
117e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	int ret;
118e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
119e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	y = 0;
120e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	z = 0;
121e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
122e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	oldfs = get_fs();
123e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	if (!user_mode(__frame))
124e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		set_fs(KERNEL_DS);
125e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
126e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	switch (__frame->tbr & TBR_TT) {
127e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#120
128e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
129e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
130e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_CMPXCHG32:
131ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
132e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		x = __frame->gr9;
133e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		y = __frame->gr10;
134e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
135e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
136e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
137e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
138e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
139e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
140e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (z != x)
141e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto done;
142e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
143e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
144e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
145e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
146e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (z != x)
147e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
148e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
149e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
150e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
151e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
152e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
153e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
154e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
155e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
156e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
157e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#121
158e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * u32 __atomic_kernel_xchg32(void *v, u32 new)
159e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
160e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_XCHG32:
161ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
162e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		y = __frame->gr9;
163e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
164e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
165e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
166e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
167e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
168e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
169e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
170e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
171e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
172e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
173e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
174e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
175e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
176e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
177e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
178e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
179e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
180e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#122
181e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
182e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
183e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_XOR:
184ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
185e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		x = __frame->gr9;
186e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
187e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
188e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
189e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
190e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
191e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
192e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
193e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
194e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
195e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				y = x ^ z;
196e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
197e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
198e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
199e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
200e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
201e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
202e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
203e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
204e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#123
205e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * ulong __atomic_kernel_OR_return(ulong i, ulong *v)
206e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
207e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_OR:
208ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
209e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		x = __frame->gr9;
210e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
211e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
212e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
213e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
214e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
215e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
216e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
217e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
218e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
219e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				y = x ^ z;
220e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
221e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
222e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
223e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
224e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
225e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
226e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
227e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
228e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#124
229e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * ulong __atomic_kernel_AND_return(ulong i, ulong *v)
230e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
231e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_AND:
232ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
233e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		x = __frame->gr9;
234e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
235e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
236e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
237e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
238e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
239e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
240e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
241e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
242e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
243e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				y = x & z;
244e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
245e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
246e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
247e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
248e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
249e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
250e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
251e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
252e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#125
253e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * int __atomic_user_sub_return(atomic_t *v, int i)
254e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
255e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_SUB:
256ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
257e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		x = __frame->gr9;
258e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
259e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
260e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
261e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
262e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
263e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
264e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
265e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
266e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
267e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				y = z - x;
268e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
269e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
270e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
271e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
272e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
273e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
274e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
275e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
276e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		/* TIRA gr0,#126
277e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 * int __atomic_user_add_return(atomic_t *v, int i)
278e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		 */
279e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	case TBR_TT_ATOMIC_ADD:
280ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		p = (unsigned long __user *) __frame->gr8;
281e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		x = __frame->gr9;
282e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
283e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		for (;;) {
284e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			ret = get_user(z, p);
285e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (ret < 0)
286e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error;
287e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
288e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_lock_irq(&atomic_op_lock);
289e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
290e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			if (__get_user(z, p) == 0) {
291e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				y = z + x;
292e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				if (__put_user(y, p) == 0)
293e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells					goto done2;
294e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells				goto error2;
295e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			}
296e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
297e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells			spin_unlock_irq(&atomic_op_lock);
298e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		}
299e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
300e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	default:
301e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		BUG();
302e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	}
303e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
304e31c243f984628d02f045dc4b622f1e2827860dcDavid Howellsdone2:
305e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	spin_unlock_irq(&atomic_op_lock);
306e31c243f984628d02f045dc4b622f1e2827860dcDavid Howellsdone:
307e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	if (!user_mode(__frame))
308e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		set_fs(oldfs);
309e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	__frame->gr5 = z;
310e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	__frame->gr9 = y;
311e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	return;
312e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
313e31c243f984628d02f045dc4b622f1e2827860dcDavid Howellserror2:
314e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	spin_unlock_irq(&atomic_op_lock);
315e31c243f984628d02f045dc4b622f1e2827860dcDavid Howellserror:
316e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	if (!user_mode(__frame))
317e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells		set_fs(oldfs);
318e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	__frame->pc -= 4;
319e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
320e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	die_if_kernel("-- Atomic Op Error --\n");
321e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
322e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	info.si_signo	= SIGSEGV;
323e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	info.si_code	= SEGV_ACCERR;
324e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	info.si_errno	= 0;
325ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	info.si_addr	= (void __user *) __frame->pc;
326e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
327e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells	force_sig_info(info.si_signo, &info, current);
328e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells}
329e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells
330e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells/*****************************************************************************/
331e31c243f984628d02f045dc4b622f1e2827860dcDavid Howells/*
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Media Exception --\n"
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "MSR0 : %08lx\n"
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "MSR1 : %08lx\n",
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      msr0, msr1);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_signo	= SIGFPE;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code	= FPE_MDAOVF;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno	= 0;
346ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	info.si_addr	= (void __user *) __frame->pc;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(info.si_signo, &info, current);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end media_exception() */
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instruction or data access exception
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void memory_access_exception(unsigned long esr0,
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unsigned long ear0,
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					unsigned long epcr0)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MMU
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long fixup;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3646510d41954dc6a9c8b1dbca7eaca0f23195ca727Harvey Harrison	fixup = search_exception_table(__frame->pc);
3656510d41954dc6a9c8b1dbca7eaca0f23195ca727Harvey Harrison	if (fixup) {
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__frame->pc = fixup;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Memory Access Exception --\n"
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR0  : %08lx\n"
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "EAR0  : %08lx\n"
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "EPCR0 : %08lx\n",
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      esr0, ear0, epcr0);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_signo	= SIGSEGV;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code	= SEGV_ACCERR;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno	= 0;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_addr	= NULL;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
383ff471b2464ca7344eba347d360f23ea415a774dcAl Viro		info.si_addr = (void __user *) ear0;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(info.si_signo, &info, current);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end memory_access_exception() */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data access error
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - double-word data load from CPU control area (0xFExxxxxx)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - read performed on inactive or self-refreshing SDRAM
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - error notification from slave device
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - misaligned address
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - access to out of bounds memory region
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - user mode accessing privileged memory region
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - write to R/O memory region
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Data Access Error --\n"
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR15 : %08lx\n"
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "EAR15 : %08lx\n",
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      esr15, ear15);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_signo	= SIGSEGV;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code	= SEGV_ACCERR;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno	= 0;
412ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	info.si_addr	= (void __user *)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(info.si_signo, &info, current);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end data_access_error() */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data store error - should only happen if accessing inactive or self-refreshing SDRAM
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Data Store Error --\n"
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR15 : %08lx\n",
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      esr15);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG();
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end data_store_error() */
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	siginfo_t info;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Division Exception --\n"
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR0 : %08lx\n"
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ISR  : %08lx\n",
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      esr0, isr);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_signo	= SIGFPE;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_code	= FPE_INTDIV;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info.si_errno	= 0;
446ff471b2464ca7344eba347d360f23ea415a774dcAl Viro	info.si_addr	= (void __user *) __frame->pc;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig_info(info.si_signo, &info, current);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end division_exception() */
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void compound_exception(unsigned long esfr1,
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   unsigned long esr0, unsigned long esr14, unsigned long esr15,
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   unsigned long msr0, unsigned long msr1)
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	die_if_kernel("-- Compound Exception --\n"
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR0  : %08lx\n"
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR15 : %08lx\n"
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "ESR15 : %08lx\n"
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "MSR0  : %08lx\n"
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      "MSR1  : %08lx\n",
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      esr0, esr14, esr15, msr0, msr1);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG();
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end compound_exception() */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The architecture-independent backtrace generator
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dump_stack(void)
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_stack(NULL, NULL);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
478402344012ebe696d9353bbf056889ddaaec83079David HowellsEXPORT_SYMBOL(dump_stack);
479402344012ebe696d9353bbf056889ddaaec83079David Howells
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid show_stack(struct task_struct *task, unsigned long *sp)
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid show_trace_task(struct task_struct *tsk)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *regnames[] = {
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"PSR ", "ISR ", "CCR ", "CCCR",
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"LR  ", "LCR ", "PC  ", "_stt",
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"sys ", "GR8*", "GNE0", "GNE1",
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"IACH", "IACL",
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"TBR ", "SP  ", "FP  ", "GR3 ",
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"GR4 ", "GR5 ", "GR6 ", "GR7 ",
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"GR8 ", "GR9 ", "GR10", "GR11",
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"GR12", "GR13", "GR14", "GR15",
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"GR16", "GR17", "GR18", "GR19",
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"GR20", "GR21", "GR22", "GR23",
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"GR24", "GR25", "GR26", "GR27",
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"EFRM", "CURR", "GR30", "BFRM"
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid show_regs(struct pt_regs *regs)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
50784e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	unsigned long *reg;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int loop;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n");
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51284e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	printk("Frame: @%08lx [%s]\n",
51384e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	       (unsigned long) regs,
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       regs->psr & PSR_S ? "kernel" : "user");
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51684e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	reg = (unsigned long *) regs;
51784e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	for (loop = 0; loop < NR_PT_REGS; loop++) {
51884e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells		printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52084e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells		if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("\n");
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" | ");
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Process %s (pid: %d)\n", current->comm, current->pid);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid die_if_kernel(const char *str, ...)
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char buffer[256];
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_list va;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (user_mode(__frame))
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_start(va, str);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vsprintf(buffer, str, va);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	va_end(va);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	console_verbose();
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n===================================\n");
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s\n", buffer);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_backtrace(__frame, 0);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__break_hijack_kernel_event();
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_exit(SIGSEGV);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dump the contents of an exception frame
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void show_backtrace_regs(struct pt_regs *frame)
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
55684e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	unsigned long *reg;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int loop;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* print the registers for this frame */
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("<-- %s Frame: @%p -->\n",
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       frame);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56484e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	reg = (unsigned long *) frame;
56584e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells	for (loop = 0; loop < NR_PT_REGS; loop++) {
56684e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells		printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56884e8cd6dbc00b4979e8d1c15c80d91987aeb3417David Howells		if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("\n");
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" | ");
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("--------\n");
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end show_backtrace_regs() */
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generate a backtrace of the kernel stack
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid show_backtrace(struct pt_regs *frame, unsigned long sp)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pt_regs *frame0;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long tos = 0, stop = 0, base;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int format;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	frame0 = (struct pt_regs *) base;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sp) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tos = sp;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		stop = (unsigned long) frame;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;) {
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* dump stack segment between frames */
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		//printk("%08lx -> %08lx\n", tos, stop);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		format = 0;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (tos < stop) {
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (format == 0)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(" %04lx :", tos & 0xffff);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" %08lx", *(unsigned long *) tos);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			tos += 4;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			format++;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (format == 8) {
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("\n");
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				format = 0;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (format > 0)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("\n");
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* dump frame 0 outside of the loop */
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (frame == frame0)
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tos = frame->sp;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((unsigned long) frame) + sizeof(*frame) != tos) {
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("-- TOS %08lx does not follow frame %p --\n",
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       tos, frame);
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		show_backtrace_regs(frame);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* dump the stack between this frame and the next */
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		stop = (unsigned long) frame->next_frame;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (stop != base &&
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (stop < tos ||
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     stop > base ||
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     (stop < base && stop + sizeof(*frame) > base) ||
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     stop & 3)) {
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       stop, tos, base);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* move to next frame */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		frame = frame->next_frame;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we can always dump frame 0, even if the rest of the stack is corrupt */
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	show_backtrace_regs(frame0);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end show_backtrace() */
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*****************************************************************************/
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initialise traps
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init trap_init (void)
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* end trap_init() */
659