diff options
Diffstat (limited to 'arch/arm/mm/fault.c')
| -rw-r--r-- | arch/arm/mm/fault.c | 75 |
1 files changed, 40 insertions, 35 deletions
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index e25b4fd8412c..65bfe84b6d67 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c | |||
| @@ -372,49 +372,50 @@ do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
| 372 | static struct fsr_info { | 372 | static struct fsr_info { |
| 373 | int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); | 373 | int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); |
| 374 | int sig; | 374 | int sig; |
| 375 | int code; | ||
| 375 | const char *name; | 376 | const char *name; |
| 376 | } fsr_info[] = { | 377 | } fsr_info[] = { |
| 377 | /* | 378 | /* |
| 378 | * The following are the standard ARMv3 and ARMv4 aborts. ARMv5 | 379 | * The following are the standard ARMv3 and ARMv4 aborts. ARMv5 |
| 379 | * defines these to be "precise" aborts. | 380 | * defines these to be "precise" aborts. |
| 380 | */ | 381 | */ |
| 381 | { do_bad, SIGSEGV, "vector exception" }, | 382 | { do_bad, SIGSEGV, 0, "vector exception" }, |
| 382 | { do_bad, SIGILL, "alignment exception" }, | 383 | { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, |
| 383 | { do_bad, SIGKILL, "terminal exception" }, | 384 | { do_bad, SIGKILL, 0, "terminal exception" }, |
| 384 | { do_bad, SIGILL, "alignment exception" }, | 385 | { do_bad, SIGILL, BUS_ADRALN, "alignment exception" }, |
| 385 | { do_bad, SIGBUS, "external abort on linefetch" }, | 386 | { do_bad, SIGBUS, 0, "external abort on linefetch" }, |
| 386 | { do_translation_fault, SIGSEGV, "section translation fault" }, | 387 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, |
| 387 | { do_bad, SIGBUS, "external abort on linefetch" }, | 388 | { do_bad, SIGBUS, 0, "external abort on linefetch" }, |
| 388 | { do_page_fault, SIGSEGV, "page translation fault" }, | 389 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, |
| 389 | { do_bad, SIGBUS, "external abort on non-linefetch" }, | 390 | { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, |
| 390 | { do_bad, SIGSEGV, "section domain fault" }, | 391 | { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" }, |
| 391 | { do_bad, SIGBUS, "external abort on non-linefetch" }, | 392 | { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, |
| 392 | { do_bad, SIGSEGV, "page domain fault" }, | 393 | { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" }, |
| 393 | { do_bad, SIGBUS, "external abort on translation" }, | 394 | { do_bad, SIGBUS, 0, "external abort on translation" }, |
| 394 | { do_sect_fault, SIGSEGV, "section permission fault" }, | 395 | { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" }, |
| 395 | { do_bad, SIGBUS, "external abort on translation" }, | 396 | { do_bad, SIGBUS, 0, "external abort on translation" }, |
| 396 | { do_page_fault, SIGSEGV, "page permission fault" }, | 397 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, |
| 397 | /* | 398 | /* |
| 398 | * The following are "imprecise" aborts, which are signalled by bit | 399 | * The following are "imprecise" aborts, which are signalled by bit |
| 399 | * 10 of the FSR, and may not be recoverable. These are only | 400 | * 10 of the FSR, and may not be recoverable. These are only |
| 400 | * supported if the CPU abort handler supports bit 10. | 401 | * supported if the CPU abort handler supports bit 10. |
| 401 | */ | 402 | */ |
| 402 | { do_bad, SIGBUS, "unknown 16" }, | 403 | { do_bad, SIGBUS, 0, "unknown 16" }, |
| 403 | { do_bad, SIGBUS, "unknown 17" }, | 404 | { do_bad, SIGBUS, 0, "unknown 17" }, |
| 404 | { do_bad, SIGBUS, "unknown 18" }, | 405 | { do_bad, SIGBUS, 0, "unknown 18" }, |
| 405 | { do_bad, SIGBUS, "unknown 19" }, | 406 | { do_bad, SIGBUS, 0, "unknown 19" }, |
| 406 | { do_bad, SIGBUS, "lock abort" }, /* xscale */ | 407 | { do_bad, SIGBUS, 0, "lock abort" }, /* xscale */ |
| 407 | { do_bad, SIGBUS, "unknown 21" }, | 408 | { do_bad, SIGBUS, 0, "unknown 21" }, |
| 408 | { do_bad, SIGBUS, "imprecise external abort" }, /* xscale */ | 409 | { do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */ |
| 409 | { do_bad, SIGBUS, "unknown 23" }, | 410 | { do_bad, SIGBUS, 0, "unknown 23" }, |
| 410 | { do_bad, SIGBUS, "dcache parity error" }, /* xscale */ | 411 | { do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */ |
| 411 | { do_bad, SIGBUS, "unknown 25" }, | 412 | { do_bad, SIGBUS, 0, "unknown 25" }, |
| 412 | { do_bad, SIGBUS, "unknown 26" }, | 413 | { do_bad, SIGBUS, 0, "unknown 26" }, |
| 413 | { do_bad, SIGBUS, "unknown 27" }, | 414 | { do_bad, SIGBUS, 0, "unknown 27" }, |
| 414 | { do_bad, SIGBUS, "unknown 28" }, | 415 | { do_bad, SIGBUS, 0, "unknown 28" }, |
| 415 | { do_bad, SIGBUS, "unknown 29" }, | 416 | { do_bad, SIGBUS, 0, "unknown 29" }, |
| 416 | { do_bad, SIGBUS, "unknown 30" }, | 417 | { do_bad, SIGBUS, 0, "unknown 30" }, |
| 417 | { do_bad, SIGBUS, "unknown 31" } | 418 | { do_bad, SIGBUS, 0, "unknown 31" } |
| 418 | }; | 419 | }; |
| 419 | 420 | ||
| 420 | void __init | 421 | void __init |
| @@ -435,15 +436,19 @@ asmlinkage void | |||
| 435 | do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | 436 | do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) |
| 436 | { | 437 | { |
| 437 | const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); | 438 | const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); |
| 439 | struct siginfo info; | ||
| 438 | 440 | ||
| 439 | if (!inf->fn(addr, fsr, regs)) | 441 | if (!inf->fn(addr, fsr, regs)) |
| 440 | return; | 442 | return; |
| 441 | 443 | ||
| 442 | printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", | 444 | printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", |
| 443 | inf->name, fsr, addr); | 445 | inf->name, fsr, addr); |
| 444 | force_sig(inf->sig, current); | 446 | |
| 445 | show_pte(current->mm, addr); | 447 | info.si_signo = inf->sig; |
| 446 | die_if_kernel("Oops", regs, 0); | 448 | info.si_errno = 0; |
| 449 | info.si_code = inf->code; | ||
| 450 | info.si_addr = (void __user *)addr; | ||
| 451 | notify_die("", regs, &info, fsr, 0); | ||
| 447 | } | 452 | } |
| 448 | 453 | ||
| 449 | asmlinkage void | 454 | asmlinkage void |
