| From foo@baz Fri Mar 29 15:53:50 CET 2019 |
| From: Michael Ellerman <mpe@ellerman.id.au> |
| Date: Fri, 29 Mar 2019 22:26:03 +1100 |
| Subject: powerpc/asm: Add a patch_site macro & helpers for patching instructions |
| To: stable@vger.kernel.org, gregkh@linuxfoundation.org |
| Cc: linuxppc-dev@ozlabs.org, diana.craciun@nxp.com, msuchanek@suse.de, christophe.leroy@c-s.fr |
| Message-ID: <20190329112620.14489-16-mpe@ellerman.id.au> |
| |
| From: Michael Ellerman <mpe@ellerman.id.au> |
| |
| commit 06d0bbc6d0f56dacac3a79900e9a9a0d5972d818 upstream. |
| |
| Add a macro and some helper C functions for patching single asm |
| instructions. |
| |
| The gas macro means we can do something like: |
| |
| 1: nop |
| patch_site 1b, patch__foo |
| |
| Which is less visually distracting than defining a GLOBAL symbol at 1, |
| and also doesn't pollute the symbol table which can confuse eg. perf. |
| |
| These are obviously similar to our existing feature sections, but are |
| not automatically patched based on CPU/MMU features, rather they are |
| designed to be manually patched by C code at some arbitrary point. |
| |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/powerpc/include/asm/code-patching-asm.h | 18 ++++++++++++++++++ |
| arch/powerpc/include/asm/code-patching.h | 2 ++ |
| arch/powerpc/lib/code-patching.c | 16 ++++++++++++++++ |
| 3 files changed, 36 insertions(+) |
| create mode 100644 arch/powerpc/include/asm/code-patching-asm.h |
| |
| --- /dev/null |
| +++ b/arch/powerpc/include/asm/code-patching-asm.h |
| @@ -0,0 +1,18 @@ |
| +/* SPDX-License-Identifier: GPL-2.0+ */ |
| +/* |
| + * Copyright 2018, Michael Ellerman, IBM Corporation. |
| + */ |
| +#ifndef _ASM_POWERPC_CODE_PATCHING_ASM_H |
| +#define _ASM_POWERPC_CODE_PATCHING_ASM_H |
| + |
| +/* Define a "site" that can be patched */ |
| +.macro patch_site label name |
| + .pushsection ".rodata" |
| + .balign 4 |
| + .global \name |
| +\name: |
| + .4byte \label - . |
| + .popsection |
| +.endm |
| + |
| +#endif /* _ASM_POWERPC_CODE_PATCHING_ASM_H */ |
| --- a/arch/powerpc/include/asm/code-patching.h |
| +++ b/arch/powerpc/include/asm/code-patching.h |
| @@ -32,6 +32,8 @@ unsigned int create_cond_branch(const un |
| int patch_branch(unsigned int *addr, unsigned long target, int flags); |
| int patch_instruction(unsigned int *addr, unsigned int instr); |
| int raw_patch_instruction(unsigned int *addr, unsigned int instr); |
| +int patch_instruction_site(s32 *addr, unsigned int instr); |
| +int patch_branch_site(s32 *site, unsigned long target, int flags); |
| |
| int instr_is_relative_branch(unsigned int instr); |
| int instr_is_relative_link_branch(unsigned int instr); |
| --- a/arch/powerpc/lib/code-patching.c |
| +++ b/arch/powerpc/lib/code-patching.c |
| @@ -206,6 +206,22 @@ int patch_branch(unsigned int *addr, uns |
| return patch_instruction(addr, create_branch(addr, target, flags)); |
| } |
| |
| +int patch_branch_site(s32 *site, unsigned long target, int flags) |
| +{ |
| + unsigned int *addr; |
| + |
| + addr = (unsigned int *)((unsigned long)site + *site); |
| + return patch_instruction(addr, create_branch(addr, target, flags)); |
| +} |
| + |
| +int patch_instruction_site(s32 *site, unsigned int instr) |
| +{ |
| + unsigned int *addr; |
| + |
| + addr = (unsigned int *)((unsigned long)site + *site); |
| + return patch_instruction(addr, instr); |
| +} |
| + |
| bool is_offset_in_branch_range(long offset) |
| { |
| /* |