aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/kernel/process.c
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/process.c
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/process.c')
-rw-r--r--arch/avr32/kernel/process.c188
1 files changed, 170 insertions, 18 deletions
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