| From 3c75296562f43e6fbc6cddd3de948a7b3e4e9bcf Mon Sep 17 00:00:00 2001 |
| From: Steffen Rumler <steffen.rumler.ext@nsn.com> |
| Date: Wed, 6 Jun 2012 16:37:17 +0200 |
| Subject: powerpc: Fix kernel panic during kernel module load |
| |
| From: Steffen Rumler <steffen.rumler.ext@nsn.com> |
| |
| commit 3c75296562f43e6fbc6cddd3de948a7b3e4e9bcf upstream. |
| |
| 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. |
| |
| Signed-off-by: Steffen Rumler <steffen.rumler.ext@nsn.com> |
| [paulus@samba.org: reworded the description] |
| Signed-off-by: Paul Mackerras <paulus@samba.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kernel/module_32.c | 11 +++++------ |
| 1 file changed, 5 insertions(+), 6 deletions(-) |
| |
| --- a/arch/powerpc/kernel/module_32.c |
| +++ b/arch/powerpc/kernel/module_32.c |
| @@ -187,8 +187,8 @@ int apply_relocate(Elf32_Shdr *sechdrs, |
| |
| static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val) |
| { |
| - if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) |
| - && entry->jump[1] == 0x396b0000 + (val & 0xffff)) |
| + if (entry->jump[0] == 0x3d800000 + ((val + 0x8000) >> 16) |
| + && entry->jump[1] == 0x398c0000 + (val & 0xffff)) |
| return 1; |
| return 0; |
| } |
| @@ -215,10 +215,9 @@ static uint32_t do_plt_call(void *locati |
| entry++; |
| } |
| |
| - /* Stolen from Paul Mackerras as well... */ |
| - entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */ |
| - entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/ |
| - entry->jump[2] = 0x7d6903a6; /* mtctr r11 */ |
| + entry->jump[0] = 0x3d800000+((val+0x8000)>>16); /* lis r12,sym@ha */ |
| + entry->jump[1] = 0x398c0000 + (val&0xffff); /* addi r12,r12,sym@l*/ |
| + entry->jump[2] = 0x7d8903a6; /* mtctr r12 */ |
| entry->jump[3] = 0x4e800420; /* bctr */ |
| |
| DEBUGP("Initialized plt for 0x%x at %p\n", val, entry); |