aboutsummaryrefslogtreecommitdiff
path: root/arch/microblaze/kernel/exceptions.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/microblaze/kernel/exceptions.c')
-rw-r--r--arch/microblaze/kernel/exceptions.c70
1 files changed, 50 insertions, 20 deletions
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
index 4a8a4064c7e..42dd12a62ff 100644
--- a/arch/microblaze/kernel/exceptions.c
+++ b/arch/microblaze/kernel/exceptions.c
@@ -13,25 +13,26 @@
* This file handles the architecture-dependent parts of hardware exceptions
*/
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>
-#include <linux/module.h>
#include <asm/exceptions.h>
#include <asm/entry.h> /* For KM CPU var */
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/ptrace.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
#include <asm/current.h>
+#include <asm/cacheflush.h>
#define MICROBLAZE_ILL_OPCODE_EXCEPTION 0x02
#define MICROBLAZE_IBUS_EXCEPTION 0x03
#define MICROBLAZE_DBUS_EXCEPTION 0x04
#define MICROBLAZE_DIV_ZERO_EXCEPTION 0x05
#define MICROBLAZE_FPU_EXCEPTION 0x06
-#define MICROBLAZE_PRIVILEG_EXCEPTION 0x07
+#define MICROBLAZE_PRIVILEGED_EXCEPTION 0x07
static DEFINE_SPINLOCK(die_lock);
@@ -39,7 +40,7 @@ void die(const char *str, struct pt_regs *fp, long err)
{
console_verbose();
spin_lock_irq(&die_lock);
- printk(KERN_WARNING "Oops: %s, sig: %ld\n", str, err);
+ pr_warn("Oops: %s, sig: %ld\n", str, err);
show_regs(fp);
spin_unlock_irq(&die_lock);
/* do_exit() should take care of panic'ing from an interrupt
@@ -48,14 +49,21 @@ void die(const char *str, struct pt_regs *fp, long err)
do_exit(err);
}
+/* for user application debugging */
+asmlinkage void sw_exception(struct pt_regs *regs)
+{
+ _exception(SIGTRAP, regs, TRAP_BRKPT, regs->r16);
+ flush_dcache_range(regs->r16, regs->r16 + 0x4);
+ flush_icache_range(regs->r16, regs->r16 + 0x4);
+}
+
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
siginfo_t info;
- if (kernel_mode(regs)) {
- debugger(regs);
+ if (kernel_mode(regs))
die("Exception in kernel mode", regs, signr);
- }
+
info.si_signo = signr;
info.si_errno = 0;
info.si_code = code;
@@ -66,40 +74,55 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
int fsr, int addr)
{
+#ifdef CONFIG_MMU
+ addr = regs->pc;
+#endif
+
#if 0
- printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",
+ pr_warn("Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",
type, user_mode(regs) ? "user" : "kernel", fsr,
(unsigned int) regs->pc, (unsigned int) regs->esr);
#endif
switch (type & 0x1F) {
case MICROBLAZE_ILL_OPCODE_EXCEPTION:
- _exception(SIGILL, regs, ILL_ILLOPC, addr);
+ if (user_mode(regs)) {
+ pr_debug("Illegal opcode exception in user mode\n");
+ _exception(SIGILL, regs, ILL_ILLOPC, addr);
+ return;
+ }
+ pr_warn("Illegal opcode exception in kernel mode.\n");
+ die("opcode exception", regs, SIGBUS);
break;
case MICROBLAZE_IBUS_EXCEPTION:
if (user_mode(regs)) {
- printk(KERN_WARNING "Instruction bus error exception in user mode.\n");
+ pr_debug("Instruction bus error exception in user mode\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
- printk(KERN_WARNING "Instruction bus error exception in kernel mode.\n");
+ pr_warn("Instruction bus error exception in kernel mode.\n");
die("bus exception", regs, SIGBUS);
break;
case MICROBLAZE_DBUS_EXCEPTION:
if (user_mode(regs)) {
- printk(KERN_WARNING "Data bus error exception in user mode.\n");
+ pr_debug("Data bus error exception in user mode\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
- printk(KERN_WARNING "Data bus error exception in kernel mode.\n");
+ pr_warn("Data bus error exception in kernel mode.\n");
die("bus exception", regs, SIGBUS);
break;
case MICROBLAZE_DIV_ZERO_EXCEPTION:
- printk(KERN_WARNING "Divide by zero exception\n");
- _exception(SIGILL, regs, ILL_ILLOPC, addr);
+ if (user_mode(regs)) {
+ pr_debug("Divide by zero exception in user mode\n");
+ _exception(SIGFPE, regs, FPE_INTDIV, addr);
+ return;
+ }
+ pr_warn("Divide by zero exception in kernel mode.\n");
+ die("Divide by zero exception", regs, SIGBUS);
break;
-
case MICROBLAZE_FPU_EXCEPTION:
+ pr_debug("FPU exception\n");
/* IEEE FP exception */
/* I removed fsr variable and use code var for storing fsr */
if (fsr & FSR_IO)
@@ -115,9 +138,16 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
_exception(SIGFPE, regs, fsr, addr);
break;
+#ifdef CONFIG_MMU
+ case MICROBLAZE_PRIVILEGED_EXCEPTION:
+ pr_debug("Privileged exception\n");
+ _exception(SIGILL, regs, ILL_PRVOPC, addr);
+ break;
+#endif
default:
- printk(KERN_WARNING "Unexpected exception %02x "
- "PC=%08x in %s mode\n", type, (unsigned int) addr,
+ /* FIXME what to do in unexpected exception */
+ pr_warn("Unexpected exception %02x PC=%08x in %s mode\n",
+ type, (unsigned int) addr,
kernel_mode(regs) ? "kernel" : "user");
}
return;