summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2017-11-16 12:45:37 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2017-12-10 21:03:29 -0500
commitb9eab08d012fa093947b230f9a87257c27fb829b (patch)
treefa5f33c519c97d9cbbf59b4598a8fdf8e8f4d273
parenta443bf6e8a7674b86221f4922cae82d67dc9e8ad (diff)
powerpc/modules: Don't try to restore r2 after a sibling call
When attempting to load a livepatch module, I got the following error: module_64: patch_module: Expect noop after relocate, got 3c820000 The error was triggered by the following code in unregister_netdevice_queue(): 14c: 00 00 00 48 b 14c <unregister_netdevice_queue+0x14c> 14c: R_PPC64_REL24 net_set_todo 150: 00 00 82 3c addis r4,r2,0 GCC didn't insert a nop after the branch to net_set_todo() because it's a sibling call, so it never returns. The nop isn't needed after the branch in that case. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Reviewed-and-tested-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/code-patching.h1
-rw-r--r--arch/powerpc/kernel/module_64.c12
-rw-r--r--arch/powerpc/lib/code-patching.c5
3 files changed, 17 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h
index abef812de7f8..2c895e8d07f7 100644
--- a/arch/powerpc/include/asm/code-patching.h
+++ b/arch/powerpc/include/asm/code-patching.h
@@ -33,6 +33,7 @@ int patch_branch(unsigned int *addr, unsigned long target, int flags);
33int patch_instruction(unsigned int *addr, unsigned int instr); 33int patch_instruction(unsigned int *addr, unsigned int instr);
34 34
35int instr_is_relative_branch(unsigned int instr); 35int instr_is_relative_branch(unsigned int instr);
36int instr_is_relative_link_branch(unsigned int instr);
36int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); 37int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr);
37unsigned long branch_target(const unsigned int *instr); 38unsigned long branch_target(const unsigned int *instr);
38unsigned int translate_branch(const unsigned int *dest, 39unsigned int translate_branch(const unsigned int *dest,
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 1685b40f3935..5b44668c0e45 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -487,7 +487,17 @@ static bool is_early_mcount_callsite(u32 *instruction)
487 restore r2. */ 487 restore r2. */
488static int restore_r2(u32 *instruction, struct module *me) 488static int restore_r2(u32 *instruction, struct module *me)
489{ 489{
490 if (is_early_mcount_callsite(instruction - 1)) 490 u32 *prev_insn = instruction - 1;
491
492 if (is_early_mcount_callsite(prev_insn))
493 return 1;
494
495 /*
496 * Make sure the branch isn't a sibling call. Sibling calls aren't
497 * "link" branches and they don't return, so they don't need the r2
498 * restore afterwards.
499 */
500 if (!instr_is_relative_link_branch(*prev_insn))
491 return 1; 501 return 1;
492 502
493 if (*instruction != PPC_INST_NOP) { 503 if (*instruction != PPC_INST_NOP) {
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index d469224c4ada..096d4e4d31e6 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -302,6 +302,11 @@ int instr_is_relative_branch(unsigned int instr)
302 return instr_is_branch_iform(instr) || instr_is_branch_bform(instr); 302 return instr_is_branch_iform(instr) || instr_is_branch_bform(instr);
303} 303}
304 304
305int instr_is_relative_link_branch(unsigned int instr)
306{
307 return instr_is_relative_branch(instr) && (instr & BRANCH_SET_LINK);
308}
309
305static unsigned long branch_iform_target(const unsigned int *instr) 310static unsigned long branch_iform_target(const unsigned int *instr)
306{ 311{
307 signed long imm; 312 signed long imm;