diff options
-rw-r--r-- | arch/arm/include/asm/system.h | 8 | ||||
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 8 | ||||
-rw-r--r-- | arch/arm/mm/alignment.c | 2 | ||||
-rw-r--r-- | arch/arm/mm/fault.c | 15 | ||||
-rw-r--r-- | arch/arm/mm/fault.h | 8 | ||||
-rw-r--r-- | arch/arm/mm/fsr-3level.c | 68 |
6 files changed, 104 insertions, 5 deletions
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index fe7de7571bac..53785828744c 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h | |||
@@ -80,6 +80,14 @@ struct siginfo; | |||
80 | void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, | 80 | void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, |
81 | unsigned long err, unsigned long trap); | 81 | unsigned long err, unsigned long trap); |
82 | 82 | ||
83 | #ifdef CONFIG_ARM_LPAE | ||
84 | #define FAULT_CODE_ALIGNMENT 33 | ||
85 | #define FAULT_CODE_DEBUG 34 | ||
86 | #else | ||
87 | #define FAULT_CODE_ALIGNMENT 1 | ||
88 | #define FAULT_CODE_DEBUG 2 | ||
89 | #endif | ||
90 | |||
83 | void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, | 91 | void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, |
84 | struct pt_regs *), | 92 | struct pt_regs *), |
85 | int sig, int code, const char *name); | 93 | int sig, int code, const char *name); |
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 814a52a9dc39..d6a95ef9131d 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c | |||
@@ -1016,10 +1016,10 @@ static int __init arch_hw_breakpoint_init(void) | |||
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | /* Register debug fault handler. */ | 1018 | /* Register debug fault handler. */ |
1019 | hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, | 1019 | hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, |
1020 | "watchpoint debug exception"); | 1020 | TRAP_HWBKPT, "watchpoint debug exception"); |
1021 | hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, | 1021 | hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, |
1022 | "breakpoint debug exception"); | 1022 | TRAP_HWBKPT, "breakpoint debug exception"); |
1023 | 1023 | ||
1024 | /* Register hotplug notifier. */ | 1024 | /* Register hotplug notifier. */ |
1025 | register_cpu_notifier(&dbg_reset_nb); | 1025 | register_cpu_notifier(&dbg_reset_nb); |
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index c335c76e0d88..caf14dc059e5 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c | |||
@@ -968,7 +968,7 @@ static int __init alignment_init(void) | |||
968 | ai_usermode = safe_usermode(ai_usermode, false); | 968 | ai_usermode = safe_usermode(ai_usermode, false); |
969 | } | 969 | } |
970 | 970 | ||
971 | hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN, | 971 | hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN, |
972 | "alignment exception"); | 972 | "alignment exception"); |
973 | 973 | ||
974 | /* | 974 | /* |
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 2a0271677725..eb5520fc755f 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c | |||
@@ -110,8 +110,10 @@ void show_pte(struct mm_struct *mm, unsigned long addr) | |||
110 | 110 | ||
111 | pte = pte_offset_map(pmd, addr); | 111 | pte = pte_offset_map(pmd, addr); |
112 | printk(", *pte=%08llx", (long long)pte_val(*pte)); | 112 | printk(", *pte=%08llx", (long long)pte_val(*pte)); |
113 | #ifndef CONFIG_ARM_LPAE | ||
113 | printk(", *ppte=%08llx", | 114 | printk(", *ppte=%08llx", |
114 | (long long)pte_val(pte[PTE_HWTABLE_PTRS])); | 115 | (long long)pte_val(pte[PTE_HWTABLE_PTRS])); |
116 | #endif | ||
115 | pte_unmap(pte); | 117 | pte_unmap(pte); |
116 | } while(0); | 118 | } while(0); |
117 | 119 | ||
@@ -428,6 +430,12 @@ do_translation_fault(unsigned long addr, unsigned int fsr, | |||
428 | pmd = pmd_offset(pud, addr); | 430 | pmd = pmd_offset(pud, addr); |
429 | pmd_k = pmd_offset(pud_k, addr); | 431 | pmd_k = pmd_offset(pud_k, addr); |
430 | 432 | ||
433 | #ifdef CONFIG_ARM_LPAE | ||
434 | /* | ||
435 | * Only one hardware entry per PMD with LPAE. | ||
436 | */ | ||
437 | index = 0; | ||
438 | #else | ||
431 | /* | 439 | /* |
432 | * On ARM one Linux PGD entry contains two hardware entries (see page | 440 | * On ARM one Linux PGD entry contains two hardware entries (see page |
433 | * tables layout in pgtable.h). We normally guarantee that we always | 441 | * tables layout in pgtable.h). We normally guarantee that we always |
@@ -437,6 +445,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr, | |||
437 | * for the first of pair. | 445 | * for the first of pair. |
438 | */ | 446 | */ |
439 | index = (addr >> SECTION_SHIFT) & 1; | 447 | index = (addr >> SECTION_SHIFT) & 1; |
448 | #endif | ||
440 | if (pmd_none(pmd_k[index])) | 449 | if (pmd_none(pmd_k[index])) |
441 | goto bad_area; | 450 | goto bad_area; |
442 | 451 | ||
@@ -484,7 +493,11 @@ struct fsr_info { | |||
484 | }; | 493 | }; |
485 | 494 | ||
486 | /* FSR definition */ | 495 | /* FSR definition */ |
496 | #ifdef CONFIG_ARM_LPAE | ||
497 | #include "fsr-3level.c" | ||
498 | #else | ||
487 | #include "fsr-2level.c" | 499 | #include "fsr-2level.c" |
500 | #endif | ||
488 | 501 | ||
489 | void __init | 502 | void __init |
490 | hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), | 503 | hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), |
@@ -553,6 +566,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs) | |||
553 | arm_notify_die("", regs, &info, ifsr, 0); | 566 | arm_notify_die("", regs, &info, ifsr, 0); |
554 | } | 567 | } |
555 | 568 | ||
569 | #ifndef CONFIG_ARM_LPAE | ||
556 | static int __init exceptions_init(void) | 570 | static int __init exceptions_init(void) |
557 | { | 571 | { |
558 | if (cpu_architecture() >= CPU_ARCH_ARMv6) { | 572 | if (cpu_architecture() >= CPU_ARCH_ARMv6) { |
@@ -575,3 +589,4 @@ static int __init exceptions_init(void) | |||
575 | } | 589 | } |
576 | 590 | ||
577 | arch_initcall(exceptions_init); | 591 | arch_initcall(exceptions_init); |
592 | #endif | ||
diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index 25b45c105be2..cf08bdfbe0d6 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h | |||
@@ -8,11 +8,19 @@ | |||
8 | #define FSR_WRITE (1 << 11) | 8 | #define FSR_WRITE (1 << 11) |
9 | #define FSR_FS4 (1 << 10) | 9 | #define FSR_FS4 (1 << 10) |
10 | #define FSR_FS3_0 (15) | 10 | #define FSR_FS3_0 (15) |
11 | #define FSR_FS5_0 (0x3f) | ||
11 | 12 | ||
13 | #ifdef CONFIG_ARM_LPAE | ||
14 | static inline int fsr_fs(unsigned int fsr) | ||
15 | { | ||
16 | return fsr & FSR_FS5_0; | ||
17 | } | ||
18 | #else | ||
12 | static inline int fsr_fs(unsigned int fsr) | 19 | static inline int fsr_fs(unsigned int fsr) |
13 | { | 20 | { |
14 | return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6; | 21 | return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6; |
15 | } | 22 | } |
23 | #endif | ||
16 | 24 | ||
17 | void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); | 25 | void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); |
18 | unsigned long search_exception_table(unsigned long addr); | 26 | unsigned long search_exception_table(unsigned long addr); |
diff --git a/arch/arm/mm/fsr-3level.c b/arch/arm/mm/fsr-3level.c new file mode 100644 index 000000000000..05a4e9431836 --- /dev/null +++ b/arch/arm/mm/fsr-3level.c | |||
@@ -0,0 +1,68 @@ | |||
1 | static struct fsr_info fsr_info[] = { | ||
2 | { do_bad, SIGBUS, 0, "unknown 0" }, | ||
3 | { do_bad, SIGBUS, 0, "unknown 1" }, | ||
4 | { do_bad, SIGBUS, 0, "unknown 2" }, | ||
5 | { do_bad, SIGBUS, 0, "unknown 3" }, | ||
6 | { do_bad, SIGBUS, 0, "reserved translation fault" }, | ||
7 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, | ||
8 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, | ||
9 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, | ||
10 | { do_bad, SIGBUS, 0, "reserved access flag fault" }, | ||
11 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, | ||
12 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, | ||
13 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, | ||
14 | { do_bad, SIGBUS, 0, "reserved permission fault" }, | ||
15 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, | ||
16 | { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, | ||
17 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, | ||
18 | { do_bad, SIGBUS, 0, "synchronous external abort" }, | ||
19 | { do_bad, SIGBUS, 0, "asynchronous external abort" }, | ||
20 | { do_bad, SIGBUS, 0, "unknown 18" }, | ||
21 | { do_bad, SIGBUS, 0, "unknown 19" }, | ||
22 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
23 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
24 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
25 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
26 | { do_bad, SIGBUS, 0, "synchronous parity error" }, | ||
27 | { do_bad, SIGBUS, 0, "asynchronous parity error" }, | ||
28 | { do_bad, SIGBUS, 0, "unknown 26" }, | ||
29 | { do_bad, SIGBUS, 0, "unknown 27" }, | ||
30 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
31 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
32 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
33 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
34 | { do_bad, SIGBUS, 0, "unknown 32" }, | ||
35 | { do_bad, SIGBUS, BUS_ADRALN, "alignment fault" }, | ||
36 | { do_bad, SIGBUS, 0, "debug event" }, | ||
37 | { do_bad, SIGBUS, 0, "unknown 35" }, | ||
38 | { do_bad, SIGBUS, 0, "unknown 36" }, | ||
39 | { do_bad, SIGBUS, 0, "unknown 37" }, | ||
40 | { do_bad, SIGBUS, 0, "unknown 38" }, | ||
41 | { do_bad, SIGBUS, 0, "unknown 39" }, | ||
42 | { do_bad, SIGBUS, 0, "unknown 40" }, | ||
43 | { do_bad, SIGBUS, 0, "unknown 41" }, | ||
44 | { do_bad, SIGBUS, 0, "unknown 42" }, | ||
45 | { do_bad, SIGBUS, 0, "unknown 43" }, | ||
46 | { do_bad, SIGBUS, 0, "unknown 44" }, | ||
47 | { do_bad, SIGBUS, 0, "unknown 45" }, | ||
48 | { do_bad, SIGBUS, 0, "unknown 46" }, | ||
49 | { do_bad, SIGBUS, 0, "unknown 47" }, | ||
50 | { do_bad, SIGBUS, 0, "unknown 48" }, | ||
51 | { do_bad, SIGBUS, 0, "unknown 49" }, | ||
52 | { do_bad, SIGBUS, 0, "unknown 50" }, | ||
53 | { do_bad, SIGBUS, 0, "unknown 51" }, | ||
54 | { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" }, | ||
55 | { do_bad, SIGBUS, 0, "unknown 53" }, | ||
56 | { do_bad, SIGBUS, 0, "unknown 54" }, | ||
57 | { do_bad, SIGBUS, 0, "unknown 55" }, | ||
58 | { do_bad, SIGBUS, 0, "unknown 56" }, | ||
59 | { do_bad, SIGBUS, 0, "unknown 57" }, | ||
60 | { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" }, | ||
61 | { do_bad, SIGBUS, 0, "unknown 59" }, | ||
62 | { do_bad, SIGBUS, 0, "unknown 60" }, | ||
63 | { do_bad, SIGBUS, 0, "unknown 61" }, | ||
64 | { do_bad, SIGBUS, 0, "unknown 62" }, | ||
65 | { do_bad, SIGBUS, 0, "unknown 63" }, | ||
66 | }; | ||
67 | |||
68 | #define ifsr_info fsr_info | ||