aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/kernel
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-03-13 12:59:11 -0400
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-04-27 07:44:13 -0400
commit623b0355d5b1f9c6d05005b649a2f3a7b9fd7816 (patch)
tree43ef35d4f6e83a49c1fb72df4b538271b650c054 /arch/avr32/kernel
parent3b328c98093702c584692bffabd440800b383d73 (diff)
[AVR32] Clean up exception handling code
* Use generic BUG() handling * Remove some useless debug statements * Use a common function _exception() to send signals or oops when an exception can't be handled. This makes sure init doesn't enter an infinite exception loop as well. Borrowed from powerpc. * Add some basic exception tracing support to the page fault code. * Rework dump_stack(), show_regs() and friends and move everything into process.c * Print information about configuration options and chip type when oopsing Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/kernel')
-rw-r--r--arch/avr32/kernel/module.c11
-rw-r--r--arch/avr32/kernel/process.c188
-rw-r--r--arch/avr32/kernel/traps.c421
-rw-r--r--arch/avr32/kernel/vmlinux.lds.c9
4 files changed, 311 insertions, 318 deletions
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index b599eae64576..1167fe9cf6c4 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -12,10 +12,11 @@
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13 */ 13 */
14 14
15#include <linux/moduleloader.h> 15#include <linux/bug.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/elf.h> 16#include <linux/elf.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/moduleloader.h>
19#include <linux/vmalloc.h> 20#include <linux/vmalloc.h>
20 21
21void *module_alloc(unsigned long size) 22void *module_alloc(unsigned long size)
@@ -315,10 +316,10 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
315 vfree(module->arch.syminfo); 316 vfree(module->arch.syminfo);
316 module->arch.syminfo = NULL; 317 module->arch.syminfo = NULL;
317 318
318 return 0; 319 return module_bug_finalize(hdr, sechdrs, module);
319} 320}
320 321
321void module_arch_cleanup(struct module *module) 322void module_arch_cleanup(struct module *module)
322{ 323{
323 324 module_bug_cleanup(module);
324} 325}
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 4f8d2d474740..4e4181ed1c6d 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -11,6 +11,7 @@
11#include <linux/fs.h> 11#include <linux/fs.h>
12#include <linux/ptrace.h> 12#include <linux/ptrace.h>
13#include <linux/reboot.h> 13#include <linux/reboot.h>
14#include <linux/uaccess.h>
14#include <linux/unistd.h> 15#include <linux/unistd.h>
15 16
16#include <asm/sysreg.h> 17#include <asm/sysreg.h>
@@ -115,39 +116,178 @@ void release_thread(struct task_struct *dead_task)
115 /* do nothing */ 116 /* do nothing */
116} 117}
117 118
119static void dump_mem(const char *str, const char *log_lvl,
120 unsigned long bottom, unsigned long top)
121{
122 unsigned long p;
123 int i;
124
125 printk("%s%s(0x%08lx to 0x%08lx)\n", log_lvl, str, bottom, top);
126
127 for (p = bottom & ~31; p < top; ) {
128 printk("%s%04lx: ", log_lvl, p & 0xffff);
129
130 for (i = 0; i < 8; i++, p += 4) {
131 unsigned int val;
132
133 if (p < bottom || p >= top)
134 printk(" ");
135 else {
136 if (__get_user(val, (unsigned int __user *)p)) {
137 printk("\n");
138 goto out;
139 }
140 printk("%08x ", val);
141 }
142 }
143 printk("\n");
144 }
145
146out:
147 return;
148}
149
150static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
151{
152 return (p > (unsigned long)tinfo)
153 && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
154}
155
156#ifdef CONFIG_FRAME_POINTER
157static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
158 struct pt_regs *regs, const char *log_lvl)
159{
160 unsigned long lr, fp;
161 struct thread_info *tinfo;
162
163 if (regs)
164 fp = regs->r7;
165 else if (tsk == current)
166 asm("mov %0, r7" : "=r"(fp));
167 else
168 fp = tsk->thread.cpu_context.r7;
169
170 /*
171 * Walk the stack as long as the frame pointer (a) is within
172 * the kernel stack of the task, and (b) it doesn't move
173 * downwards.
174 */
175 tinfo = task_thread_info(tsk);
176 printk("%sCall trace:\n", log_lvl);
177 while (valid_stack_ptr(tinfo, fp)) {
178 unsigned long new_fp;
179
180 lr = *(unsigned long *)fp;
181#ifdef CONFIG_KALLSYMS
182 printk("%s [<%08lx>] ", log_lvl, lr);
183#else
184 printk(" [<%08lx>] ", lr);
185#endif
186 print_symbol("%s\n", lr);
187
188 new_fp = *(unsigned long *)(fp + 4);
189 if (new_fp <= fp)
190 break;
191 fp = new_fp;
192 }
193 printk("\n");
194}
195#else
196static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
197 struct pt_regs *regs, const char *log_lvl)
198{
199 unsigned long addr;
200
201 printk("%sCall trace:\n", log_lvl);
202
203 while (!kstack_end(sp)) {
204 addr = *sp++;
205 if (kernel_text_address(addr)) {
206#ifdef CONFIG_KALLSYMS
207 printk("%s [<%08lx>] ", log_lvl, addr);
208#else
209 printk(" [<%08lx>] ", addr);
210#endif
211 print_symbol("%s\n", addr);
212 }
213 }
214 printk("\n");
215}
216#endif
217
218void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
219 struct pt_regs *regs, const char *log_lvl)
220{
221 struct thread_info *tinfo;
222
223 if (sp == 0) {
224 if (tsk)
225 sp = tsk->thread.cpu_context.ksp;
226 else
227 sp = (unsigned long)&tinfo;
228 }
229 if (!tsk)
230 tsk = current;
231
232 tinfo = task_thread_info(tsk);
233
234 if (valid_stack_ptr(tinfo, sp)) {
235 dump_mem("Stack: ", log_lvl, sp,
236 THREAD_SIZE + (unsigned long)tinfo);
237 show_trace_log_lvl(tsk, (unsigned long *)sp, regs, log_lvl);
238 }
239}
240
241void show_stack(struct task_struct *tsk, unsigned long *stack)
242{
243 show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
244}
245
246void dump_stack(void)
247{
248 unsigned long stack;
249
250 show_trace_log_lvl(current, &stack, NULL, "");
251}
252EXPORT_SYMBOL(dump_stack);
253
118static const char *cpu_modes[] = { 254static const char *cpu_modes[] = {
119 "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1", 255 "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
120 "Interrupt level 2", "Interrupt level 3", "Exception", "NMI" 256 "Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
121}; 257};
122 258
123void show_regs(struct pt_regs *regs) 259void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
124{ 260{
125 unsigned long sp = regs->sp; 261 unsigned long sp = regs->sp;
126 unsigned long lr = regs->lr; 262 unsigned long lr = regs->lr;
127 unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT; 263 unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
128 264
129 if (!user_mode(regs)) 265 if (!user_mode(regs)) {
130 sp = (unsigned long)regs + FRAME_SIZE_FULL; 266 sp = (unsigned long)regs + FRAME_SIZE_FULL;
131 267
132 print_symbol("PC is at %s\n", instruction_pointer(regs)); 268 printk("%s", log_lvl);
133 print_symbol("LR is at %s\n", lr); 269 print_symbol("PC is at %s\n", instruction_pointer(regs));
134 printk("pc : [<%08lx>] lr : [<%08lx>] %s\n" 270 printk("%s", log_lvl);
135 "sp : %08lx r12: %08lx r11: %08lx\n", 271 print_symbol("LR is at %s\n", lr);
136 instruction_pointer(regs), 272 }
137 lr, print_tainted(), sp, regs->r12, regs->r11); 273
138 printk("r10: %08lx r9 : %08lx r8 : %08lx\n", 274 printk("%spc : [<%08lx>] lr : [<%08lx>] %s\n"
139 regs->r10, regs->r9, regs->r8); 275 "%ssp : %08lx r12: %08lx r11: %08lx\n",
140 printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", 276 log_lvl, instruction_pointer(regs), lr, print_tainted(),
141 regs->r7, regs->r6, regs->r5, regs->r4); 277 log_lvl, sp, regs->r12, regs->r11);
142 printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", 278 printk("%sr10: %08lx r9 : %08lx r8 : %08lx\n",
143 regs->r3, regs->r2, regs->r1, regs->r0); 279 log_lvl, regs->r10, regs->r9, regs->r8);
144 printk("Flags: %c%c%c%c%c\n", 280 printk("%sr7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
281 log_lvl, regs->r7, regs->r6, regs->r5, regs->r4);
282 printk("%sr3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
283 log_lvl, regs->r3, regs->r2, regs->r1, regs->r0);
284 printk("%sFlags: %c%c%c%c%c\n", log_lvl,
145 regs->sr & SR_Q ? 'Q' : 'q', 285 regs->sr & SR_Q ? 'Q' : 'q',
146 regs->sr & SR_V ? 'V' : 'v', 286 regs->sr & SR_V ? 'V' : 'v',
147 regs->sr & SR_N ? 'N' : 'n', 287 regs->sr & SR_N ? 'N' : 'n',
148 regs->sr & SR_Z ? 'Z' : 'z', 288 regs->sr & SR_Z ? 'Z' : 'z',
149 regs->sr & SR_C ? 'C' : 'c'); 289 regs->sr & SR_C ? 'C' : 'c');
150 printk("Mode bits: %c%c%c%c%c%c%c%c%c\n", 290 printk("%sMode bits: %c%c%c%c%c%c%c%c%c\n", log_lvl,
151 regs->sr & SR_H ? 'H' : 'h', 291 regs->sr & SR_H ? 'H' : 'h',
152 regs->sr & SR_R ? 'R' : 'r', 292 regs->sr & SR_R ? 'R' : 'r',
153 regs->sr & SR_J ? 'J' : 'j', 293 regs->sr & SR_J ? 'J' : 'j',
@@ -157,9 +297,21 @@ void show_regs(struct pt_regs *regs)
157 regs->sr & SR_I1M ? '1' : '.', 297 regs->sr & SR_I1M ? '1' : '.',
158 regs->sr & SR_I0M ? '0' : '.', 298 regs->sr & SR_I0M ? '0' : '.',
159 regs->sr & SR_GM ? 'G' : 'g'); 299 regs->sr & SR_GM ? 'G' : 'g');
160 printk("CPU Mode: %s\n", cpu_modes[mode]); 300 printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]);
301 printk("%sProcess: %s [%d] (task: %p thread: %p)\n",
302 log_lvl, current->comm, current->pid, current,
303 task_thread_info(current));
304}
305
306void show_regs(struct pt_regs *regs)
307{
308 unsigned long sp = regs->sp;
309
310 if (!user_mode(regs))
311 sp = (unsigned long)regs + FRAME_SIZE_FULL;
161 312
162 show_trace(NULL, (unsigned long *)sp, regs); 313 show_regs_log_lvl(regs, "");
314 show_trace_log_lvl(current, (unsigned long *)sp, regs, "");
163} 315}
164EXPORT_SYMBOL(show_regs); 316EXPORT_SYMBOL(show_regs);
165 317
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index adc01a12d154..4f0382d8483f 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -5,158 +5,25 @@
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8#undef DEBUG 8
9#include <linux/sched.h> 9#include <linux/bug.h>
10#include <linux/init.h> 10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/kallsyms.h> 11#include <linux/kallsyms.h>
12#include <linux/module.h>
13#include <linux/notifier.h> 13#include <linux/notifier.h>
14#include <linux/sched.h>
15#include <linux/uaccess.h>
14 16
15#include <asm/traps.h>
16#include <asm/sysreg.h>
17#include <asm/addrspace.h> 17#include <asm/addrspace.h>
18#include <asm/ocd.h>
19#include <asm/mmu_context.h> 18#include <asm/mmu_context.h>
20#include <asm/uaccess.h> 19#include <asm/ocd.h>
21 20#include <asm/sysreg.h>
22static void dump_mem(const char *str, unsigned long bottom, unsigned long top) 21#include <asm/traps.h>
23{
24 unsigned long p;
25 int i;
26
27 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
28
29 for (p = bottom & ~31; p < top; ) {
30 printk("%04lx: ", p & 0xffff);
31
32 for (i = 0; i < 8; i++, p += 4) {
33 unsigned int val;
34
35 if (p < bottom || p >= top)
36 printk(" ");
37 else {
38 if (__get_user(val, (unsigned int __user *)p)) {
39 printk("\n");
40 goto out;
41 }
42 printk("%08x ", val);
43 }
44 }
45 printk("\n");
46 }
47
48out:
49 return;
50}
51
52static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
53{
54 return (p > (unsigned long)tinfo)
55 && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
56}
57
58#ifdef CONFIG_FRAME_POINTER
59static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
60 struct pt_regs *regs)
61{
62 unsigned long lr, fp;
63 struct thread_info *tinfo;
64
65 tinfo = (struct thread_info *)
66 ((unsigned long)sp & ~(THREAD_SIZE - 1));
67
68 if (regs)
69 fp = regs->r7;
70 else if (tsk == current)
71 asm("mov %0, r7" : "=r"(fp));
72 else
73 fp = tsk->thread.cpu_context.r7;
74
75 /*
76 * Walk the stack as long as the frame pointer (a) is within
77 * the kernel stack of the task, and (b) it doesn't move
78 * downwards.
79 */
80 while (valid_stack_ptr(tinfo, fp)) {
81 unsigned long new_fp;
82
83 lr = *(unsigned long *)fp;
84 printk(" [<%08lx>] ", lr);
85 print_symbol("%s\n", lr);
86
87 new_fp = *(unsigned long *)(fp + 4);
88 if (new_fp <= fp)
89 break;
90 fp = new_fp;
91 }
92 printk("\n");
93}
94#else
95static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
96 struct pt_regs *regs)
97{
98 unsigned long addr;
99
100 while (!kstack_end(sp)) {
101 addr = *sp++;
102 if (kernel_text_address(addr)) {
103 printk(" [<%08lx>] ", addr);
104 print_symbol("%s\n", addr);
105 }
106 }
107}
108#endif
109
110void show_trace(struct task_struct *tsk, unsigned long *sp,
111 struct pt_regs *regs)
112{
113 if (regs &&
114 (((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
115 ((regs->sr & MODE_MASK) == MODE_USER)))
116 return;
117
118 printk ("Call trace:");
119#ifdef CONFIG_KALLSYMS
120 printk("\n");
121#endif
122
123 __show_trace(tsk, sp, regs);
124 printk("\n");
125}
126
127void show_stack(struct task_struct *tsk, unsigned long *sp)
128{
129 unsigned long stack;
130
131 if (!tsk)
132 tsk = current;
133 if (sp == 0) {
134 if (tsk == current) {
135 register unsigned long *real_sp __asm__("sp");
136 sp = real_sp;
137 } else {
138 sp = (unsigned long *)tsk->thread.cpu_context.ksp;
139 }
140 }
141
142 stack = (unsigned long)sp;
143 dump_mem("Stack: ", stack,
144 THREAD_SIZE + (unsigned long)tsk->thread_info);
145 show_trace(tsk, sp, NULL);
146}
147
148void dump_stack(void)
149{
150 show_stack(NULL, NULL);
151}
152EXPORT_SYMBOL(dump_stack);
153 22
154ATOMIC_NOTIFIER_HEAD(avr32_die_chain); 23ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
155 24
156int register_die_notifier(struct notifier_block *nb) 25int register_die_notifier(struct notifier_block *nb)
157{ 26{
158 pr_debug("register_die_notifier: %p\n", nb);
159
160 return atomic_notifier_chain_register(&avr32_die_chain, nb); 27 return atomic_notifier_chain_register(&avr32_die_chain, nb);
161} 28}
162EXPORT_SYMBOL(register_die_notifier); 29EXPORT_SYMBOL(register_die_notifier);
@@ -169,93 +36,103 @@ EXPORT_SYMBOL(unregister_die_notifier);
169 36
170static DEFINE_SPINLOCK(die_lock); 37static DEFINE_SPINLOCK(die_lock);
171 38
172void __die(const char *str, struct pt_regs *regs, unsigned long err, 39void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
173 const char *file, const char *func, unsigned long line)
174{ 40{
175 struct task_struct *tsk = current;
176 static int die_counter; 41 static int die_counter;
177 42
178 console_verbose(); 43 console_verbose();
179 spin_lock_irq(&die_lock); 44 spin_lock_irq(&die_lock);
180 bust_spinlocks(1); 45 bust_spinlocks(1);
181 46
182 printk(KERN_ALERT "%s", str); 47 printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n" KERN_EMERG,
183 if (file && func) 48 str, err, ++die_counter);
184 printk(" in %s:%s, line %ld", file, func, line); 49#ifdef CONFIG_PREEMPT
185 printk("[#%d]:\n", ++die_counter); 50 printk("PREEMPT ");
186 print_modules(); 51#endif
187 show_regs(regs); 52#ifdef CONFIG_FRAME_POINTER
188 printk("Process %s (pid: %d, stack limit = 0x%p)\n", 53 printk("FRAME_POINTER ");
189 tsk->comm, tsk->pid, tsk->thread_info + 1); 54#endif
190 55 if (current_cpu_data.features & AVR32_FEATURE_OCD) {
191 if (!user_mode(regs) || in_interrupt()) { 56 unsigned long did = __mfdr(DBGREG_DID);
192 dump_mem("Stack: ", regs->sp, 57 printk("chip: 0x%03lx:0x%04lx rev %lu\n",
193 THREAD_SIZE + (unsigned long)tsk->thread_info); 58 (did >> 1) & 0x7ff,
59 (did >> 12) & 0x7fff,
60 (did >> 28) & 0xf);
61 } else {
62 printk("cpu: arch %u r%u / core %u r%u\n",
63 current_cpu_data.arch_type,
64 current_cpu_data.arch_revision,
65 current_cpu_data.cpu_type,
66 current_cpu_data.cpu_revision);
194 } 67 }
195 68
69 print_modules();
70 show_regs_log_lvl(regs, KERN_EMERG);
71 show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG);
196 bust_spinlocks(0); 72 bust_spinlocks(0);
197 spin_unlock_irq(&die_lock); 73 spin_unlock_irq(&die_lock);
198 do_exit(SIGSEGV); 74
75 if (in_interrupt())
76 panic("Fatal exception in interrupt");
77
78 if (panic_on_oops)
79 panic("Fatal exception");
80
81 do_exit(err);
199} 82}
200 83
201void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err, 84void _exception(long signr, struct pt_regs *regs, int code,
202 const char *file, const char *func, unsigned long line) 85 unsigned long addr)
203{ 86{
87 siginfo_t info;
88
204 if (!user_mode(regs)) 89 if (!user_mode(regs))
205 __die(str, regs, err, file, func, line); 90 die("Unhandled exception in kernel mode", regs, signr);
206} 91
92 memset(&info, 0, sizeof(info));
93 info.si_signo = signr;
94 info.si_code = code;
95 info.si_addr = (void __user *)addr;
96 force_sig_info(signr, &info, current);
207 97
208asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
209{
210#ifdef CONFIG_SUBARCH_AVR32B
211 /* 98 /*
212 * The exception entry always saves RSR_EX. For NMI, this is 99 * Init gets no signals that it doesn't have a handler for.
213 * wrong; it should be RSR_NMI 100 * That's all very well, but if it has caused a synchronous
101 * exception and we ignore the resulting signal, it will just
102 * generate the same exception over and over again and we get
103 * nowhere. Better to kill it and let the kernel panic.
214 */ 104 */
215 regs->sr = sysreg_read(RSR_NMI); 105 if (is_init(current)) {
216#endif 106 __sighandler_t handler;
107
108 spin_lock_irq(&current->sighand->siglock);
109 handler = current->sighand->action[signr-1].sa.sa_handler;
110 spin_unlock_irq(&current->sighand->siglock);
111 if (handler == SIG_DFL) {
112 /* init has generated a synchronous exception
113 and it doesn't have a handler for the signal */
114 printk(KERN_CRIT "init has generated signal %ld "
115 "but has no handler for it\n", signr);
116 do_exit(signr);
117 }
118 }
119}
217 120
218 printk("NMI taken!!!!\n"); 121asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
219 die("NMI", regs, ecr); 122{
220 BUG(); 123 printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
124 show_regs_log_lvl(regs, KERN_ALERT);
125 show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
221} 126}
222 127
223asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs) 128asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
224{ 129{
225 printk("Unable to handle critical exception %lu at pc = %08lx!\n", 130 die("Critical exception", regs, SIGKILL);
226 ecr, regs->pc);
227 die("Oops", regs, ecr);
228 BUG();
229} 131}
230 132
231asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs) 133asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
232{ 134{
233 siginfo_t info; 135 _exception(SIGBUS, regs, BUS_ADRALN, regs->pc);
234
235 die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);
236
237#ifdef DEBUG
238 if (ecr == ECR_ADDR_ALIGN_X)
239 pr_debug("Instruction Address Exception at pc = %08lx\n",
240 regs->pc);
241 else if (ecr == ECR_ADDR_ALIGN_R)
242 pr_debug("Data Address Exception (Read) at pc = %08lx\n",
243 regs->pc);
244 else if (ecr == ECR_ADDR_ALIGN_W)
245 pr_debug("Data Address Exception (Write) at pc = %08lx\n",
246 regs->pc);
247 else
248 BUG();
249
250 show_regs(regs);
251#endif
252
253 info.si_signo = SIGBUS;
254 info.si_errno = 0;
255 info.si_code = BUS_ADRALN;
256 info.si_addr = (void __user *)regs->pc;
257
258 force_sig_info(SIGBUS, &info, current);
259} 136}
260 137
261/* This way of handling undefined instructions is stolen from ARM */ 138/* This way of handling undefined instructions is stolen from ARM */
@@ -280,7 +157,8 @@ static int do_cop_absent(u32 insn)
280{ 157{
281 int cop_nr; 158 int cop_nr;
282 u32 cpucr; 159 u32 cpucr;
283 if ( (insn & 0xfdf00000) == 0xf1900000 ) 160
161 if ((insn & 0xfdf00000) == 0xf1900000)
284 /* LDC0 */ 162 /* LDC0 */
285 cop_nr = 0; 163 cop_nr = 0;
286 else 164 else
@@ -292,136 +170,91 @@ static int do_cop_absent(u32 insn)
292 sysreg_write(CPUCR, cpucr); 170 sysreg_write(CPUCR, cpucr);
293 171
294 cpucr = sysreg_read(CPUCR); 172 cpucr = sysreg_read(CPUCR);
295 if ( !(cpucr & (1 << (24 + cop_nr))) ){ 173 if (!(cpucr & (1 << (24 + cop_nr))))
296 printk("Coprocessor #%i not found!\n", cop_nr); 174 return -ENODEV;
297 return -1;
298 }
299 175
300 return 0; 176 return 0;
301} 177}
302 178
303#ifdef CONFIG_BUG 179int is_valid_bugaddr(unsigned long pc)
304#ifdef CONFIG_DEBUG_BUGVERBOSE
305static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
306{
307 char *file;
308 u16 line;
309 char c;
310
311 if (__get_user(line, (u16 __user *)(regs->pc + 2)))
312 return;
313 if (__get_user(file, (char * __user *)(regs->pc + 4))
314 || (unsigned long)file < PAGE_OFFSET
315 || __get_user(c, file))
316 file = "<bad filename>";
317
318 printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
319}
320#else
321static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
322{ 180{
181 unsigned short opcode;
182
183 if (pc < PAGE_OFFSET)
184 return 0;
185 if (probe_kernel_address((u16 *)pc, opcode))
186 return 0;
323 187
188 return opcode == AVR32_BUG_OPCODE;
324} 189}
325#endif
326#endif
327 190
328asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs) 191asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
329{ 192{
330 u32 insn; 193 u32 insn;
331 struct undef_hook *hook; 194 struct undef_hook *hook;
332 siginfo_t info;
333 void __user *pc; 195 void __user *pc;
196 long code;
334 197
335 if (!user_mode(regs)) 198 if (!user_mode(regs) && (ecr == ECR_ILLEGAL_OPCODE)) {
336 goto kernel_trap; 199 enum bug_trap_type type;
200
201 type = report_bug(regs->pc);
202 switch (type) {
203 case BUG_TRAP_TYPE_NONE:
204 break;
205 case BUG_TRAP_TYPE_WARN:
206 regs->pc += 2;
207 return;
208 case BUG_TRAP_TYPE_BUG:
209 die("Kernel BUG", regs, SIGKILL);
210 }
211 }
337 212
338 local_irq_enable(); 213 local_irq_enable();
339 214
340 pc = (void __user *)instruction_pointer(regs); 215 if (user_mode(regs)) {
341 if (__get_user(insn, (u32 __user *)pc)) 216 pc = (void __user *)instruction_pointer(regs);
342 goto invalid_area; 217 if (get_user(insn, (u32 __user *)pc))
218 goto invalid_area;
343 219
344 if (ecr == ECR_COPROC_ABSENT) { 220 if (ecr == ECR_COPROC_ABSENT && !do_cop_absent(insn))
345 if (do_cop_absent(insn) == 0)
346 return; 221 return;
347 }
348 222
349 spin_lock_irq(&undef_lock); 223 spin_lock_irq(&undef_lock);
350 list_for_each_entry(hook, &undef_hook, node) { 224 list_for_each_entry(hook, &undef_hook, node) {
351 if ((insn & hook->insn_mask) == hook->insn_val) { 225 if ((insn & hook->insn_mask) == hook->insn_val) {
352 if (hook->fn(regs, insn) == 0) { 226 if (hook->fn(regs, insn) == 0) {
353 spin_unlock_irq(&undef_lock); 227 spin_unlock_irq(&undef_lock);
354 return; 228 return;
229 }
355 } 230 }
356 } 231 }
232 spin_unlock_irq(&undef_lock);
357 } 233 }
358 spin_unlock_irq(&undef_lock);
359
360invalid_area:
361 234
362#ifdef DEBUG
363 printk("Illegal instruction at pc = %08lx\n", regs->pc);
364 if (regs->pc < TASK_SIZE) {
365 unsigned long ptbr, pgd, pte, *p;
366
367 ptbr = sysreg_read(PTBR);
368 p = (unsigned long *)ptbr;
369 pgd = p[regs->pc >> 22];
370 p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
371 pte = p[(regs->pc >> 12) & 0x3ff];
372 printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
373 }
374#endif
375
376 info.si_signo = SIGILL;
377 info.si_errno = 0;
378 info.si_addr = (void __user *)regs->pc;
379 switch (ecr) { 235 switch (ecr) {
380 case ECR_ILLEGAL_OPCODE:
381 case ECR_UNIMPL_INSTRUCTION:
382 info.si_code = ILL_ILLOPC;
383 break;
384 case ECR_PRIVILEGE_VIOLATION: 236 case ECR_PRIVILEGE_VIOLATION:
385 info.si_code = ILL_PRVOPC; 237 code = ILL_PRVOPC;
386 break; 238 break;
387 case ECR_COPROC_ABSENT: 239 case ECR_COPROC_ABSENT:
388 info.si_code = ILL_COPROC; 240 code = ILL_COPROC;
389 break; 241 break;
390 default: 242 default:
391 BUG(); 243 code = ILL_ILLOPC;
244 break;
392 } 245 }
393 246
394 force_sig_info(SIGILL, &info, current); 247 _exception(SIGILL, regs, code, regs->pc);
395 return; 248 return;
396 249
397kernel_trap: 250invalid_area:
398#ifdef CONFIG_BUG 251 _exception(SIGSEGV, regs, SEGV_MAPERR, regs->pc);
399 if (__kernel_text_address(instruction_pointer(regs))) {
400 insn = *(u16 *)instruction_pointer(regs);
401 if (insn == AVR32_BUG_OPCODE) {
402 do_bug_verbose(regs, insn);
403 die("Kernel BUG", regs, 0);
404 return;
405 }
406 }
407#endif
408
409 die("Oops: Illegal instruction in kernel code", regs, ecr);
410} 252}
411 253
412asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs) 254asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
413{ 255{
414 siginfo_t info; 256 /* We have no FPU yet */
415 257 _exception(SIGILL, regs, ILL_COPROC, regs->pc);
416 printk("Floating-point exception at pc = %08lx\n", regs->pc);
417
418 /* We have no FPU... */
419 info.si_signo = SIGILL;
420 info.si_errno = 0;
421 info.si_addr = (void __user *)regs->pc;
422 info.si_code = ILL_COPROC;
423
424 force_sig_info(SIGILL, &info, current);
425} 258}
426 259
427 260
diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
index ef13b7c78935..7ad20cfb48a8 100644
--- a/arch/avr32/kernel/vmlinux.lds.c
+++ b/arch/avr32/kernel/vmlinux.lds.c
@@ -26,6 +26,12 @@ SECTIONS
26 _sinittext = .; 26 _sinittext = .;
27 *(.text.reset) 27 *(.text.reset)
28 *(.init.text) 28 *(.init.text)
29 /*
30 * .exit.text is discarded at runtime, not
31 * link time, to deal with references from
32 * __bug_table
33 */
34 *(.exit.text)
29 _einittext = .; 35 _einittext = .;
30 . = ALIGN(4); 36 . = ALIGN(4);
31 __tagtable_begin = .; 37 __tagtable_begin = .;
@@ -86,6 +92,8 @@ SECTIONS
86 __stop___ex_table = .; 92 __stop___ex_table = .;
87 } 93 }
88 94
95 BUG_TABLE
96
89 RODATA 97 RODATA
90 98
91 . = ALIGN(8192); 99 . = ALIGN(8192);
@@ -126,7 +134,6 @@ SECTIONS
126 * thrown away, as cleanup code is never called unless it's a module. 134 * thrown away, as cleanup code is never called unless it's a module.
127 */ 135 */
128 /DISCARD/ : { 136 /DISCARD/ : {
129 *(.exit.text)
130 *(.exit.data) 137 *(.exit.data)
131 *(.exitcall.exit) 138 *(.exitcall.exit)
132 } 139 }