Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4703aef authored by Rusty Russell's avatar Rusty Russell
Browse files

module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y

powerpc applies relocations to the kcrctab.  They're absolute symbols,
but it's not completely unreasonable: other archs may too, but the
relocation is often 0.

http://lists.ozlabs.org/pipermail/linuxppc-dev/2009-November/077972.html



Inspired-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Tested-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Acked-by: default avatarPaul Mackerras <paulus@samba.org>
parent a8773769
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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 */
+3 −0
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ jiffies = jiffies_64 + 4;
#endif
SECTIONS
{
	. = 0;
	reloc_start = .;

	. = KERNELBASE;

/*
+21 −7
Original line number Diff line number Diff line
@@ -880,11 +880,23 @@ static int try_to_force_load(struct module *mod, const char *reason)
}

#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;
@@ -905,10 +917,10 @@ static int check_version(Elf_Shdr *sechdrs,
		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;
	}

@@ -931,7 +943,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
	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. */
@@ -949,7 +962,8 @@ static inline 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)
{
	return 1;
}
@@ -984,8 +998,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
	/* 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;