diff options
Diffstat (limited to 'arch/parisc/kernel/traps.c')
-rw-r--r-- | arch/parisc/kernel/traps.c | 153 |
1 files changed, 75 insertions, 78 deletions
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 65cd6ca32fed..55bc1471967d 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/console.h> | 27 | #include <linux/console.h> |
28 | #include <linux/kallsyms.h> | 28 | #include <linux/kallsyms.h> |
29 | #include <linux/bug.h> | ||
29 | 30 | ||
30 | #include <asm/assembly.h> | 31 | #include <asm/assembly.h> |
31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
@@ -39,6 +40,8 @@ | |||
39 | #include <asm/pdc.h> | 40 | #include <asm/pdc.h> |
40 | #include <asm/pdc_chassis.h> | 41 | #include <asm/pdc_chassis.h> |
41 | #include <asm/unwind.h> | 42 | #include <asm/unwind.h> |
43 | #include <asm/tlbflush.h> | ||
44 | #include <asm/cacheflush.h> | ||
42 | 45 | ||
43 | #include "../math-emu/math-emu.h" /* for handle_fpe() */ | 46 | #include "../math-emu/math-emu.h" /* for handle_fpe() */ |
44 | 47 | ||
@@ -49,7 +52,7 @@ | |||
49 | DEFINE_SPINLOCK(pa_dbit_lock); | 52 | DEFINE_SPINLOCK(pa_dbit_lock); |
50 | #endif | 53 | #endif |
51 | 54 | ||
52 | int printbinary(char *buf, unsigned long x, int nbits) | 55 | static int printbinary(char *buf, unsigned long x, int nbits) |
53 | { | 56 | { |
54 | unsigned long mask = 1UL << (nbits - 1); | 57 | unsigned long mask = 1UL << (nbits - 1); |
55 | while (mask != 0) { | 58 | while (mask != 0) { |
@@ -61,7 +64,7 @@ int printbinary(char *buf, unsigned long x, int nbits) | |||
61 | return nbits; | 64 | return nbits; |
62 | } | 65 | } |
63 | 66 | ||
64 | #ifdef __LP64__ | 67 | #ifdef CONFIG_64BIT |
65 | #define RFMT "%016lx" | 68 | #define RFMT "%016lx" |
66 | #else | 69 | #else |
67 | #define RFMT "%08lx" | 70 | #define RFMT "%08lx" |
@@ -160,13 +163,13 @@ static void do_show_stack(struct unwind_frame_info *info) | |||
160 | { | 163 | { |
161 | int i = 1; | 164 | int i = 1; |
162 | 165 | ||
163 | printk("Backtrace:\n"); | 166 | printk(KERN_CRIT "Backtrace:\n"); |
164 | while (i <= 16) { | 167 | while (i <= 16) { |
165 | if (unwind_once(info) < 0 || info->ip == 0) | 168 | if (unwind_once(info) < 0 || info->ip == 0) |
166 | break; | 169 | break; |
167 | 170 | ||
168 | if (__kernel_text_address(info->ip)) { | 171 | if (__kernel_text_address(info->ip)) { |
169 | printk(" [<" RFMT ">] ", info->ip); | 172 | printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip); |
170 | #ifdef CONFIG_KALLSYMS | 173 | #ifdef CONFIG_KALLSYMS |
171 | print_symbol("%s\n", info->ip); | 174 | print_symbol("%s\n", info->ip); |
172 | #else | 175 | #else |
@@ -185,18 +188,19 @@ void show_stack(struct task_struct *task, unsigned long *s) | |||
185 | 188 | ||
186 | if (!task) { | 189 | if (!task) { |
187 | unsigned long sp; | 190 | unsigned long sp; |
188 | struct pt_regs *r; | ||
189 | 191 | ||
190 | HERE: | 192 | HERE: |
191 | asm volatile ("copy %%r30, %0" : "=r"(sp)); | 193 | asm volatile ("copy %%r30, %0" : "=r"(sp)); |
192 | r = kzalloc(sizeof(struct pt_regs), GFP_KERNEL); | 194 | { |
193 | if (!r) | 195 | struct pt_regs r; |
194 | return; | 196 | |
195 | r->iaoq[0] = (unsigned long)&&HERE; | 197 | memset(&r, 0, sizeof(struct pt_regs)); |
196 | r->gr[2] = (unsigned long)__builtin_return_address(0); | 198 | r.iaoq[0] = (unsigned long)&&HERE; |
197 | r->gr[30] = sp; | 199 | r.gr[2] = (unsigned long)__builtin_return_address(0); |
198 | unwind_frame_init(&info, current, r); | 200 | r.gr[30] = sp; |
199 | kfree(r); | 201 | |
202 | unwind_frame_init(&info, current, &r); | ||
203 | } | ||
200 | } else { | 204 | } else { |
201 | unwind_frame_init_from_blocked_task(&info, task); | 205 | unwind_frame_init_from_blocked_task(&info, task); |
202 | } | 206 | } |
@@ -204,6 +208,11 @@ HERE: | |||
204 | do_show_stack(&info); | 208 | do_show_stack(&info); |
205 | } | 209 | } |
206 | 210 | ||
211 | int is_valid_bugaddr(unsigned long iaoq) | ||
212 | { | ||
213 | return 1; | ||
214 | } | ||
215 | |||
207 | void die_if_kernel(char *str, struct pt_regs *regs, long err) | 216 | void die_if_kernel(char *str, struct pt_regs *regs, long err) |
208 | { | 217 | { |
209 | if (user_mode(regs)) { | 218 | if (user_mode(regs)) { |
@@ -222,15 +231,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
222 | oops_in_progress = 1; | 231 | oops_in_progress = 1; |
223 | 232 | ||
224 | /* Amuse the user in a SPARC fashion */ | 233 | /* Amuse the user in a SPARC fashion */ |
225 | printk( | 234 | if (err) printk( |
226 | " _______________________________ \n" | 235 | KERN_CRIT " _______________________________ \n" |
227 | " < Your System ate a SPARC! Gah! >\n" | 236 | KERN_CRIT " < Your System ate a SPARC! Gah! >\n" |
228 | " ------------------------------- \n" | 237 | KERN_CRIT " ------------------------------- \n" |
229 | " \\ ^__^\n" | 238 | KERN_CRIT " \\ ^__^\n" |
230 | " \\ (xx)\\_______\n" | 239 | KERN_CRIT " \\ (xx)\\_______\n" |
231 | " (__)\\ )\\/\\\n" | 240 | KERN_CRIT " (__)\\ )\\/\\\n" |
232 | " U ||----w |\n" | 241 | KERN_CRIT " U ||----w |\n" |
233 | " || ||\n"); | 242 | KERN_CRIT " || ||\n"); |
234 | 243 | ||
235 | /* unlock the pdc lock if necessary */ | 244 | /* unlock the pdc lock if necessary */ |
236 | pdc_emergency_unlock(); | 245 | pdc_emergency_unlock(); |
@@ -242,9 +251,20 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
242 | if (!console_drivers) | 251 | if (!console_drivers) |
243 | pdc_console_restart(); | 252 | pdc_console_restart(); |
244 | 253 | ||
245 | printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", | 254 | if (err) |
246 | current->comm, current->pid, str, err); | 255 | printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", |
256 | current->comm, current->pid, str, err); | ||
257 | |||
258 | /* Wot's wrong wif bein' racy? */ | ||
259 | if (current->thread.flags & PARISC_KERNEL_DEATH) { | ||
260 | printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); | ||
261 | local_irq_enable(); | ||
262 | while (1); | ||
263 | } | ||
264 | current->thread.flags |= PARISC_KERNEL_DEATH; | ||
265 | |||
247 | show_regs(regs); | 266 | show_regs(regs); |
267 | dump_stack(); | ||
248 | 268 | ||
249 | if (in_interrupt()) | 269 | if (in_interrupt()) |
250 | panic("Fatal exception in interrupt"); | 270 | panic("Fatal exception in interrupt"); |
@@ -255,14 +275,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
255 | panic("Fatal exception"); | 275 | panic("Fatal exception"); |
256 | } | 276 | } |
257 | 277 | ||
258 | /* Wot's wrong wif bein' racy? */ | ||
259 | if (current->thread.flags & PARISC_KERNEL_DEATH) { | ||
260 | printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); | ||
261 | local_irq_enable(); | ||
262 | while (1); | ||
263 | } | ||
264 | |||
265 | current->thread.flags |= PARISC_KERNEL_DEATH; | ||
266 | do_exit(SIGSEGV); | 278 | do_exit(SIGSEGV); |
267 | } | 279 | } |
268 | 280 | ||
@@ -273,61 +285,45 @@ int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs) | |||
273 | 285 | ||
274 | /* gdb uses break 4,8 */ | 286 | /* gdb uses break 4,8 */ |
275 | #define GDB_BREAK_INSN 0x10004 | 287 | #define GDB_BREAK_INSN 0x10004 |
276 | void handle_gdb_break(struct pt_regs *regs, int wot) | 288 | static void handle_gdb_break(struct pt_regs *regs, int wot) |
277 | { | 289 | { |
278 | struct siginfo si; | 290 | struct siginfo si; |
279 | 291 | ||
280 | si.si_code = wot; | ||
281 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | ||
282 | si.si_signo = SIGTRAP; | 292 | si.si_signo = SIGTRAP; |
283 | si.si_errno = 0; | 293 | si.si_errno = 0; |
294 | si.si_code = wot; | ||
295 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | ||
284 | force_sig_info(SIGTRAP, &si, current); | 296 | force_sig_info(SIGTRAP, &si, current); |
285 | } | 297 | } |
286 | 298 | ||
287 | void handle_break(unsigned iir, struct pt_regs *regs) | 299 | static void handle_break(struct pt_regs *regs) |
288 | { | 300 | { |
289 | struct siginfo si; | 301 | unsigned iir = regs->iir; |
290 | 302 | ||
291 | switch(iir) { | 303 | if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) { |
292 | case 0x00: | 304 | /* check if a BUG() or WARN() trapped here. */ |
293 | #ifdef PRINT_USER_FAULTS | 305 | enum bug_trap_type tt; |
294 | printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n", | 306 | tt = report_bug(regs->iaoq[0] & ~3); |
295 | current->pid, current->comm); | 307 | if (tt == BUG_TRAP_TYPE_WARN) { |
296 | #endif | 308 | regs->iaoq[0] += 4; |
297 | die_if_kernel("Breakpoint", regs, 0); | 309 | regs->iaoq[1] += 4; |
298 | #ifdef PRINT_USER_FAULTS | 310 | return; /* return to next instruction when WARN_ON(). */ |
299 | show_regs(regs); | 311 | } |
300 | #endif | 312 | die_if_kernel("Unknown kernel breakpoint", regs, |
301 | si.si_code = TRAP_BRKPT; | 313 | (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); |
302 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | 314 | } |
303 | si.si_signo = SIGTRAP; | ||
304 | force_sig_info(SIGTRAP, &si, current); | ||
305 | break; | ||
306 | |||
307 | case GDB_BREAK_INSN: | ||
308 | die_if_kernel("Breakpoint", regs, 0); | ||
309 | handle_gdb_break(regs, TRAP_BRKPT); | ||
310 | break; | ||
311 | 315 | ||
312 | default: | ||
313 | #ifdef PRINT_USER_FAULTS | 316 | #ifdef PRINT_USER_FAULTS |
314 | printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n", | 317 | if (unlikely(iir != GDB_BREAK_INSN)) { |
315 | iir, current->pid, current->comm); | 318 | printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", |
319 | iir & 31, (iir>>13) & ((1<<13)-1), | ||
320 | current->pid, current->comm); | ||
316 | show_regs(regs); | 321 | show_regs(regs); |
317 | #endif | ||
318 | si.si_signo = SIGTRAP; | ||
319 | si.si_code = TRAP_BRKPT; | ||
320 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | ||
321 | force_sig_info(SIGTRAP, &si, current); | ||
322 | return; | ||
323 | } | 322 | } |
324 | } | 323 | #endif |
325 | |||
326 | 324 | ||
327 | int handle_toc(void) | 325 | /* send standard GDB signal */ |
328 | { | 326 | handle_gdb_break(regs, TRAP_BRKPT); |
329 | printk(KERN_CRIT "TOC call.\n"); | ||
330 | return 0; | ||
331 | } | 327 | } |
332 | 328 | ||
333 | static void default_trap(int code, struct pt_regs *regs) | 329 | static void default_trap(int code, struct pt_regs *regs) |
@@ -336,7 +332,7 @@ static void default_trap(int code, struct pt_regs *regs) | |||
336 | show_regs(regs); | 332 | show_regs(regs); |
337 | } | 333 | } |
338 | 334 | ||
339 | void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap; | 335 | void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap; |
340 | 336 | ||
341 | 337 | ||
342 | void transfer_pim_to_trap_frame(struct pt_regs *regs) | 338 | void transfer_pim_to_trap_frame(struct pt_regs *regs) |
@@ -554,7 +550,8 @@ void handle_interruption(int code, struct pt_regs *regs) | |||
554 | /* Low-priority machine check */ | 550 | /* Low-priority machine check */ |
555 | pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC); | 551 | pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC); |
556 | 552 | ||
557 | flush_all_caches(); | 553 | flush_cache_all(); |
554 | flush_tlb_all(); | ||
558 | cpu_lpmc(5, regs); | 555 | cpu_lpmc(5, regs); |
559 | return; | 556 | return; |
560 | 557 | ||
@@ -572,7 +569,7 @@ void handle_interruption(int code, struct pt_regs *regs) | |||
572 | 569 | ||
573 | case 9: | 570 | case 9: |
574 | /* Break instruction trap */ | 571 | /* Break instruction trap */ |
575 | handle_break(regs->iir,regs); | 572 | handle_break(regs); |
576 | return; | 573 | return; |
577 | 574 | ||
578 | case 10: | 575 | case 10: |
@@ -840,7 +837,7 @@ int __init check_ivt(void *iva) | |||
840 | return 0; | 837 | return 0; |
841 | } | 838 | } |
842 | 839 | ||
843 | #ifndef __LP64__ | 840 | #ifndef CONFIG_64BIT |
844 | extern const void fault_vector_11; | 841 | extern const void fault_vector_11; |
845 | #endif | 842 | #endif |
846 | extern const void fault_vector_20; | 843 | extern const void fault_vector_20; |
@@ -852,7 +849,7 @@ void __init trap_init(void) | |||
852 | if (boot_cpu_data.cpu_type >= pcxu) | 849 | if (boot_cpu_data.cpu_type >= pcxu) |
853 | iva = (void *) &fault_vector_20; | 850 | iva = (void *) &fault_vector_20; |
854 | else | 851 | else |
855 | #ifdef __LP64__ | 852 | #ifdef CONFIG_64BIT |
856 | panic("Can't boot 64-bit OS on PA1.1 processor!"); | 853 | panic("Can't boot 64-bit OS on PA1.1 processor!"); |
857 | #else | 854 | #else |
858 | iva = (void *) &fault_vector_11; | 855 | iva = (void *) &fault_vector_11; |