diff options
-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); |