Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754177AbbG0Puj (ORCPT ); Mon, 27 Jul 2015 11:50:39 -0400 Received: from verein.lst.de ([213.95.11.211]:38284 "EHLO newverein.lst.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753189AbbG0Pui (ORCPT ); Mon, 27 Jul 2015 11:50:38 -0400 Date: Mon, 27 Jul 2015 17:50:36 +0200 From: Torsten Duwe To: Anton Blanchard Cc: Benjamin Herrenschmidt , Michael Ellerman , Jiri Kosina , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org Subject: RFC: Kernel Live Patching for ppc64le (ABIv2) Message-ID: <20150727155036.GA19677@lst.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.17 (2007-11-01) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3512 Lines: 94 Here is my approach to handle ABIv2 local calls that naturally become global when passing through KLP. On ppc64le a call is either local within the same module, and the TOC pointer is neither saved nor restored by the caller, or it is a global call that passes over a TOC-saving trampoline and the next instruction after the bl restores it. The problem I'm struggling with is the case where KLP redirects a local call into the newly-loaded module, making it global. I have considered and discarded some solutions, but have not detected a flaw in this one so far ;-) GCC adds a NOP after every function call that can be patched by the module linker to restore the TOC; the module linker also generates the matching trampolines. So, if I see the restore instruction, as generated by the module linker, I assume the call already is global and takes care of the caller's TOC. KLP can simply change the call into the new functions' global entry. Should it be a local call that passes through ftrace_caller (where klp_ftrace_handler registers itself), I add a small stack frame that restores the TOC on return. This way it can be done on a per- thread basis to support various consistency models. Please skim over this patch and tell me if you see any problems. (This is on top of my ftrace with regs series, which probably needs another iteration) Signed-off-by: Torsten Duwe diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 4768104..57af111 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -1191,8 +1191,29 @@ _GLOBAL(ftrace_caller) 2: // Here we have our proper TOC ptr in R2, // and the one we need to restore on return in r0. - ld r12, 16(r1) // get caller's adress + ld r12, LRSAVE(r1) // get caller's adress + // Is there a TOC restore insn? + std r11,-8(r1) + std r12,-16(r1) + lwz r12,0(r12) + lis r11,0xe841 // "ld r2,TOCSAVE(r1)" + li r11,TOCSAVE + cmpd r12,r11 + ld r11,-8(r1) + ld r12,-16(r1) + beq 4f + // TODO: test if it's really a NOP. What if not? + + // If no TOC restore insn, then it was a local call and + // the callee's TOC needs to be restored as caller's TOC + // in case of live patching. + std r0,TOCSAVE(r1) + stdu r1,-32(r1) // open new mini stack frame + LOAD_REG_IMMEDIATE(r11,KLP_return_helper) + std r11,LRSAVE(r1) + ld r11,24(r1) // restore again, from -8(r1+32) +4: stdu r1,-SWITCH_FRAME_SIZE(r1) std r12, _LINK(r1) @@ -1265,6 +1286,23 @@ _GLOBAL(ftrace_stub) nop .localentry ftrace_stub,.-ftrace_stub blr + +/* Helper functions for local calls that are becoming global + due to live patching. + We can't simply patch the NOP after the original call, + because, depending on the consistency model, some kernel + threads may still have called the original, local function + *without* saving their TOC in the respective stack frame slot, + so the decision is made per-thread during function return by + maybe inserting a KLP_return_helper frame or not. +*/ +KLP_return_helper: + ld r0,LRSAVE(r1) // get the real return address + addi r1, r1, 32 // destroy this stack frame + ld r2,TOCSAVE(r1) // restore TOC + mtlr r0 + blr + #else _GLOBAL_TOC(_mcount) /* Taken from output of objdump from lib64/glibc */ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/