aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/ftrace.c40
1 files changed, 19 insertions, 21 deletions
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 78cdd7fbecd0..f202d0731b06 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -292,19 +292,24 @@ static int
292__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 292__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
293{ 293{
294 unsigned int op[2]; 294 unsigned int op[2];
295 unsigned long ip = rec->ip; 295 void *ip = (void *)rec->ip;
296 296
297 /* read where this goes */ 297 /* read where this goes */
298 if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) 298 if (probe_kernel_read(op, ip, sizeof(op)))
299 return -EFAULT; 299 return -EFAULT;
300 300
301 /* 301 /*
302 * It should be pointing to two nops or 302 * We expect to see:
303 * b +8; ld r2,40(r1) 303 *
304 * b +8
305 * ld r2,XX(r1)
306 *
307 * The load offset is different depending on the ABI. For simplicity
308 * just mask it out when doing the compare.
304 */ 309 */
305 if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && 310 if ((op[0] != 0x48000008) || ((op[1] & 0xffff00000) != 0xe8410000)) {
306 ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) { 311 printk(KERN_ERR "Unexpected call sequence: %x %x\n",
307 printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); 312 op[0], op[1]);
308 return -EINVAL; 313 return -EINVAL;
309 } 314 }
310 315
@@ -314,23 +319,16 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
314 return -EINVAL; 319 return -EINVAL;
315 } 320 }
316 321
317 /* create the branch to the trampoline */ 322 /* Ensure branch is within 24 bits */
318 op[0] = create_branch((unsigned int *)ip, 323 if (create_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
319 rec->arch.mod->arch.tramp, BRANCH_SET_LINK); 324 printk(KERN_ERR "Branch out of range");
320 if (!op[0]) {
321 printk(KERN_ERR "REL24 out of range!\n");
322 return -EINVAL; 325 return -EINVAL;
323 } 326 }
324 327
325 /* ld r2,40(r1) */ 328 if (patch_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
326 op[1] = 0xe8410028; 329 printk(KERN_ERR "REL24 out of range!\n");
327 330 return -EINVAL;
328 pr_devel("write to %lx\n", rec->ip); 331 }
329
330 if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
331 return -EPERM;
332
333 flush_icache_range(ip, ip + 8);
334 332
335 return 0; 333 return 0;
336} 334}