When the kernel is compiled to use 64bit ABIv2 the _GLOBAL() macro does not include a global entry point. A function's global entry point is used when the function is called from a different TOC context and in the kernel this typically means a call from a module into the vmlinux (or vis-a-vis).
There are a few exported ASM functions declared with _GLOBAL() and calling them from a module will module will likely crash the kernel since any TOC relative load will yield garbage. To fix this use _GLOBAL_TOC() for exported asm functions rather than _GLOBAL() and some documentation about when to use each. Signed-off-by: Oliver O'Halloran <ooh...@gmail.com> --- arch/powerpc/include/asm/ppc_asm.h | 12 ++++++++++++ arch/powerpc/kernel/misc_64.S | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 359c443..3abf8c3 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -198,6 +198,18 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #ifdef PPC64_ELF_ABI_v2 +/* + * When to use _GLOBAL_TOC() instead of _GLOBAL(): + * + * a) The function is exported using EXPORT_SYMBOL_*() + * *and* + * b) The function, or any function that it calls, references the TOC. + * + * In this situation _GLOBAL_TOC() is required because exported functions are + * callable from modules which may a different TOC to the kernel proper and the + * _GLOBAL() macro skips the TOC setup which is required on ELF ABIv2. + */ + #define _GLOBAL(name) \ .align 2 ; \ .type name,@function; \ diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index ec94aef..d18da8c 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -67,7 +67,7 @@ PPC64_CACHES: * flush all bytes from start through stop-1 inclusive */ -_GLOBAL(flush_icache_range) +_GLOBAL_TOC(flush_icache_range) BEGIN_FTR_SECTION PURGE_PREFETCHED_INS blr @@ -120,7 +120,7 @@ EXPORT_SYMBOL(flush_icache_range) * * flush all bytes from start to stop-1 inclusive */ -_GLOBAL(flush_dcache_range) +_GLOBAL_TOC(flush_dcache_range) /* * Flush the data cache to memory -- 2.9.3