diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2012-09-05 07:26:11 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-09-26 09:45:10 -0400 |
commit | eb608fb366de123a97227437e5306f731f4a63c5 (patch) | |
tree | 6466e9b0bcd942457e0aa251af48816e3e925d90 | |
parent | 24996edce547fd981c089db9a12717fd76a51160 (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.h | 42 | ||||
-rw-r--r-- | arch/s390/include/asm/uaccess.h | 15 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 4 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/kprobes.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 2 | ||||
-rw-r--r-- | arch/s390/mm/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/mm/extable.c | 81 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 2 | ||||
-rw-r--r-- | scripts/sortextable.c | 10 |
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 | |||
368 | extern int memcpy_real(void *, void *, size_t); | 353 | extern int memcpy_real(void *, void *, size_t); |
369 | extern void memcpy_absolute(void *, void *, size_t); | 354 | extern 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 | ||
77 | struct exception_table_entry | 77 | struct exception_table_entry |
78 | { | 78 | { |
79 | unsigned long insn, fixup; | 79 | int insn, fixup; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static inline unsigned long extable_insn(const struct exception_table_entry *x) | ||
83 | { | ||
84 | return (unsigned long)&x->insn + x->insn; | ||
85 | } | ||
86 | |||
87 | static 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 | |||
82 | struct uaccess_ops { | 95 | struct 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 | ||
256 | static void early_pgm_check_handler(void) | 256 | static 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 | ||
268 | static noinline __init void setup_lowcore_early(void) | 268 | static 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 | ||
5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \ | 5 | obj-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 |
7 | obj-$(CONFIG_CMM) += cmm.o | 7 | obj-$(CONFIG_CMM) += cmm.o |
8 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 8 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
9 | obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o | 9 | obj-$(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 | */ | ||
12 | const struct exception_table_entry * | ||
13 | search_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 | */ | ||
40 | static 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 | |||
48 | void 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 | */ | ||
68 | void 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 | ||
164 | static int compare_x86_table(const void *a, const void *b) | 164 | static 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 | ||
176 | static void sort_x86_table(char *extab_image, int image_size) | 176 | static 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 */ |