/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * livepatch.c - powerpc-specific Kernel Live Patching Core * * Copyright (C) 2023 Huawei Technologies Co., Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include .section ".text","ax",@progbits /* * Livepatch function branch stub. * see struct ppc64_klp_bstub_entry * use it jump to livepatch trampoline */ _GLOBAL(livepatch_branch_stub) addis r11,r2, 0 /* */ addi r11,r11, 0 /* */ ld r12,24(r11) mtctr r12 bctr _GLOBAL(livepatch_branch_stub_end) nop /* for magic */ /* * This function runs in the livepatch context, between two functions. * As such it can only clobber registers which are volatile and used in * function linkage. * * We get here when a function A, calls another function B, but B has * been live patched with a new function C. * * On entry: * - we have no stack frame and can not allocate one * - LR points back to the original caller (in A) * - CTR used to hold the new NIP for call * - r0, r11 & r12 are free * -- r11 point back to the bstub data which store (func descr) * ---- 0(saved_entry) : new function address * ---- 8(r0) : new R2(toc) for new function * -- tag livepatch stack with r11 * -- save temporary variables with r12 */ _GLOBAL(livepatch_branch_trampoline) mflr r0 std r0, 16(r1) std r2, 24(r1) stdu r1, -STACK_FRAME_MIN_SIZE(r1) /* Load func descr address to R11 */ lis r11, 0 /* saved_entry@highest */ ori r11,r11,0 /* saved_entry@higher */ rldicr r11,r11,32,31 oris r11,r11,0 /* saved_entry@high */ ori r11,r11,0 /* saved_entry@low */ /* Call NEW_FUNC */ ld r12, 0(r11) /* load new func address to R12 */ ld r2, 8(r11) /* set up new R2 */ mtctr r12 /* load R12(new func address) to CTR */ bctrl /* call new func */ /* * Now we are returning from the patched function to the original * caller A. We are free to use r11, r12 and we can use r2 until we * restore it. */ addi r1, r1, STACK_FRAME_MIN_SIZE ld r2, 24(r1) ld r0, 16(r1) mtlr r0 /* Return to original caller of live patched function */ blr _GLOBAL(livepatch_branch_trampoline_end) nop /* * This function is the trampoline of livepatch brk handler. * * brk -> traps * - klp_brk_handler * - set R11 to new_func address * - set NIP to livepatch_brk_trampoline address * see arch/powerpc/kernel/livepatch.c */ _GLOBAL(livepatch_brk_trampoline) mflr r0 std r0, 16(r1) std r2, 24(r1) stdu r1, -STACK_FRAME_MIN_SIZE(r1) /* Call NEW_FUNC */ ld r12, 0(r11) /* load new func address to R12 */ ld r2, 8(r11) /* set up new R2 */ mtctr r12 /* load R12(new func address) to CTR */ bctrl /* call new func */ /* * Now we are returning from the patched function to the original * caller A. We are free to use r11, r12 and we can use r2 until we * restore it. */ addi r1, r1, STACK_FRAME_MIN_SIZE ld r2, 24(r1) ld r0, 16(r1) mtlr r0 /* Return to original caller of live patched function */ blr