diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-06-07 17:08:28 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-06-13 07:20:09 -0400 |
commit | 82bd1d7d45a69c54fb6beedb78ccb1c7d308dd93 (patch) | |
tree | f9a60086a663ab07304db13eacb53b7ce325b42f | |
parent | 6510a20e1b1a3a5703429a09d03adf44882ae373 (diff) |
Blackfin: push down exception oops checking
Rather than maintain a duplicate list of valid exceptions we can take in
the kernel both in the first if() check and the switch() check, delay the
oops check to after the switch(). All valid exceptions will have returned
by this point leaving only the invalid ones.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r-- | arch/blackfin/kernel/traps.c | 88 |
1 files changed, 43 insertions, 45 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index ed7127b1b9f9..d279552fe9b0 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c | |||
@@ -239,6 +239,11 @@ asmlinkage void double_fault_c(struct pt_regs *fp) | |||
239 | 239 | ||
240 | } | 240 | } |
241 | 241 | ||
242 | static int kernel_mode_regs(struct pt_regs *regs) | ||
243 | { | ||
244 | return regs->ipend & 0xffc0; | ||
245 | } | ||
246 | |||
242 | asmlinkage void trap_c(struct pt_regs *fp) | 247 | asmlinkage void trap_c(struct pt_regs *fp) |
243 | { | 248 | { |
244 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 249 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
@@ -247,6 +252,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
247 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | 252 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO |
248 | unsigned int cpu = smp_processor_id(); | 253 | unsigned int cpu = smp_processor_id(); |
249 | #endif | 254 | #endif |
255 | const char *strerror = NULL; | ||
250 | int sig = 0; | 256 | int sig = 0; |
251 | siginfo_t info; | 257 | siginfo_t info; |
252 | unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; | 258 | unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; |
@@ -260,27 +266,10 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
260 | * double faults if the stack has become corrupt | 266 | * double faults if the stack has become corrupt |
261 | */ | 267 | */ |
262 | 268 | ||
263 | /* If the fault was caused by a kernel thread, or interrupt handler | 269 | #ifndef CONFIG_KGDB |
264 | * we will kernel panic, so the system reboots. | 270 | /* IPEND is skipped if KGDB isn't enabled (see entry code) */ |
265 | * If KGDB is enabled, don't set this for kernel breakpoints | 271 | fp->ipend = bfin_read_IPEND(); |
266 | */ | ||
267 | |||
268 | /* TODO: check to see if we are in some sort of deferred HWERR | ||
269 | * that we should be able to recover from, not kernel panic | ||
270 | */ | ||
271 | if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP) | ||
272 | #ifdef CONFIG_KGDB | ||
273 | && (trapnr != VEC_EXCPT02) | ||
274 | #endif | 272 | #endif |
275 | ){ | ||
276 | console_verbose(); | ||
277 | oops_in_progress = 1; | ||
278 | } else if (current) { | ||
279 | if (current->mm == NULL) { | ||
280 | console_verbose(); | ||
281 | oops_in_progress = 1; | ||
282 | } | ||
283 | } | ||
284 | 273 | ||
285 | /* trap_c() will be called for exceptions. During exceptions | 274 | /* trap_c() will be called for exceptions. During exceptions |
286 | * processing, the pc value should be set with retx value. | 275 | * processing, the pc value should be set with retx value. |
@@ -308,7 +297,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
308 | sig = SIGTRAP; | 297 | sig = SIGTRAP; |
309 | CHK_DEBUGGER_TRAP_MAYBE(); | 298 | CHK_DEBUGGER_TRAP_MAYBE(); |
310 | /* Check if this is a breakpoint in kernel space */ | 299 | /* Check if this is a breakpoint in kernel space */ |
311 | if (fp->ipend & 0xffc0) | 300 | if (kernel_mode_regs(fp)) |
312 | goto traps_done; | 301 | goto traps_done; |
313 | else | 302 | else |
314 | break; | 303 | break; |
@@ -316,7 +305,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
316 | case VEC_EXCPT03: | 305 | case VEC_EXCPT03: |
317 | info.si_code = SEGV_STACKFLOW; | 306 | info.si_code = SEGV_STACKFLOW; |
318 | sig = SIGSEGV; | 307 | sig = SIGSEGV; |
319 | verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); | 308 | strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE); |
320 | CHK_DEBUGGER_TRAP_MAYBE(); | 309 | CHK_DEBUGGER_TRAP_MAYBE(); |
321 | break; | 310 | break; |
322 | /* 0x02 - KGDB initial connection and break signal trap */ | 311 | /* 0x02 - KGDB initial connection and break signal trap */ |
@@ -345,7 +334,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
345 | case VEC_EXCPT04 ... VEC_EXCPT15: | 334 | case VEC_EXCPT04 ... VEC_EXCPT15: |
346 | info.si_code = ILL_ILLPARAOP; | 335 | info.si_code = ILL_ILLPARAOP; |
347 | sig = SIGILL; | 336 | sig = SIGILL; |
348 | verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE)); | 337 | strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE); |
349 | CHK_DEBUGGER_TRAP_MAYBE(); | 338 | CHK_DEBUGGER_TRAP_MAYBE(); |
350 | break; | 339 | break; |
351 | /* 0x10 HW Single step, handled here */ | 340 | /* 0x10 HW Single step, handled here */ |
@@ -354,7 +343,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
354 | sig = SIGTRAP; | 343 | sig = SIGTRAP; |
355 | CHK_DEBUGGER_TRAP_MAYBE(); | 344 | CHK_DEBUGGER_TRAP_MAYBE(); |
356 | /* Check if this is a single step in kernel space */ | 345 | /* Check if this is a single step in kernel space */ |
357 | if (fp->ipend & 0xffc0) | 346 | if (kernel_mode_regs(fp)) |
358 | goto traps_done; | 347 | goto traps_done; |
359 | else | 348 | else |
360 | break; | 349 | break; |
@@ -362,7 +351,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
362 | case VEC_OVFLOW: | 351 | case VEC_OVFLOW: |
363 | info.si_code = TRAP_TRACEFLOW; | 352 | info.si_code = TRAP_TRACEFLOW; |
364 | sig = SIGTRAP; | 353 | sig = SIGTRAP; |
365 | verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); | 354 | strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE); |
366 | CHK_DEBUGGER_TRAP_MAYBE(); | 355 | CHK_DEBUGGER_TRAP_MAYBE(); |
367 | break; | 356 | break; |
368 | /* 0x12 - Reserved, Caught by default */ | 357 | /* 0x12 - Reserved, Caught by default */ |
@@ -401,35 +390,35 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
401 | #endif | 390 | #endif |
402 | info.si_code = ILL_ILLOPC; | 391 | info.si_code = ILL_ILLOPC; |
403 | sig = SIGILL; | 392 | sig = SIGILL; |
404 | verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); | 393 | strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE); |
405 | CHK_DEBUGGER_TRAP_MAYBE(); | 394 | CHK_DEBUGGER_TRAP_MAYBE(); |
406 | break; | 395 | break; |
407 | /* 0x22 - Illegal Instruction Combination, handled here */ | 396 | /* 0x22 - Illegal Instruction Combination, handled here */ |
408 | case VEC_ILGAL_I: | 397 | case VEC_ILGAL_I: |
409 | info.si_code = ILL_ILLPARAOP; | 398 | info.si_code = ILL_ILLPARAOP; |
410 | sig = SIGILL; | 399 | sig = SIGILL; |
411 | verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); | 400 | strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE); |
412 | CHK_DEBUGGER_TRAP_MAYBE(); | 401 | CHK_DEBUGGER_TRAP_MAYBE(); |
413 | break; | 402 | break; |
414 | /* 0x23 - Data CPLB protection violation, handled here */ | 403 | /* 0x23 - Data CPLB protection violation, handled here */ |
415 | case VEC_CPLB_VL: | 404 | case VEC_CPLB_VL: |
416 | info.si_code = ILL_CPLB_VI; | 405 | info.si_code = ILL_CPLB_VI; |
417 | sig = SIGBUS; | 406 | sig = SIGBUS; |
418 | verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); | 407 | strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE); |
419 | CHK_DEBUGGER_TRAP_MAYBE(); | 408 | CHK_DEBUGGER_TRAP_MAYBE(); |
420 | break; | 409 | break; |
421 | /* 0x24 - Data access misaligned, handled here */ | 410 | /* 0x24 - Data access misaligned, handled here */ |
422 | case VEC_MISALI_D: | 411 | case VEC_MISALI_D: |
423 | info.si_code = BUS_ADRALN; | 412 | info.si_code = BUS_ADRALN; |
424 | sig = SIGBUS; | 413 | sig = SIGBUS; |
425 | verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); | 414 | strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE); |
426 | CHK_DEBUGGER_TRAP_MAYBE(); | 415 | CHK_DEBUGGER_TRAP_MAYBE(); |
427 | break; | 416 | break; |
428 | /* 0x25 - Unrecoverable Event, handled here */ | 417 | /* 0x25 - Unrecoverable Event, handled here */ |
429 | case VEC_UNCOV: | 418 | case VEC_UNCOV: |
430 | info.si_code = ILL_ILLEXCPT; | 419 | info.si_code = ILL_ILLEXCPT; |
431 | sig = SIGILL; | 420 | sig = SIGILL; |
432 | verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); | 421 | strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE); |
433 | CHK_DEBUGGER_TRAP_MAYBE(); | 422 | CHK_DEBUGGER_TRAP_MAYBE(); |
434 | break; | 423 | break; |
435 | /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, | 424 | /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, |
@@ -437,7 +426,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
437 | case VEC_CPLB_M: | 426 | case VEC_CPLB_M: |
438 | info.si_code = BUS_ADRALN; | 427 | info.si_code = BUS_ADRALN; |
439 | sig = SIGBUS; | 428 | sig = SIGBUS; |
440 | verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); | 429 | strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE); |
441 | break; | 430 | break; |
442 | /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ | 431 | /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ |
443 | case VEC_CPLB_MHIT: | 432 | case VEC_CPLB_MHIT: |
@@ -445,10 +434,10 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
445 | sig = SIGSEGV; | 434 | sig = SIGSEGV; |
446 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | 435 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO |
447 | if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START) | 436 | if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START) |
448 | verbose_printk(KERN_NOTICE "NULL pointer access\n"); | 437 | strerror = KERN_NOTICE "NULL pointer access\n"; |
449 | else | 438 | else |
450 | #endif | 439 | #endif |
451 | verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); | 440 | strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE); |
452 | CHK_DEBUGGER_TRAP_MAYBE(); | 441 | CHK_DEBUGGER_TRAP_MAYBE(); |
453 | break; | 442 | break; |
454 | /* 0x28 - Emulation Watchpoint, handled here */ | 443 | /* 0x28 - Emulation Watchpoint, handled here */ |
@@ -458,7 +447,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
458 | pr_debug(EXC_0x28(KERN_DEBUG)); | 447 | pr_debug(EXC_0x28(KERN_DEBUG)); |
459 | CHK_DEBUGGER_TRAP_MAYBE(); | 448 | CHK_DEBUGGER_TRAP_MAYBE(); |
460 | /* Check if this is a watchpoint in kernel space */ | 449 | /* Check if this is a watchpoint in kernel space */ |
461 | if (fp->ipend & 0xffc0) | 450 | if (kernel_mode_regs(fp)) |
462 | goto traps_done; | 451 | goto traps_done; |
463 | else | 452 | else |
464 | break; | 453 | break; |
@@ -467,7 +456,7 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
467 | case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */ | 456 | case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */ |
468 | info.si_code = BUS_OPFETCH; | 457 | info.si_code = BUS_OPFETCH; |
469 | sig = SIGBUS; | 458 | sig = SIGBUS; |
470 | verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n"); | 459 | strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n"; |
471 | CHK_DEBUGGER_TRAP_MAYBE(); | 460 | CHK_DEBUGGER_TRAP_MAYBE(); |
472 | break; | 461 | break; |
473 | #else | 462 | #else |
@@ -477,21 +466,21 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
477 | case VEC_MISALI_I: | 466 | case VEC_MISALI_I: |
478 | info.si_code = BUS_ADRALN; | 467 | info.si_code = BUS_ADRALN; |
479 | sig = SIGBUS; | 468 | sig = SIGBUS; |
480 | verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); | 469 | strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE); |
481 | CHK_DEBUGGER_TRAP_MAYBE(); | 470 | CHK_DEBUGGER_TRAP_MAYBE(); |
482 | break; | 471 | break; |
483 | /* 0x2B - Instruction CPLB protection violation, handled here */ | 472 | /* 0x2B - Instruction CPLB protection violation, handled here */ |
484 | case VEC_CPLB_I_VL: | 473 | case VEC_CPLB_I_VL: |
485 | info.si_code = ILL_CPLB_VI; | 474 | info.si_code = ILL_CPLB_VI; |
486 | sig = SIGBUS; | 475 | sig = SIGBUS; |
487 | verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); | 476 | strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE); |
488 | CHK_DEBUGGER_TRAP_MAYBE(); | 477 | CHK_DEBUGGER_TRAP_MAYBE(); |
489 | break; | 478 | break; |
490 | /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ | 479 | /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ |
491 | case VEC_CPLB_I_M: | 480 | case VEC_CPLB_I_M: |
492 | info.si_code = ILL_CPLB_MISS; | 481 | info.si_code = ILL_CPLB_MISS; |
493 | sig = SIGBUS; | 482 | sig = SIGBUS; |
494 | verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); | 483 | strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE); |
495 | break; | 484 | break; |
496 | /* 0x2D - Instruction CPLB Multiple Hits, handled here */ | 485 | /* 0x2D - Instruction CPLB Multiple Hits, handled here */ |
497 | case VEC_CPLB_I_MHIT: | 486 | case VEC_CPLB_I_MHIT: |
@@ -499,17 +488,17 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
499 | sig = SIGSEGV; | 488 | sig = SIGSEGV; |
500 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO | 489 | #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO |
501 | if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START) | 490 | if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START) |
502 | verbose_printk(KERN_NOTICE "Jump to NULL address\n"); | 491 | strerror = KERN_NOTICE "Jump to NULL address\n"; |
503 | else | 492 | else |
504 | #endif | 493 | #endif |
505 | verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); | 494 | strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE); |
506 | CHK_DEBUGGER_TRAP_MAYBE(); | 495 | CHK_DEBUGGER_TRAP_MAYBE(); |
507 | break; | 496 | break; |
508 | /* 0x2E - Illegal use of Supervisor Resource, handled here */ | 497 | /* 0x2E - Illegal use of Supervisor Resource, handled here */ |
509 | case VEC_ILL_RES: | 498 | case VEC_ILL_RES: |
510 | info.si_code = ILL_PRVOPC; | 499 | info.si_code = ILL_PRVOPC; |
511 | sig = SIGILL; | 500 | sig = SIGILL; |
512 | verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); | 501 | strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE); |
513 | CHK_DEBUGGER_TRAP_MAYBE(); | 502 | CHK_DEBUGGER_TRAP_MAYBE(); |
514 | break; | 503 | break; |
515 | /* 0x2F - Reserved, Caught by default */ | 504 | /* 0x2F - Reserved, Caught by default */ |
@@ -537,17 +526,17 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
537 | case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): | 526 | case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): |
538 | info.si_code = BUS_ADRALN; | 527 | info.si_code = BUS_ADRALN; |
539 | sig = SIGBUS; | 528 | sig = SIGBUS; |
540 | verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE)); | 529 | strerror = KERN_NOTICE HWC_x2(KERN_NOTICE); |
541 | break; | 530 | break; |
542 | /* External Memory Addressing Error */ | 531 | /* External Memory Addressing Error */ |
543 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): | 532 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): |
544 | info.si_code = BUS_ADRERR; | 533 | info.si_code = BUS_ADRERR; |
545 | sig = SIGBUS; | 534 | sig = SIGBUS; |
546 | verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE)); | 535 | strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); |
547 | break; | 536 | break; |
548 | /* Performance Monitor Overflow */ | 537 | /* Performance Monitor Overflow */ |
549 | case (SEQSTAT_HWERRCAUSE_PERF_FLOW): | 538 | case (SEQSTAT_HWERRCAUSE_PERF_FLOW): |
550 | verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE)); | 539 | strerror = KERN_NOTICE HWC_x12(KERN_NOTICE); |
551 | break; | 540 | break; |
552 | /* RAISE 5 instruction */ | 541 | /* RAISE 5 instruction */ |
553 | case (SEQSTAT_HWERRCAUSE_RAISE_5): | 542 | case (SEQSTAT_HWERRCAUSE_RAISE_5): |
@@ -564,7 +553,6 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
564 | * if we get here we hit a reserved one, so panic | 553 | * if we get here we hit a reserved one, so panic |
565 | */ | 554 | */ |
566 | default: | 555 | default: |
567 | oops_in_progress = 1; | ||
568 | info.si_code = ILL_ILLPARAOP; | 556 | info.si_code = ILL_ILLPARAOP; |
569 | sig = SIGILL; | 557 | sig = SIGILL; |
570 | verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", | 558 | verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", |
@@ -575,6 +563,16 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
575 | 563 | ||
576 | BUG_ON(sig == 0); | 564 | BUG_ON(sig == 0); |
577 | 565 | ||
566 | /* If the fault was caused by a kernel thread, or interrupt handler | ||
567 | * we will kernel panic, so the system reboots. | ||
568 | */ | ||
569 | if (kernel_mode_regs(fp) || (current && !current->mm)) { | ||
570 | console_verbose(); | ||
571 | oops_in_progress = 1; | ||
572 | if (strerror) | ||
573 | verbose_printk(strerror); | ||
574 | } | ||
575 | |||
578 | if (sig != SIGTRAP) { | 576 | if (sig != SIGTRAP) { |
579 | dump_bfin_process(fp); | 577 | dump_bfin_process(fp); |
580 | dump_bfin_mem(fp); | 578 | dump_bfin_mem(fp); |