diff options
-rw-r--r-- | arch/powerpc/kernel/ftrace.c | 40 |
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 | } |