]>
Commit | Line | Data |
---|---|---|
45d80ddf SL |
1 | From 1d66f83aebd639a61d5432a5f5411dc5924ca240 Mon Sep 17 00:00:00 2001 |
2 | From: Michael Ellerman <mpe@ellerman.id.au> | |
3 | Date: Thu, 11 Apr 2019 21:46:13 +1000 | |
4 | Subject: powerpc/asm: Add a patch_site macro & helpers for patching | |
5 | instructions | |
6 | ||
7 | commit 06d0bbc6d0f56dacac3a79900e9a9a0d5972d818 upstream. | |
8 | ||
9 | Add a macro and some helper C functions for patching single asm | |
10 | instructions. | |
11 | ||
12 | The gas macro means we can do something like: | |
13 | ||
14 | 1: nop | |
15 | patch_site 1b, patch__foo | |
16 | ||
17 | Which is less visually distracting than defining a GLOBAL symbol at 1, | |
18 | and also doesn't pollute the symbol table which can confuse eg. perf. | |
19 | ||
20 | These are obviously similar to our existing feature sections, but are | |
21 | not automatically patched based on CPU/MMU features, rather they are | |
22 | designed to be manually patched by C code at some arbitrary point. | |
23 | ||
24 | Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> | |
25 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
26 | --- | |
27 | arch/powerpc/include/asm/code-patching-asm.h | 18 ++++++++++++++++++ | |
28 | arch/powerpc/include/asm/code-patching.h | 2 ++ | |
29 | arch/powerpc/lib/code-patching.c | 16 ++++++++++++++++ | |
30 | 3 files changed, 36 insertions(+) | |
31 | create mode 100644 arch/powerpc/include/asm/code-patching-asm.h | |
32 | ||
33 | diff --git a/arch/powerpc/include/asm/code-patching-asm.h b/arch/powerpc/include/asm/code-patching-asm.h | |
34 | new file mode 100644 | |
35 | index 000000000000..ed7b1448493a | |
36 | --- /dev/null | |
37 | +++ b/arch/powerpc/include/asm/code-patching-asm.h | |
38 | @@ -0,0 +1,18 @@ | |
39 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
40 | +/* | |
41 | + * Copyright 2018, Michael Ellerman, IBM Corporation. | |
42 | + */ | |
43 | +#ifndef _ASM_POWERPC_CODE_PATCHING_ASM_H | |
44 | +#define _ASM_POWERPC_CODE_PATCHING_ASM_H | |
45 | + | |
46 | +/* Define a "site" that can be patched */ | |
47 | +.macro patch_site label name | |
48 | + .pushsection ".rodata" | |
49 | + .balign 4 | |
50 | + .global \name | |
51 | +\name: | |
52 | + .4byte \label - . | |
53 | + .popsection | |
54 | +.endm | |
55 | + | |
56 | +#endif /* _ASM_POWERPC_CODE_PATCHING_ASM_H */ | |
57 | diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h | |
58 | index b4ab1f497335..ab934f8232bd 100644 | |
59 | --- a/arch/powerpc/include/asm/code-patching.h | |
60 | +++ b/arch/powerpc/include/asm/code-patching.h | |
61 | @@ -28,6 +28,8 @@ unsigned int create_cond_branch(const unsigned int *addr, | |
62 | unsigned long target, int flags); | |
63 | int patch_branch(unsigned int *addr, unsigned long target, int flags); | |
64 | int patch_instruction(unsigned int *addr, unsigned int instr); | |
65 | +int patch_instruction_site(s32 *addr, unsigned int instr); | |
66 | +int patch_branch_site(s32 *site, unsigned long target, int flags); | |
67 | ||
68 | int instr_is_relative_branch(unsigned int instr); | |
69 | int instr_is_relative_link_branch(unsigned int instr); | |
70 | diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c | |
71 | index c77c486fbf24..14535ad4cdd1 100644 | |
72 | --- a/arch/powerpc/lib/code-patching.c | |
73 | +++ b/arch/powerpc/lib/code-patching.c | |
74 | @@ -40,6 +40,22 @@ int patch_branch(unsigned int *addr, unsigned long target, int flags) | |
75 | return patch_instruction(addr, create_branch(addr, target, flags)); | |
76 | } | |
77 | ||
78 | +int patch_branch_site(s32 *site, unsigned long target, int flags) | |
79 | +{ | |
80 | + unsigned int *addr; | |
81 | + | |
82 | + addr = (unsigned int *)((unsigned long)site + *site); | |
83 | + return patch_instruction(addr, create_branch(addr, target, flags)); | |
84 | +} | |
85 | + | |
86 | +int patch_instruction_site(s32 *site, unsigned int instr) | |
87 | +{ | |
88 | + unsigned int *addr; | |
89 | + | |
90 | + addr = (unsigned int *)((unsigned long)site + *site); | |
91 | + return patch_instruction(addr, instr); | |
92 | +} | |
93 | + | |
94 | unsigned int create_branch(const unsigned int *addr, | |
95 | unsigned long target, int flags) | |
96 | { | |
97 | -- | |
98 | 2.19.1 | |
99 |