Commit 3c752965 authored by Steffen Rumler's avatar Steffen Rumler Committed by Paul Mackerras

powerpc: Fix kernel panic during kernel module load

This fixes a problem which can causes kernel oopses while loading
a kernel module.

According to the PowerPC EABI specification, GPR r11 is assigned
the dedicated function to point to the previous stack frame.
In the powerpc-specific kernel module loader, do_plt_call()
(in arch/powerpc/kernel/module_32.c), GPR r11 is also used
to generate trampoline code.

This combination crashes the kernel, in the case where the compiler
chooses to use a helper function for saving GPRs on entry, and the
module loader has placed the .init.text section far away from the
.text section, meaning that it has to generate a trampoline for
functions in the .init.text section to call the GPR save helper.
Because the trampoline trashes r11, references to the stack frame
using r11 can cause an oops.

The fix just uses GPR r12 instead of GPR r11 for generating the
trampoline code.  According to the statements from Freescale, this is
safe from an EABI perspective.

I've tested the fix for kernel 2.6.33 on MPC8541.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarSteffen Rumler <steffen.rumler.ext@nsn.com>
[paulus@samba.org: reworded the description]
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 860aed25
...@@ -176,8 +176,8 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr, ...@@ -176,8 +176,8 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr,
static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val)
{ {
if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) if (entry->jump[0] == 0x3d800000 + ((val + 0x8000) >> 16)
&& entry->jump[1] == 0x396b0000 + (val & 0xffff)) && entry->jump[1] == 0x398c0000 + (val & 0xffff))
return 1; return 1;
return 0; return 0;
} }
...@@ -204,10 +204,9 @@ static uint32_t do_plt_call(void *location, ...@@ -204,10 +204,9 @@ static uint32_t do_plt_call(void *location,
entry++; entry++;
} }
/* Stolen from Paul Mackerras as well... */ entry->jump[0] = 0x3d800000+((val+0x8000)>>16); /* lis r12,sym@ha */
entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */ entry->jump[1] = 0x398c0000 + (val&0xffff); /* addi r12,r12,sym@l*/
entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/ entry->jump[2] = 0x7d8903a6; /* mtctr r12 */
entry->jump[2] = 0x7d6903a6; /* mtctr r11 */
entry->jump[3] = 0x4e800420; /* bctr */ entry->jump[3] = 0x4e800420; /* bctr */
DEBUGP("Initialized plt for 0x%x at %p\n", val, entry); DEBUGP("Initialized plt for 0x%x at %p\n", val, entry);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment