aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2016-10-14 01:47:31 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-11-13 19:11:51 -0500
commit61a92f703120daf7ed25e046275aa8a2d3085ad4 (patch)
tree0ded0103f9cc2e2a6fc53e0fcc5bb6c4c2329265
parent24bfa6a9e0d4fe414dfc4ad06c93e10c4c37194e (diff)
powerpc: Add support for relative exception tables
This halves the exception table size on 64-bit builds, and it allows build-time sorting of exception tables to work on relocated kernels. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> [mpe: Minor asm fixups and bits to keep the selftests working] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h6
-rw-r--r--arch/powerpc/include/asm/uaccess.h27
-rw-r--r--arch/powerpc/kernel/kprobes.c2
-rw-r--r--arch/powerpc/kernel/traps.c2
-rw-r--r--arch/powerpc/mm/fault.c2
-rw-r--r--arch/powerpc/platforms/embedded6xx/holly.c2
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c2
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c2
-rw-r--r--tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c12
9 files changed, 34 insertions, 23 deletions
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 6af8852d1f7f..bf9de5575ca9 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -785,9 +785,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
785 */ 785 */
786#define EX_TABLE(_fault, _target) \ 786#define EX_TABLE(_fault, _target) \
787 stringify_in_c(.section __ex_table,"a";)\ 787 stringify_in_c(.section __ex_table,"a";)\
788 PPC_LONG_ALIGN stringify_in_c(;) \ 788 stringify_in_c(.balign 4;) \
789 PPC_LONG stringify_in_c(_fault;) \ 789 stringify_in_c(.long (_fault) - . ;) \
790 PPC_LONG stringify_in_c(_target;) \ 790 stringify_in_c(.long (_target) - . ;) \
791 stringify_in_c(.previous) 791 stringify_in_c(.previous)
792 792
793#endif /* _ASM_POWERPC_PPC_ASM_H */ 793#endif /* _ASM_POWERPC_PPC_ASM_H */
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index e0b724619c4a..a15d84d59356 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -64,23 +64,30 @@
64 __access_ok((__force unsigned long)(addr), (size), get_fs())) 64 __access_ok((__force unsigned long)(addr), (size), get_fs()))
65 65
66/* 66/*
67 * The exception table consists of pairs of addresses: the first is the 67 * The exception table consists of pairs of relative addresses: the first is
68 * address of an instruction that is allowed to fault, and the second is 68 * the address of an instruction that is allowed to fault, and the second is
69 * the address at which the program should continue. No registers are 69 * the address at which the program should continue. No registers are
70 * modified, so it is entirely up to the continuation code to figure out 70 * modified, so it is entirely up to the continuation code to figure out what
71 * what to do. 71 * to do.
72 * 72 *
73 * All the routines below use bits of fixup code that are out of line 73 * All the routines below use bits of fixup code that are out of line with the
74 * with the main instruction path. This means when everything is well, 74 * main instruction path. This means when everything is well, we don't even
75 * we don't even have to jump over them. Further, they do not intrude 75 * have to jump over them. Further, they do not intrude on our cache or tlb
76 * on our cache or tlb entries. 76 * entries.
77 */ 77 */
78 78
79#define ARCH_HAS_RELATIVE_EXTABLE
80
79struct exception_table_entry { 81struct exception_table_entry {
80 unsigned long insn; 82 int insn;
81 unsigned long fixup; 83 int fixup;
82}; 84};
83 85
86static inline unsigned long extable_fixup(const struct exception_table_entry *x)
87{
88 return (unsigned long)&x->fixup + x->fixup;
89}
90
84/* 91/*
85 * These are the main single-value transfer routines. They automatically 92 * These are the main single-value transfer routines. They automatically
86 * use the right size if we just have the right pointer type. 93 * use the right size if we just have the right pointer type.
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index e785cc9e1ecd..9479d8e360cf 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -449,7 +449,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
449 * zero, try to fix up. 449 * zero, try to fix up.
450 */ 450 */
451 if ((entry = search_exception_tables(regs->nip)) != NULL) { 451 if ((entry = search_exception_tables(regs->nip)) != NULL) {
452 regs->nip = entry->fixup; 452 regs->nip = extable_fixup(entry);
453 return 1; 453 return 1;
454 } 454 }
455 455
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 023a462725b5..32c468b8b548 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -365,7 +365,7 @@ static inline int check_io_access(struct pt_regs *regs)
365 (*nip & 0x100)? "OUT to": "IN from", 365 (*nip & 0x100)? "OUT to": "IN from",
366 regs->gpr[rb] - _IO_BASE, nip); 366 regs->gpr[rb] - _IO_BASE, nip);
367 regs->msr |= MSR_RI; 367 regs->msr |= MSR_RI;
368 regs->nip = entry->fixup; 368 regs->nip = extable_fixup(entry);
369 return 1; 369 return 1;
370 } 370 }
371 } 371 }
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index d0b137d96df1..73932f4a386e 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -512,7 +512,7 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
512 512
513 /* Are we prepared to handle this fault? */ 513 /* Are we prepared to handle this fault? */
514 if ((entry = search_exception_tables(regs->nip)) != NULL) { 514 if ((entry = search_exception_tables(regs->nip)) != NULL) {
515 regs->nip = entry->fixup; 515 regs->nip = extable_fixup(entry);
516 return; 516 return;
517 } 517 }
518 518
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
index dfd310031549..0409714e8070 100644
--- a/arch/powerpc/platforms/embedded6xx/holly.c
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -263,7 +263,7 @@ static int ppc750_machine_check_exception(struct pt_regs *regs)
263 if ((entry = search_exception_tables(regs->nip)) != NULL) { 263 if ((entry = search_exception_tables(regs->nip)) != NULL) {
264 tsi108_clear_pci_cfg_error(); 264 tsi108_clear_pci_cfg_error();
265 regs->msr |= MSR_RI; 265 regs->msr |= MSR_RI;
266 regs->nip = entry->fixup; 266 regs->nip = extable_fixup(entry);
267 return 1; 267 return 1;
268 } 268 }
269 return 0; 269 return 0;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index f97bab8e37a2..9de100e22bf3 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -174,7 +174,7 @@ static int mpc7448_machine_check_exception(struct pt_regs *regs)
174 if ((entry = search_exception_tables(regs->nip)) != NULL) { 174 if ((entry = search_exception_tables(regs->nip)) != NULL) {
175 tsi108_clear_pci_cfg_error(); 175 tsi108_clear_pci_cfg_error();
176 regs->msr |= MSR_RI; 176 regs->msr |= MSR_RI;
177 regs->nip = entry->fixup; 177 regs->nip = extable_fixup(entry);
178 return 1; 178 return 1;
179 } 179 }
180 return 0; 180 return 0;
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 87fee0c8eb21..1c41c51f22cb 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -111,7 +111,7 @@ int fsl_rio_mcheck_exception(struct pt_regs *regs)
111 out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 111 out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
112 0); 112 0);
113 regs->msr |= MSR_RI; 113 regs->msr |= MSR_RI;
114 regs->nip = entry->fixup; 114 regs->nip = extable_fixup(entry);
115 return 1; 115 return 1;
116 } 116 }
117 } 117 }
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
index cd7af4e1b65a..ed3239bbfae2 100644
--- a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
+++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
@@ -73,19 +73,23 @@ extern char __stop___ex_table[];
73#error implement UCONTEXT_NIA 73#error implement UCONTEXT_NIA
74#endif 74#endif
75 75
76struct extbl_entry {
77 int insn;
78 int fixup;
79};
76 80
77static void segv_handler(int signr, siginfo_t *info, void *ptr) 81static void segv_handler(int signr, siginfo_t *info, void *ptr)
78{ 82{
79 ucontext_t *uc = (ucontext_t *)ptr; 83 ucontext_t *uc = (ucontext_t *)ptr;
80 unsigned long addr = (unsigned long)info->si_addr; 84 unsigned long addr = (unsigned long)info->si_addr;
81 unsigned long *ip = &UCONTEXT_NIA(uc); 85 unsigned long *ip = &UCONTEXT_NIA(uc);
82 unsigned long *ex_p = (unsigned long *)__start___ex_table; 86 struct extbl_entry *entry = (struct extbl_entry *)__start___ex_table;
83 87
84 while (ex_p < (unsigned long *)__stop___ex_table) { 88 while (entry < (struct extbl_entry *)__stop___ex_table) {
85 unsigned long insn, fixup; 89 unsigned long insn, fixup;
86 90
87 insn = *ex_p++; 91 insn = (unsigned long)&entry->insn + entry->insn;
88 fixup = *ex_p++; 92 fixup = (unsigned long)&entry->fixup + entry->fixup;
89 93
90 if (insn == *ip) { 94 if (insn == *ip) {
91 *ip = fixup; 95 *ip = fixup;