aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2014-04-04 01:54:04 -0400
committerAnton Blanchard <anton@samba.org>2014-04-22 20:05:35 -0400
commit24a1bdc358bf3c533f7d575202e92aaca0f91761 (patch)
tree22adf64f47105e2bf6141b2d6edc5a5f53d4f41e
parent62c9da6a8b394eb9336a255fc23457202d6b9755 (diff)
powerpc/ftrace: Fix ABIv2 issues with __ftrace_make_call
__ftrace_make_call assumed ABIv1 TOC stack offsets, so it broke on ABIv2. While we are here, we can simplify the instruction modification code. Since we always update one instruction there is no need to probe_kernel_write and flush_icache_range, just use patch_branch. Signed-off-by: Anton Blanchard <anton@samba.org>
-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}