Re: [PATCH] ppc64: re-enable kexec to allow module loads with CONFIG_MODVERSIONS and CONFIG_RELOCATABLE turned on
From: Rusty Russell <hidden>
Date: 2009-12-01 02:58:27
Also in:
lkml
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Michael Ellerman, Linus Torvalds
On Tue, 1 Dec 2009 04:46:00 am Neil Horman wrote:
Paul, Ben, given that Rusty hasn't come back with any opinion on this patch, do you feel comfortable merging it via the ppc tree? Currently the earlyinit routine is only compiled in and used for your arch, so I think its fairly benign.
Sorry, I *did* track down the archives for linuxppc-dev, then find your post, then read your patch. But I didn't actually reply. Other than minor issues, there's one significant one: you shouldn't be trying to change rodata. It might work on PPC today, but it's poor form at least. How's this? Untested on ppc. Other changes: 1) I also changed reloc_start to an array; this is a good idea for any linker-defined symbols so the compiler can't make assumptions about size. 2) local.h? How about module.h? 3) I don't think the extra ". = 0" is necessary. 4) ARCH_USES_RELOC_ENTRIES isn't clear enough for me; I prefer ARCH_RELOCATE_KCRCTAB. module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y http://lists.ozlabs.org/pipermail/linuxppc-dev/2009-November/077972.html Inspired-by: Neil Horman [off-list ref] Signed-off-by: Rusty Russell <redacted>
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h@@ -87,5 +87,10 @@ struct exception_table_entry; void sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish); +#ifdef CONFIG_MODVERSIONS +#define ARCH_RELOCATES_KCRCTAB + +extern const unsigned long reloc_start[]; +#endif #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MODULE_H */
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S@@ -38,6 +38,9 @@ jiffies = jiffies_64 + 4; #endif SECTIONS { + . = 0; + reloc_start = .; + . = KERNELBASE; /*
diff --git a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c
+++ b/kernel/module.c@@ -1030,11 +1030,23 @@ static int try_to_force_load(struct modu } #ifdef CONFIG_MODVERSIONS +/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ +static unsigned long maybe_relocated(unsigned long crc, + const struct module *crc_owner) +{ +#ifdef ARCH_RELOCATES_KCRCTAB + if (crc_owner == NULL) + return crc - (unsigned long)reloc_start; +#endif + return crc; +} + static int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, - const unsigned long *crc) + const unsigned long *crc, + const struct module *crc_owner) { unsigned int i, num_versions; struct modversion_info *versions;
@@ -1055,10 +1067,10 @@ static int check_version(Elf_Shdr *sechd if (strcmp(versions[i].name, symname) != 0) continue; - if (versions[i].crc == *crc) + if (versions[i].crc == maybe_relocated(*crc, crc_owner)) return 1; DEBUGP("Found checksum %lX vs module %lX\n", - *crc, versions[i].crc); + maybe_relocated(*crc, crc_owner), versions[i].crc); goto bad_version; }
@@ -1081,7 +1093,8 @@ static inline int check_modstruct_versio if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, &crc, true, false)) BUG(); - return check_version(sechdrs, versindex, "module_layout", mod, crc); + return check_version(sechdrs, versindex, "module_layout", mod, crc, + NULL); } /* First part is kernel version, which we ignore if module has crcs. */
@@ -1099,7 +1112,8 @@ static inline int check_version(Elf_Shdr unsigned int versindex, const char *symname, struct module *mod, - const unsigned long *crc) + const unsigned long *crc, + const struct module *crc_owner) { return 1; }
@@ -1134,8 +1148,8 @@ static const struct kernel_symbol *resol /* use_module can fail due to OOM, or module initialization or unloading */ if (sym) { - if (!check_version(sechdrs, versindex, name, mod, crc) || - !use_module(mod, owner)) + if (!check_version(sechdrs, versindex, name, mod, crc, owner) + || !use_module(mod, owner)) sym = NULL; } return sym;