aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib/code-patching.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/lib/code-patching.c')
-rw-r--r--arch/powerpc/lib/code-patching.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index d469224c4ada..e0d881ab304e 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -23,19 +23,26 @@
23#include <asm/code-patching.h> 23#include <asm/code-patching.h>
24#include <asm/setup.h> 24#include <asm/setup.h>
25 25
26static int __patch_instruction(unsigned int *addr, unsigned int instr) 26static int __patch_instruction(unsigned int *exec_addr, unsigned int instr,
27 unsigned int *patch_addr)
27{ 28{
28 int err; 29 int err;
29 30
30 __put_user_size(instr, addr, 4, err); 31 __put_user_size(instr, patch_addr, 4, err);
31 if (err) 32 if (err)
32 return err; 33 return err;
33 34
34 asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" :: "r" (addr)); 35 asm ("dcbst 0, %0; sync; icbi 0,%1; sync; isync" :: "r" (patch_addr),
36 "r" (exec_addr));
35 37
36 return 0; 38 return 0;
37} 39}
38 40
41int raw_patch_instruction(unsigned int *addr, unsigned int instr)
42{
43 return __patch_instruction(addr, instr, addr);
44}
45
39#ifdef CONFIG_STRICT_KERNEL_RWX 46#ifdef CONFIG_STRICT_KERNEL_RWX
40static DEFINE_PER_CPU(struct vm_struct *, text_poke_area); 47static DEFINE_PER_CPU(struct vm_struct *, text_poke_area);
41 48
@@ -138,7 +145,7 @@ static inline int unmap_patch_area(unsigned long addr)
138int patch_instruction(unsigned int *addr, unsigned int instr) 145int patch_instruction(unsigned int *addr, unsigned int instr)
139{ 146{
140 int err; 147 int err;
141 unsigned int *dest = NULL; 148 unsigned int *patch_addr = NULL;
142 unsigned long flags; 149 unsigned long flags;
143 unsigned long text_poke_addr; 150 unsigned long text_poke_addr;
144 unsigned long kaddr = (unsigned long)addr; 151 unsigned long kaddr = (unsigned long)addr;
@@ -148,8 +155,8 @@ int patch_instruction(unsigned int *addr, unsigned int instr)
148 * when text_poke_area is not ready, but we still need 155 * when text_poke_area is not ready, but we still need
149 * to allow patching. We just do the plain old patching 156 * to allow patching. We just do the plain old patching
150 */ 157 */
151 if (!this_cpu_read(*PTRRELOC(&text_poke_area))) 158 if (!this_cpu_read(text_poke_area))
152 return __patch_instruction(addr, instr); 159 return raw_patch_instruction(addr, instr);
153 160
154 local_irq_save(flags); 161 local_irq_save(flags);
155 162
@@ -159,17 +166,10 @@ int patch_instruction(unsigned int *addr, unsigned int instr)
159 goto out; 166 goto out;
160 } 167 }
161 168
162 dest = (unsigned int *)(text_poke_addr) + 169 patch_addr = (unsigned int *)(text_poke_addr) +
163 ((kaddr & ~PAGE_MASK) / sizeof(unsigned int)); 170 ((kaddr & ~PAGE_MASK) / sizeof(unsigned int));
164 171
165 /* 172 __patch_instruction(addr, instr, patch_addr);
166 * We use __put_user_size so that we can handle faults while
167 * writing to dest and return err to handle faults gracefully
168 */
169 __put_user_size(instr, dest, 4, err);
170 if (!err)
171 asm ("dcbst 0, %0; sync; icbi 0,%0; icbi 0,%1; sync; isync"
172 ::"r" (dest), "r"(addr));
173 173
174 err = unmap_patch_area(text_poke_addr); 174 err = unmap_patch_area(text_poke_addr);
175 if (err) 175 if (err)
@@ -184,7 +184,7 @@ out:
184 184
185int patch_instruction(unsigned int *addr, unsigned int instr) 185int patch_instruction(unsigned int *addr, unsigned int instr)
186{ 186{
187 return __patch_instruction(addr, instr); 187 return raw_patch_instruction(addr, instr);
188} 188}
189 189
190#endif /* CONFIG_STRICT_KERNEL_RWX */ 190#endif /* CONFIG_STRICT_KERNEL_RWX */
@@ -302,6 +302,11 @@ int instr_is_relative_branch(unsigned int instr)
302 return instr_is_branch_iform(instr) || instr_is_branch_bform(instr); 302 return instr_is_branch_iform(instr) || instr_is_branch_bform(instr);
303} 303}
304 304
305int instr_is_relative_link_branch(unsigned int instr)
306{
307 return instr_is_relative_branch(instr) && (instr & BRANCH_SET_LINK);
308}
309
305static unsigned long branch_iform_target(const unsigned int *instr) 310static unsigned long branch_iform_target(const unsigned int *instr)
306{ 311{
307 signed long imm; 312 signed long imm;