| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
|---|
| 1 | 2 | #ifndef _ASM_POWERPC_CODE_PATCHING_H |
|---|
| 2 | 3 | #define _ASM_POWERPC_CODE_PATCHING_H |
|---|
| 3 | 4 | |
|---|
| 4 | 5 | /* |
|---|
| 5 | 6 | * Copyright 2008, Michael Ellerman, IBM Corporation. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; either version |
|---|
| 10 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 11 | 7 | */ |
|---|
| 12 | 8 | |
|---|
| 13 | 9 | #include <asm/types.h> |
|---|
| .. | .. |
|---|
| 15 | 11 | #include <linux/string.h> |
|---|
| 16 | 12 | #include <linux/kallsyms.h> |
|---|
| 17 | 13 | #include <asm/asm-compat.h> |
|---|
| 14 | +#include <asm/inst.h> |
|---|
| 18 | 15 | |
|---|
| 19 | 16 | /* Flags for create_branch: |
|---|
| 20 | 17 | * "b" == create_branch(addr, target, 0); |
|---|
| .. | .. |
|---|
| 27 | 24 | |
|---|
| 28 | 25 | bool is_offset_in_branch_range(long offset); |
|---|
| 29 | 26 | bool is_offset_in_cond_branch_range(long offset); |
|---|
| 30 | | -unsigned int create_branch(const unsigned int *addr, |
|---|
| 31 | | - unsigned long target, int flags); |
|---|
| 32 | | -unsigned int create_cond_branch(const unsigned int *addr, |
|---|
| 33 | | - unsigned long target, int flags); |
|---|
| 34 | | -int patch_branch(unsigned int *addr, unsigned long target, int flags); |
|---|
| 35 | | -int patch_instruction(unsigned int *addr, unsigned int instr); |
|---|
| 36 | | -int raw_patch_instruction(unsigned int *addr, unsigned int instr); |
|---|
| 37 | | -int patch_instruction_site(s32 *addr, unsigned int instr); |
|---|
| 38 | | -int patch_branch_site(s32 *site, unsigned long target, int flags); |
|---|
| 27 | +int create_branch(struct ppc_inst *instr, const struct ppc_inst *addr, |
|---|
| 28 | + unsigned long target, int flags); |
|---|
| 29 | +int create_cond_branch(struct ppc_inst *instr, const struct ppc_inst *addr, |
|---|
| 30 | + unsigned long target, int flags); |
|---|
| 31 | +int patch_branch(struct ppc_inst *addr, unsigned long target, int flags); |
|---|
| 32 | +int patch_instruction(struct ppc_inst *addr, struct ppc_inst instr); |
|---|
| 33 | +int raw_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr); |
|---|
| 39 | 34 | |
|---|
| 40 | | -int instr_is_relative_branch(unsigned int instr); |
|---|
| 41 | | -int instr_is_relative_link_branch(unsigned int instr); |
|---|
| 42 | | -int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); |
|---|
| 43 | | -unsigned long branch_target(const unsigned int *instr); |
|---|
| 44 | | -unsigned int translate_branch(const unsigned int *dest, |
|---|
| 45 | | - const unsigned int *src); |
|---|
| 46 | | -extern bool is_conditional_branch(unsigned int instr); |
|---|
| 35 | +static inline unsigned long patch_site_addr(s32 *site) |
|---|
| 36 | +{ |
|---|
| 37 | + return (unsigned long)site + *site; |
|---|
| 38 | +} |
|---|
| 39 | + |
|---|
| 40 | +static inline int patch_instruction_site(s32 *site, struct ppc_inst instr) |
|---|
| 41 | +{ |
|---|
| 42 | + return patch_instruction((struct ppc_inst *)patch_site_addr(site), instr); |
|---|
| 43 | +} |
|---|
| 44 | + |
|---|
| 45 | +static inline int patch_branch_site(s32 *site, unsigned long target, int flags) |
|---|
| 46 | +{ |
|---|
| 47 | + return patch_branch((struct ppc_inst *)patch_site_addr(site), target, flags); |
|---|
| 48 | +} |
|---|
| 49 | + |
|---|
| 50 | +static inline int modify_instruction(unsigned int *addr, unsigned int clr, |
|---|
| 51 | + unsigned int set) |
|---|
| 52 | +{ |
|---|
| 53 | + return patch_instruction((struct ppc_inst *)addr, ppc_inst((*addr & ~clr) | set)); |
|---|
| 54 | +} |
|---|
| 55 | + |
|---|
| 56 | +static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned int set) |
|---|
| 57 | +{ |
|---|
| 58 | + return modify_instruction((unsigned int *)patch_site_addr(site), clr, set); |
|---|
| 59 | +} |
|---|
| 60 | + |
|---|
| 61 | +int instr_is_relative_branch(struct ppc_inst instr); |
|---|
| 62 | +int instr_is_relative_link_branch(struct ppc_inst instr); |
|---|
| 63 | +int instr_is_branch_to_addr(const struct ppc_inst *instr, unsigned long addr); |
|---|
| 64 | +unsigned long branch_target(const struct ppc_inst *instr); |
|---|
| 65 | +int translate_branch(struct ppc_inst *instr, const struct ppc_inst *dest, |
|---|
| 66 | + const struct ppc_inst *src); |
|---|
| 67 | +extern bool is_conditional_branch(struct ppc_inst instr); |
|---|
| 47 | 68 | #ifdef CONFIG_PPC_BOOK3E_64 |
|---|
| 48 | 69 | void __patch_exception(int exc, unsigned long addr); |
|---|
| 49 | 70 | #define patch_exception(exc, name) do { \ |
|---|