diff options
Diffstat (limited to 'arch/arm/mm/fault.c')
-rw-r--r-- | arch/arm/mm/fault.c | 111 |
1 files changed, 19 insertions, 92 deletions
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 4aabeaec25df..bb7eac381a8e 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c | |||
@@ -27,19 +27,6 @@ | |||
27 | 27 | ||
28 | #include "fault.h" | 28 | #include "fault.h" |
29 | 29 | ||
30 | /* | ||
31 | * Fault status register encodings. We steal bit 31 for our own purposes. | ||
32 | */ | ||
33 | #define FSR_LNX_PF (1 << 31) | ||
34 | #define FSR_WRITE (1 << 11) | ||
35 | #define FSR_FS4 (1 << 10) | ||
36 | #define FSR_FS3_0 (15) | ||
37 | |||
38 | static inline int fsr_fs(unsigned int fsr) | ||
39 | { | ||
40 | return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6; | ||
41 | } | ||
42 | |||
43 | #ifdef CONFIG_MMU | 30 | #ifdef CONFIG_MMU |
44 | 31 | ||
45 | #ifdef CONFIG_KPROBES | 32 | #ifdef CONFIG_KPROBES |
@@ -123,8 +110,10 @@ void show_pte(struct mm_struct *mm, unsigned long addr) | |||
123 | 110 | ||
124 | pte = pte_offset_map(pmd, addr); | 111 | pte = pte_offset_map(pmd, addr); |
125 | printk(", *pte=%08llx", (long long)pte_val(*pte)); | 112 | printk(", *pte=%08llx", (long long)pte_val(*pte)); |
113 | #ifndef CONFIG_ARM_LPAE | ||
126 | printk(", *ppte=%08llx", | 114 | printk(", *ppte=%08llx", |
127 | (long long)pte_val(pte[PTE_HWTABLE_PTRS])); | 115 | (long long)pte_val(pte[PTE_HWTABLE_PTRS])); |
116 | #endif | ||
128 | pte_unmap(pte); | 117 | pte_unmap(pte); |
129 | } while(0); | 118 | } while(0); |
130 | 119 | ||
@@ -461,6 +450,12 @@ do_translation_fault(unsigned long addr, unsigned int fsr, | |||
461 | pmd = pmd_offset(pud, addr); | 450 | pmd = pmd_offset(pud, addr); |
462 | pmd_k = pmd_offset(pud_k, addr); | 451 | pmd_k = pmd_offset(pud_k, addr); |
463 | 452 | ||
453 | #ifdef CONFIG_ARM_LPAE | ||
454 | /* | ||
455 | * Only one hardware entry per PMD with LPAE. | ||
456 | */ | ||
457 | index = 0; | ||
458 | #else | ||
464 | /* | 459 | /* |
465 | * On ARM one Linux PGD entry contains two hardware entries (see page | 460 | * On ARM one Linux PGD entry contains two hardware entries (see page |
466 | * tables layout in pgtable.h). We normally guarantee that we always | 461 | * tables layout in pgtable.h). We normally guarantee that we always |
@@ -470,6 +465,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr, | |||
470 | * for the first of pair. | 465 | * for the first of pair. |
471 | */ | 466 | */ |
472 | index = (addr >> SECTION_SHIFT) & 1; | 467 | index = (addr >> SECTION_SHIFT) & 1; |
468 | #endif | ||
473 | if (pmd_none(pmd_k[index])) | 469 | if (pmd_none(pmd_k[index])) |
474 | goto bad_area; | 470 | goto bad_area; |
475 | 471 | ||
@@ -509,55 +505,20 @@ do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
509 | return 1; | 505 | return 1; |
510 | } | 506 | } |
511 | 507 | ||
512 | static struct fsr_info { | 508 | struct fsr_info { |
513 | int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); | 509 | int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); |
514 | int sig; | 510 | int sig; |
515 | int code; | 511 | int code; |
516 | const char *name; | 512 | const char *name; |
517 | } fsr_info[] = { | ||
518 | /* | ||
519 | * The following are the standard ARMv3 and ARMv4 aborts. ARMv5 | ||
520 | * defines these to be "precise" aborts. | ||
521 | */ | ||
522 | { do_bad, SIGSEGV, 0, "vector exception" }, | ||
523 | { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, | ||
524 | { do_bad, SIGKILL, 0, "terminal exception" }, | ||
525 | { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" }, | ||
526 | { do_bad, SIGBUS, 0, "external abort on linefetch" }, | ||
527 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, | ||
528 | { do_bad, SIGBUS, 0, "external abort on linefetch" }, | ||
529 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, | ||
530 | { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, | ||
531 | { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" }, | ||
532 | { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, | ||
533 | { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" }, | ||
534 | { do_bad, SIGBUS, 0, "external abort on translation" }, | ||
535 | { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" }, | ||
536 | { do_bad, SIGBUS, 0, "external abort on translation" }, | ||
537 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, | ||
538 | /* | ||
539 | * The following are "imprecise" aborts, which are signalled by bit | ||
540 | * 10 of the FSR, and may not be recoverable. These are only | ||
541 | * supported if the CPU abort handler supports bit 10. | ||
542 | */ | ||
543 | { do_bad, SIGBUS, 0, "unknown 16" }, | ||
544 | { do_bad, SIGBUS, 0, "unknown 17" }, | ||
545 | { do_bad, SIGBUS, 0, "unknown 18" }, | ||
546 | { do_bad, SIGBUS, 0, "unknown 19" }, | ||
547 | { do_bad, SIGBUS, 0, "lock abort" }, /* xscale */ | ||
548 | { do_bad, SIGBUS, 0, "unknown 21" }, | ||
549 | { do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */ | ||
550 | { do_bad, SIGBUS, 0, "unknown 23" }, | ||
551 | { do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */ | ||
552 | { do_bad, SIGBUS, 0, "unknown 25" }, | ||
553 | { do_bad, SIGBUS, 0, "unknown 26" }, | ||
554 | { do_bad, SIGBUS, 0, "unknown 27" }, | ||
555 | { do_bad, SIGBUS, 0, "unknown 28" }, | ||
556 | { do_bad, SIGBUS, 0, "unknown 29" }, | ||
557 | { do_bad, SIGBUS, 0, "unknown 30" }, | ||
558 | { do_bad, SIGBUS, 0, "unknown 31" } | ||
559 | }; | 513 | }; |
560 | 514 | ||
515 | /* FSR definition */ | ||
516 | #ifdef CONFIG_ARM_LPAE | ||
517 | #include "fsr-3level.c" | ||
518 | #else | ||
519 | #include "fsr-2level.c" | ||
520 | #endif | ||
521 | |||
561 | void __init | 522 | void __init |
562 | hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), | 523 | hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), |
563 | int sig, int code, const char *name) | 524 | int sig, int code, const char *name) |
@@ -593,42 +554,6 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
593 | arm_notify_die("", regs, &info, fsr, 0); | 554 | arm_notify_die("", regs, &info, fsr, 0); |
594 | } | 555 | } |
595 | 556 | ||
596 | |||
597 | static struct fsr_info ifsr_info[] = { | ||
598 | { do_bad, SIGBUS, 0, "unknown 0" }, | ||
599 | { do_bad, SIGBUS, 0, "unknown 1" }, | ||
600 | { do_bad, SIGBUS, 0, "debug event" }, | ||
601 | { do_bad, SIGSEGV, SEGV_ACCERR, "section access flag fault" }, | ||
602 | { do_bad, SIGBUS, 0, "unknown 4" }, | ||
603 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, | ||
604 | { do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" }, | ||
605 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, | ||
606 | { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, | ||
607 | { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" }, | ||
608 | { do_bad, SIGBUS, 0, "unknown 10" }, | ||
609 | { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" }, | ||
610 | { do_bad, SIGBUS, 0, "external abort on translation" }, | ||
611 | { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" }, | ||
612 | { do_bad, SIGBUS, 0, "external abort on translation" }, | ||
613 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, | ||
614 | { do_bad, SIGBUS, 0, "unknown 16" }, | ||
615 | { do_bad, SIGBUS, 0, "unknown 17" }, | ||
616 | { do_bad, SIGBUS, 0, "unknown 18" }, | ||
617 | { do_bad, SIGBUS, 0, "unknown 19" }, | ||
618 | { do_bad, SIGBUS, 0, "unknown 20" }, | ||
619 | { do_bad, SIGBUS, 0, "unknown 21" }, | ||
620 | { do_bad, SIGBUS, 0, "unknown 22" }, | ||
621 | { do_bad, SIGBUS, 0, "unknown 23" }, | ||
622 | { do_bad, SIGBUS, 0, "unknown 24" }, | ||
623 | { do_bad, SIGBUS, 0, "unknown 25" }, | ||
624 | { do_bad, SIGBUS, 0, "unknown 26" }, | ||
625 | { do_bad, SIGBUS, 0, "unknown 27" }, | ||
626 | { do_bad, SIGBUS, 0, "unknown 28" }, | ||
627 | { do_bad, SIGBUS, 0, "unknown 29" }, | ||
628 | { do_bad, SIGBUS, 0, "unknown 30" }, | ||
629 | { do_bad, SIGBUS, 0, "unknown 31" }, | ||
630 | }; | ||
631 | |||
632 | void __init | 557 | void __init |
633 | hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), | 558 | hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), |
634 | int sig, int code, const char *name) | 559 | int sig, int code, const char *name) |
@@ -661,6 +586,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) | |||
661 | arm_notify_die("", regs, &info, ifsr, 0); | 586 | arm_notify_die("", regs, &info, ifsr, 0); |
662 | } | 587 | } |
663 | 588 | ||
589 | #ifndef CONFIG_ARM_LPAE | ||
664 | static int __init exceptions_init(void) | 590 | static int __init exceptions_init(void) |
665 | { | 591 | { |
666 | if (cpu_architecture() >= CPU_ARCH_ARMv6) { | 592 | if (cpu_architecture() >= CPU_ARCH_ARMv6) { |
@@ -683,3 +609,4 @@ static int __init exceptions_init(void) | |||
683 | } | 609 | } |
684 | 610 | ||
685 | arch_initcall(exceptions_init); | 611 | arch_initcall(exceptions_init); |
612 | #endif | ||