aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2012-09-05 07:26:11 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-26 09:45:10 -0400
commiteb608fb366de123a97227437e5306f731f4a63c5 (patch)
tree6466e9b0bcd942457e0aa251af48816e3e925d90
parent24996edce547fd981c089db9a12717fd76a51160 (diff)
s390/exceptions: switch to relative exception table entries
This is the s390 port of 70627654 "x86, extable: Switch to relative exception table entries". Reduces the size of our exception tables by 50% on 64 bit builds. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/processor.h42
-rw-r--r--arch/s390/include/asm/uaccess.h15
-rw-r--r--arch/s390/kernel/early.c4
-rw-r--r--arch/s390/kernel/entry64.S5
-rw-r--r--arch/s390/kernel/kprobes.c2
-rw-r--r--arch/s390/kernel/traps.c2
-rw-r--r--arch/s390/mm/Makefile2
-rw-r--r--arch/s390/mm/extable.c81
-rw-r--r--arch/s390/mm/fault.c2
-rw-r--r--scripts/sortextable.c10
10 files changed, 132 insertions, 33 deletions
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 7e81ff17a89b..f3e0aabfc6bc 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -11,6 +11,8 @@
11#ifndef __ASM_S390_PROCESSOR_H 11#ifndef __ASM_S390_PROCESSOR_H
12#define __ASM_S390_PROCESSOR_H 12#define __ASM_S390_PROCESSOR_H
13 13
14#ifndef __ASSEMBLY__
15
14#include <linux/linkage.h> 16#include <linux/linkage.h>
15#include <linux/irqflags.h> 17#include <linux/irqflags.h>
16#include <asm/cpu.h> 18#include <asm/cpu.h>
@@ -348,23 +350,6 @@ extern void (*s390_base_ext_handler_fn)(void);
348 350
349#define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL 351#define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL
350 352
351/*
352 * Helper macro for exception table entries
353 */
354#ifndef CONFIG_64BIT
355#define EX_TABLE(_fault,_target) \
356 ".section __ex_table,\"a\"\n" \
357 " .align 4\n" \
358 " .long " #_fault "," #_target "\n" \
359 ".previous\n"
360#else
361#define EX_TABLE(_fault,_target) \
362 ".section __ex_table,\"a\"\n" \
363 " .align 8\n" \
364 " .quad " #_fault "," #_target "\n" \
365 ".previous\n"
366#endif
367
368extern int memcpy_real(void *, void *, size_t); 353extern int memcpy_real(void *, void *, size_t);
369extern void memcpy_absolute(void *, void *, size_t); 354extern void memcpy_absolute(void *, void *, size_t);
370 355
@@ -375,4 +360,25 @@ extern void memcpy_absolute(void *, void *, size_t);
375 memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ 360 memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \
376} 361}
377 362
378#endif /* __ASM_S390_PROCESSOR_H */ 363/*
364 * Helper macro for exception table entries
365 */
366#define EX_TABLE(_fault, _target) \
367 ".section __ex_table,\"a\"\n" \
368 ".align 4\n" \
369 ".long (" #_fault ") - .\n" \
370 ".long (" #_target ") - .\n" \
371 ".previous\n"
372
373#else /* __ASSEMBLY__ */
374
375#define EX_TABLE(_fault, _target) \
376 .section __ex_table,"a" ; \
377 .align 4 ; \
378 .long (_fault) - . ; \
379 .long (_target) - . ; \
380 .previous
381
382#endif /* __ASSEMBLY__ */
383
384#endif /* __ASM_S390_PROCESSOR_H */
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index a8ab18b18b54..34268df959a3 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -76,9 +76,22 @@ static inline int __range_ok(unsigned long addr, unsigned long size)
76 76
77struct exception_table_entry 77struct exception_table_entry
78{ 78{
79 unsigned long insn, fixup; 79 int insn, fixup;
80}; 80};
81 81
82static inline unsigned long extable_insn(const struct exception_table_entry *x)
83{
84 return (unsigned long)&x->insn + x->insn;
85}
86
87static inline unsigned long extable_fixup(const struct exception_table_entry *x)
88{
89 return (unsigned long)&x->fixup + x->fixup;
90}
91
92#define ARCH_HAS_SORT_EXTABLE
93#define ARCH_HAS_SEARCH_EXTABLE
94
82struct uaccess_ops { 95struct uaccess_ops {
83 size_t (*copy_from_user)(size_t, const void __user *, void *); 96 size_t (*copy_from_user)(size_t, const void __user *, void *);
84 size_t (*copy_from_user_small)(size_t, const void __user *, void *); 97 size_t (*copy_from_user_small)(size_t, const void __user *, void *);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index f4bcdc01bfc8..e8000d5ff533 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -255,14 +255,14 @@ static __init void setup_topology(void)
255 255
256static void early_pgm_check_handler(void) 256static void early_pgm_check_handler(void)
257{ 257{
258 unsigned long addr;
259 const struct exception_table_entry *fixup; 258 const struct exception_table_entry *fixup;
259 unsigned long addr;
260 260
261 addr = S390_lowcore.program_old_psw.addr; 261 addr = S390_lowcore.program_old_psw.addr;
262 fixup = search_exception_tables(addr & PSW_ADDR_INSN); 262 fixup = search_exception_tables(addr & PSW_ADDR_INSN);
263 if (!fixup) 263 if (!fixup)
264 disabled_wait(0); 264 disabled_wait(0);
265 S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; 265 S390_lowcore.program_old_psw.addr = extable_fixup(fixup)|PSW_ADDR_AMODE;
266} 266}
267 267
268static noinline __init void setup_lowcore_early(void) 268static noinline __init void setup_lowcore_early(void)
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 95e9d93d4f41..7549985402f7 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -10,6 +10,7 @@
10 10
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/linkage.h> 12#include <linux/linkage.h>
13#include <asm/processor.h>
13#include <asm/cache.h> 14#include <asm/cache.h>
14#include <asm/errno.h> 15#include <asm/errno.h>
15#include <asm/ptrace.h> 16#include <asm/ptrace.h>
@@ -1008,9 +1009,7 @@ sie_fault:
1008.Lhost_id: 1009.Lhost_id:
1009 .quad 0 1010 .quad 0
1010 1011
1011 .section __ex_table,"a" 1012 EX_TABLE(sie_loop,sie_fault)
1012 .quad sie_loop,sie_fault
1013 .previous
1014#endif 1013#endif
1015 1014
1016 .section .rodata, "a" 1015 .section .rodata, "a"
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 8aa634f5944b..d1c7214e157c 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -547,7 +547,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
547 */ 547 */
548 entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 548 entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
549 if (entry) { 549 if (entry) {
550 regs->psw.addr = entry->fixup | PSW_ADDR_AMODE; 550 regs->psw.addr = extable_fixup(entry) | PSW_ADDR_AMODE;
551 return 1; 551 return 1;
552 } 552 }
553 553
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 29af52628e8b..befc761fc154 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -322,7 +322,7 @@ static void __kprobes do_trap(struct pt_regs *regs,
322 const struct exception_table_entry *fixup; 322 const struct exception_table_entry *fixup;
323 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 323 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
324 if (fixup) 324 if (fixup)
325 regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; 325 regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE;
326 else { 326 else {
327 enum bug_trap_type btt; 327 enum bug_trap_type btt;
328 328
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index d98fe9004a52..0f5536b0c1a1 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \ 5obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
6 page-states.o gup.o 6 page-states.o gup.o extable.o
7obj-$(CONFIG_CMM) += cmm.o 7obj-$(CONFIG_CMM) += cmm.o
8obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 8obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
9obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o 9obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o
diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c
new file mode 100644
index 000000000000..4d1ee88864e8
--- /dev/null
+++ b/arch/s390/mm/extable.c
@@ -0,0 +1,81 @@
1#include <linux/module.h>
2#include <linux/sort.h>
3#include <asm/uaccess.h>
4
5/*
6 * Search one exception table for an entry corresponding to the
7 * given instruction address, and return the address of the entry,
8 * or NULL if none is found.
9 * We use a binary search, and thus we assume that the table is
10 * already sorted.
11 */
12const struct exception_table_entry *
13search_extable(const struct exception_table_entry *first,
14 const struct exception_table_entry *last,
15 unsigned long value)
16{
17 const struct exception_table_entry *mid;
18 unsigned long addr;
19
20 while (first <= last) {
21 mid = ((last - first) >> 1) + first;
22 addr = extable_insn(mid);
23 if (addr < value)
24 first = mid + 1;
25 else if (addr > value)
26 last = mid - 1;
27 else
28 return mid;
29 }
30 return NULL;
31}
32
33/*
34 * The exception table needs to be sorted so that the binary
35 * search that we use to find entries in it works properly.
36 * This is used both for the kernel exception table and for
37 * the exception tables of modules that get loaded.
38 *
39 */
40static int cmp_ex(const void *a, const void *b)
41{
42 const struct exception_table_entry *x = a, *y = b;
43
44 /* This compare is only valid after normalization. */
45 return x->insn - y->insn;
46}
47
48void sort_extable(struct exception_table_entry *start,
49 struct exception_table_entry *finish)
50{
51 struct exception_table_entry *p;
52 int i;
53
54 /* Normalize entries to being relative to the start of the section */
55 for (p = start, i = 0; p < finish; p++, i += 8)
56 p->insn += i;
57 sort(start, finish - start, sizeof(*start), cmp_ex, NULL);
58 /* Denormalize all entries */
59 for (p = start, i = 0; p < finish; p++, i += 8)
60 p->insn -= i;
61}
62
63#ifdef CONFIG_MODULES
64/*
65 * If the exception table is sorted, any referring to the module init
66 * will be at the beginning or the end.
67 */
68void trim_init_extable(struct module *m)
69{
70 /* Trim the beginning */
71 while (m->num_exentries &&
72 within_module_init(extable_insn(&m->extable[0]), m)) {
73 m->extable++;
74 m->num_exentries--;
75 }
76 /* Trim the end */
77 while (m->num_exentries &&
78 within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m))
79 m->num_exentries--;
80}
81#endif /* CONFIG_MODULES */
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 8b2cac1ddbc5..ac9122ca1152 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -163,7 +163,7 @@ static noinline void do_no_context(struct pt_regs *regs)
163 /* Are we prepared to handle this kernel fault? */ 163 /* Are we prepared to handle this kernel fault? */
164 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 164 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
165 if (fixup) { 165 if (fixup) {
166 regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; 166 regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE;
167 return; 167 return;
168 } 168 }
169 169
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index 6acf83449105..f19ddc47304c 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -161,7 +161,7 @@ typedef void (*table_sort_t)(char *, int);
161#define SORTEXTABLE_64 161#define SORTEXTABLE_64
162#include "sortextable.h" 162#include "sortextable.h"
163 163
164static int compare_x86_table(const void *a, const void *b) 164static int compare_relative_table(const void *a, const void *b)
165{ 165{
166 int32_t av = (int32_t)r(a); 166 int32_t av = (int32_t)r(a);
167 int32_t bv = (int32_t)r(b); 167 int32_t bv = (int32_t)r(b);
@@ -173,7 +173,7 @@ static int compare_x86_table(const void *a, const void *b)
173 return 0; 173 return 0;
174} 174}
175 175
176static void sort_x86_table(char *extab_image, int image_size) 176static void sort_relative_table(char *extab_image, int image_size)
177{ 177{
178 int i; 178 int i;
179 179
@@ -188,7 +188,7 @@ static void sort_x86_table(char *extab_image, int image_size)
188 i += 4; 188 i += 4;
189 } 189 }
190 190
191 qsort(extab_image, image_size / 8, 8, compare_x86_table); 191 qsort(extab_image, image_size / 8, 8, compare_relative_table);
192 192
193 /* Now denormalize. */ 193 /* Now denormalize. */
194 i = 0; 194 i = 0;
@@ -245,9 +245,9 @@ do_file(char const *const fname)
245 break; 245 break;
246 case EM_386: 246 case EM_386:
247 case EM_X86_64: 247 case EM_X86_64:
248 custom_sort = sort_x86_table;
249 break;
250 case EM_S390: 248 case EM_S390:
249 custom_sort = sort_relative_table;
250 break;
251 case EM_MIPS: 251 case EM_MIPS:
252 break; 252 break;
253 } /* end switch */ 253 } /* end switch */