diff options
author | Michal Simek <monstr@monstr.eu> | 2009-05-26 10:30:24 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2009-05-26 10:45:20 -0400 |
commit | 4bb73c3de752dc386958be32dc7e1d9fefdcbbf0 (patch) | |
tree | 8931ff6a85eb734c1769601f7cd62c632667e404 /arch/microblaze/kernel/exceptions.c | |
parent | 0d6de9532663a4120ce35f507f16b72df382e360 (diff) |
microblaze_mmu_v2: Add MMU related exceptions handling
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze/kernel/exceptions.c')
-rw-r--r-- | arch/microblaze/kernel/exceptions.c | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c index 4a8a4064c7ee..0cb64a31e89a 100644 --- a/arch/microblaze/kernel/exceptions.c +++ b/arch/microblaze/kernel/exceptions.c | |||
@@ -21,9 +21,9 @@ | |||
21 | 21 | ||
22 | #include <asm/exceptions.h> | 22 | #include <asm/exceptions.h> |
23 | #include <asm/entry.h> /* For KM CPU var */ | 23 | #include <asm/entry.h> /* For KM CPU var */ |
24 | #include <asm/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #include <asm/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <asm/ptrace.h> | 26 | #include <linux/ptrace.h> |
27 | #include <asm/current.h> | 27 | #include <asm/current.h> |
28 | 28 | ||
29 | #define MICROBLAZE_ILL_OPCODE_EXCEPTION 0x02 | 29 | #define MICROBLAZE_ILL_OPCODE_EXCEPTION 0x02 |
@@ -31,7 +31,7 @@ | |||
31 | #define MICROBLAZE_DBUS_EXCEPTION 0x04 | 31 | #define MICROBLAZE_DBUS_EXCEPTION 0x04 |
32 | #define MICROBLAZE_DIV_ZERO_EXCEPTION 0x05 | 32 | #define MICROBLAZE_DIV_ZERO_EXCEPTION 0x05 |
33 | #define MICROBLAZE_FPU_EXCEPTION 0x06 | 33 | #define MICROBLAZE_FPU_EXCEPTION 0x06 |
34 | #define MICROBLAZE_PRIVILEG_EXCEPTION 0x07 | 34 | #define MICROBLAZE_PRIVILEGED_EXCEPTION 0x07 |
35 | 35 | ||
36 | static DEFINE_SPINLOCK(die_lock); | 36 | static DEFINE_SPINLOCK(die_lock); |
37 | 37 | ||
@@ -66,6 +66,11 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
66 | asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, | 66 | asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, |
67 | int fsr, int addr) | 67 | int fsr, int addr) |
68 | { | 68 | { |
69 | #ifdef CONFIG_MMU | ||
70 | int code; | ||
71 | addr = regs->pc; | ||
72 | #endif | ||
73 | |||
69 | #if 0 | 74 | #if 0 |
70 | printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n", | 75 | printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n", |
71 | type, user_mode(regs) ? "user" : "kernel", fsr, | 76 | type, user_mode(regs) ? "user" : "kernel", fsr, |
@@ -74,7 +79,13 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, | |||
74 | 79 | ||
75 | switch (type & 0x1F) { | 80 | switch (type & 0x1F) { |
76 | case MICROBLAZE_ILL_OPCODE_EXCEPTION: | 81 | case MICROBLAZE_ILL_OPCODE_EXCEPTION: |
77 | _exception(SIGILL, regs, ILL_ILLOPC, addr); | 82 | if (user_mode(regs)) { |
83 | printk(KERN_WARNING "Illegal opcode exception in user mode.\n"); | ||
84 | _exception(SIGILL, regs, ILL_ILLOPC, addr); | ||
85 | return; | ||
86 | } | ||
87 | printk(KERN_WARNING "Illegal opcode exception in kernel mode.\n"); | ||
88 | die("opcode exception", regs, SIGBUS); | ||
78 | break; | 89 | break; |
79 | case MICROBLAZE_IBUS_EXCEPTION: | 90 | case MICROBLAZE_IBUS_EXCEPTION: |
80 | if (user_mode(regs)) { | 91 | if (user_mode(regs)) { |
@@ -95,11 +106,16 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, | |||
95 | die("bus exception", regs, SIGBUS); | 106 | die("bus exception", regs, SIGBUS); |
96 | break; | 107 | break; |
97 | case MICROBLAZE_DIV_ZERO_EXCEPTION: | 108 | case MICROBLAZE_DIV_ZERO_EXCEPTION: |
98 | printk(KERN_WARNING "Divide by zero exception\n"); | 109 | if (user_mode(regs)) { |
99 | _exception(SIGILL, regs, ILL_ILLOPC, addr); | 110 | printk(KERN_WARNING "Divide by zero exception in user mode\n"); |
111 | _exception(SIGILL, regs, ILL_ILLOPC, addr); | ||
112 | return; | ||
113 | } | ||
114 | printk(KERN_WARNING "Divide by zero exception in kernel mode.\n"); | ||
115 | die("Divide by exception", regs, SIGBUS); | ||
100 | break; | 116 | break; |
101 | |||
102 | case MICROBLAZE_FPU_EXCEPTION: | 117 | case MICROBLAZE_FPU_EXCEPTION: |
118 | printk(KERN_WARNING "FPU exception\n"); | ||
103 | /* IEEE FP exception */ | 119 | /* IEEE FP exception */ |
104 | /* I removed fsr variable and use code var for storing fsr */ | 120 | /* I removed fsr variable and use code var for storing fsr */ |
105 | if (fsr & FSR_IO) | 121 | if (fsr & FSR_IO) |
@@ -115,7 +131,20 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, | |||
115 | _exception(SIGFPE, regs, fsr, addr); | 131 | _exception(SIGFPE, regs, fsr, addr); |
116 | break; | 132 | break; |
117 | 133 | ||
134 | #ifdef CONFIG_MMU | ||
135 | case MICROBLAZE_PRIVILEGED_EXCEPTION: | ||
136 | printk(KERN_WARNING "Privileged exception\n"); | ||
137 | /* "brk r0,r0" - used as debug breakpoint */ | ||
138 | if (get_user(code, (unsigned long *)regs->pc) == 0 | ||
139 | && code == 0x980c0000) { | ||
140 | _exception(SIGTRAP, regs, TRAP_BRKPT, addr); | ||
141 | } else { | ||
142 | _exception(SIGILL, regs, ILL_PRVOPC, addr); | ||
143 | } | ||
144 | break; | ||
145 | #endif | ||
118 | default: | 146 | default: |
147 | /* FIXME what to do in unexpected exception */ | ||
119 | printk(KERN_WARNING "Unexpected exception %02x " | 148 | printk(KERN_WARNING "Unexpected exception %02x " |
120 | "PC=%08x in %s mode\n", type, (unsigned int) addr, | 149 | "PC=%08x in %s mode\n", type, (unsigned int) addr, |
121 | kernel_mode(regs) ? "kernel" : "user"); | 150 | kernel_mode(regs) ? "kernel" : "user"); |