Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Heiko Carstens and committed by
Martin Schwidefsky
eb608fb3 24996edc

+132 -33
+24 -18
arch/s390/include/asm/processor.h
··· 11 11 #ifndef __ASM_S390_PROCESSOR_H 12 12 #define __ASM_S390_PROCESSOR_H 13 13 14 + #ifndef __ASSEMBLY__ 15 + 14 16 #include <linux/linkage.h> 15 17 #include <linux/irqflags.h> 16 18 #include <asm/cpu.h> ··· 350 348 351 349 #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL 352 350 353 - /* 354 - * Helper macro for exception table entries 355 - */ 356 - #ifndef CONFIG_64BIT 357 - #define EX_TABLE(_fault,_target) \ 358 - ".section __ex_table,\"a\"\n" \ 359 - " .align 4\n" \ 360 - " .long " #_fault "," #_target "\n" \ 361 - ".previous\n" 362 - #else 363 - #define EX_TABLE(_fault,_target) \ 364 - ".section __ex_table,\"a\"\n" \ 365 - " .align 8\n" \ 366 - " .quad " #_fault "," #_target "\n" \ 367 - ".previous\n" 368 - #endif 369 - 370 351 extern int memcpy_real(void *, void *, size_t); 371 352 extern void memcpy_absolute(void *, void *, size_t); 372 353 ··· 360 375 memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ 361 376 } 362 377 363 - #endif /* __ASM_S390_PROCESSOR_H */ 378 + /* 379 + * Helper macro for exception table entries 380 + */ 381 + #define EX_TABLE(_fault, _target) \ 382 + ".section __ex_table,\"a\"\n" \ 383 + ".align 4\n" \ 384 + ".long (" #_fault ") - .\n" \ 385 + ".long (" #_target ") - .\n" \ 386 + ".previous\n" 387 + 388 + #else /* __ASSEMBLY__ */ 389 + 390 + #define EX_TABLE(_fault, _target) \ 391 + .section __ex_table,"a" ; \ 392 + .align 4 ; \ 393 + .long (_fault) - . ; \ 394 + .long (_target) - . ; \ 395 + .previous 396 + 397 + #endif /* __ASSEMBLY__ */ 398 + 399 + #endif /* __ASM_S390_PROCESSOR_H */
+14 -1
arch/s390/include/asm/uaccess.h
··· 76 76 77 77 struct exception_table_entry 78 78 { 79 - unsigned long insn, fixup; 79 + int insn, fixup; 80 80 }; 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 81 94 82 95 struct uaccess_ops { 83 96 size_t (*copy_from_user)(size_t, const void __user *, void *);
+2 -2
arch/s390/kernel/early.c
··· 255 255 256 256 static void early_pgm_check_handler(void) 257 257 { 258 - unsigned long addr; 259 258 const struct exception_table_entry *fixup; 259 + unsigned long addr; 260 260 261 261 addr = S390_lowcore.program_old_psw.addr; 262 262 fixup = search_exception_tables(addr & PSW_ADDR_INSN); 263 263 if (!fixup) 264 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 268 static noinline __init void setup_lowcore_early(void)
+2 -3
arch/s390/kernel/entry64.S
··· 10 10 11 11 #include <linux/init.h> 12 12 #include <linux/linkage.h> 13 + #include <asm/processor.h> 13 14 #include <asm/cache.h> 14 15 #include <asm/errno.h> 15 16 #include <asm/ptrace.h> ··· 1009 1008 .Lhost_id: 1010 1009 .quad 0 1011 1010 1012 - .section __ex_table,"a" 1013 - .quad sie_loop,sie_fault 1014 - .previous 1011 + EX_TABLE(sie_loop,sie_fault) 1015 1012 #endif 1016 1013 1017 1014 .section .rodata, "a"
+1 -1
arch/s390/kernel/kprobes.c
··· 547 547 */ 548 548 entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 549 549 if (entry) { 550 - regs->psw.addr = entry->fixup | PSW_ADDR_AMODE; 550 + regs->psw.addr = extable_fixup(entry) | PSW_ADDR_AMODE; 551 551 return 1; 552 552 } 553 553
+1 -1
arch/s390/kernel/traps.c
··· 322 322 const struct exception_table_entry *fixup; 323 323 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 324 324 if (fixup) 325 - regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; 325 + regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE; 326 326 else { 327 327 enum bug_trap_type btt; 328 328
+1 -1
arch/s390/mm/Makefile
··· 3 3 # 4 4 5 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 7 obj-$(CONFIG_CMM) += cmm.o 8 8 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 9 9 obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o
+81
arch/s390/mm/extable.c
··· 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 */
+1 -1
arch/s390/mm/fault.c
··· 163 163 /* Are we prepared to handle this kernel fault? */ 164 164 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 165 165 if (fixup) { 166 - regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; 166 + regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE; 167 167 return; 168 168 } 169 169
+5 -5
scripts/sortextable.c
··· 161 161 #define SORTEXTABLE_64 162 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 166 int32_t av = (int32_t)r(a); 167 167 int32_t bv = (int32_t)r(b); ··· 173 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 178 int i; 179 179 ··· 188 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 193 /* Now denormalize. */ 194 194 i = 0; ··· 245 245 break; 246 246 case EM_386: 247 247 case EM_X86_64: 248 - custom_sort = sort_x86_table; 249 - break; 250 248 case EM_S390: 249 + custom_sort = sort_relative_table; 250 + break; 251 251 case EM_MIPS: 252 252 break; 253 253 } /* end switch */