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

[POWERPC] Support feature fixups in modules

This patch adds support for feature fixups in modules. This involves
adding support for R_PPC64_REL64 relocs to the 64 bits module loader.
It also modifies modpost.c to ignore the powerpc fixup sections (or it
would warn when used in .init.text).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Benjamin Herrenschmidt and committed by
Paul Mackerras
21c4ff80 0909c8c2

+71 -19
+29 -10
arch/powerpc/kernel/module_32.c
··· 24 24 #include <linux/kernel.h> 25 25 #include <linux/cache.h> 26 26 27 + #include "setup.h" 28 + 27 29 #if 0 28 30 #define DEBUGP printk 29 31 #else ··· 271 269 return 0; 272 270 } 273 271 272 + static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, 273 + const Elf_Shdr *sechdrs, 274 + const char *name) 275 + { 276 + char *secstrings; 277 + unsigned int i; 278 + 279 + secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 280 + for (i = 1; i < hdr->e_shnum; i++) 281 + if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) 282 + return &sechdrs[i]; 283 + return NULL; 284 + } 285 + 274 286 int module_finalize(const Elf_Ehdr *hdr, 275 287 const Elf_Shdr *sechdrs, 276 288 struct module *me) 277 289 { 278 - char *secstrings; 279 - unsigned int i; 290 + const Elf_Shdr *sect; 280 291 281 292 me->arch.bug_table = NULL; 282 293 me->arch.num_bugs = 0; 283 294 284 295 /* Find the __bug_table section, if present */ 285 - secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 286 - for (i = 1; i < hdr->e_shnum; i++) { 287 - if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) 288 - continue; 289 - me->arch.bug_table = (void *) sechdrs[i].sh_addr; 290 - me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); 291 - break; 296 + sect = find_section(hdr, sechdrs, "__bug_table"); 297 + if (sect != NULL) { 298 + me->arch.bug_table = (void *) sect->sh_addr; 299 + me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry); 292 300 } 293 301 294 - /* 302 + /* 295 303 * Strictly speaking this should have a spinlock to protect against 296 304 * traversals, but since we only traverse on BUG()s, a spinlock 297 305 * could potentially lead to deadlock and thus be counter-productive. 298 306 */ 299 307 list_add(&me->arch.bug_list, &module_bug_list); 308 + 309 + /* Apply feature fixups */ 310 + sect = find_section(hdr, sechdrs, "__ftr_fixup"); 311 + if (sect != NULL) 312 + do_feature_fixups(cur_cpu_spec->cpu_features, 313 + (void *)sect->sh_addr, 314 + (void *)sect->sh_addr + sect->sh_size); 300 315 301 316 return 0; 302 317 }
+40 -9
arch/powerpc/kernel/module_64.c
··· 22 22 #include <linux/vmalloc.h> 23 23 #include <asm/module.h> 24 24 #include <asm/uaccess.h> 25 + #include <asm/firmware.h> 26 + 27 + #include "setup.h" 25 28 26 29 /* FIXME: We don't do .init separately. To do this, we'd need to have 27 30 a separate r2 value in the init and core section, and stub between ··· 403 400 | (value & 0x03fffffc); 404 401 break; 405 402 403 + case R_PPC64_REL64: 404 + /* 64 bits relative (used by features fixups) */ 405 + *location = value - (unsigned long)location; 406 + break; 407 + 406 408 default: 407 409 printk("%s: Unknown ADD relocation: %lu\n", 408 410 me->name, ··· 421 413 422 414 LIST_HEAD(module_bug_list); 423 415 424 - int module_finalize(const Elf_Ehdr *hdr, 425 - const Elf_Shdr *sechdrs, struct module *me) 416 + static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, 417 + const Elf_Shdr *sechdrs, 418 + const char *name) 426 419 { 427 420 char *secstrings; 428 421 unsigned int i; 422 + 423 + secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 424 + for (i = 1; i < hdr->e_shnum; i++) 425 + if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) 426 + return &sechdrs[i]; 427 + return NULL; 428 + } 429 + 430 + int module_finalize(const Elf_Ehdr *hdr, 431 + const Elf_Shdr *sechdrs, struct module *me) 432 + { 433 + const Elf_Shdr *sect; 429 434 430 435 me->arch.bug_table = NULL; 431 436 me->arch.num_bugs = 0; 432 437 433 438 /* Find the __bug_table section, if present */ 434 - secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 435 - for (i = 1; i < hdr->e_shnum; i++) { 436 - if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) 437 - continue; 438 - me->arch.bug_table = (void *) sechdrs[i].sh_addr; 439 - me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); 440 - break; 439 + sect = find_section(hdr, sechdrs, "__bug_table"); 440 + if (sect != NULL) { 441 + me->arch.bug_table = (void *) sect->sh_addr; 442 + me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry); 441 443 } 442 444 443 445 /* ··· 456 438 * could potentially lead to deadlock and thus be counter-productive. 457 439 */ 458 440 list_add(&me->arch.bug_list, &module_bug_list); 441 + 442 + /* Apply feature fixups */ 443 + sect = find_section(hdr, sechdrs, "__ftr_fixup"); 444 + if (sect != NULL) 445 + do_feature_fixups(cur_cpu_spec->cpu_features, 446 + (void *)sect->sh_addr, 447 + (void *)sect->sh_addr + sect->sh_size); 448 + 449 + sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); 450 + if (sect != NULL) 451 + do_feature_fixups(powerpc_firmware_features, 452 + (void *)sect->sh_addr, 453 + (void *)sect->sh_addr + sect->sh_size); 459 454 460 455 return 0; 461 456 }
+2
scripts/mod/modpost.c
··· 921 921 ".fixup", 922 922 ".smp_locks", 923 923 ".plt", /* seen on ARCH=um build on x86_64. Harmless */ 924 + "__ftr_fixup", /* powerpc cpu feature fixup */ 925 + "__fw_ftr_fixup", /* powerpc firmware feature fixup */ 924 926 NULL 925 927 }; 926 928 /* Start of section names */