aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-11-25 17:06:19 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-28 08:08:01 -0500
commit0029ff87529dff01a4b9c5bf380a0caacb5f7418 (patch)
tree143534dbd52f76ae008b3abc21256c00d4d9fa9b /arch/powerpc
parentec682cef2d2c1a25a198d32a87fe2649da671d1e (diff)
powerpc: ftrace, use create_branch
Impact: clean up Paul Mackerras pointed out that the code to determine if the branch can reach the destination is incorrect. Michael Ellerman suggested to pull out the code from create_branch and use that. Simply using create_branch is probably the best. Reported-by: Michael Ellerman <michael@ellerman.id.au> Reported-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/ftrace.c54
1 files changed, 12 insertions, 42 deletions
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index a4640e4f1172..5355244c99ff 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -114,19 +114,9 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
114 */ 114 */
115static int test_24bit_addr(unsigned long ip, unsigned long addr) 115static int test_24bit_addr(unsigned long ip, unsigned long addr)
116{ 116{
117 long diff;
118 117
119 /* 118 /* use the create_branch to verify that this offset can be branched */
120 * Can we get to addr from ip in 24 bits? 119 return create_branch((unsigned int *)ip, addr, 0);
121 * (26 really, since we mulitply by 4 for 4 byte alignment)
122 */
123 diff = addr - ip;
124
125 /*
126 * Return true if diff is less than 1 << 25
127 * and greater than -1 << 26.
128 */
129 return (diff < (1 << 25)) && (diff > (-1 << 26));
130} 120}
131 121
132static int is_bl_op(unsigned int op) 122static int is_bl_op(unsigned int op)
@@ -134,11 +124,6 @@ static int is_bl_op(unsigned int op)
134 return (op & 0xfc000003) == 0x48000001; 124 return (op & 0xfc000003) == 0x48000001;
135} 125}
136 126
137static int test_offset(unsigned long offset)
138{
139 return (offset + 0x2000000 > 0x3ffffff) || ((offset & 3) != 0);
140}
141
142static unsigned long find_bl_target(unsigned long ip, unsigned int op) 127static unsigned long find_bl_target(unsigned long ip, unsigned int op)
143{ 128{
144 static int offset; 129 static int offset;
@@ -151,12 +136,6 @@ static unsigned long find_bl_target(unsigned long ip, unsigned int op)
151 return ip + (long)offset; 136 return ip + (long)offset;
152} 137}
153 138
154static unsigned int branch_offset(unsigned long offset)
155{
156 /* return "bl ip+offset" */
157 return 0x48000001 | (offset & 0x03fffffc);
158}
159
160#ifdef CONFIG_PPC64 139#ifdef CONFIG_PPC64
161static int 140static int
162__ftrace_make_nop(struct module *mod, 141__ftrace_make_nop(struct module *mod,
@@ -402,7 +381,6 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
402{ 381{
403 unsigned int op[2]; 382 unsigned int op[2];
404 unsigned long ip = rec->ip; 383 unsigned long ip = rec->ip;
405 unsigned long offset;
406 384
407 /* read where this goes */ 385 /* read where this goes */
408 if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) 386 if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
@@ -424,17 +402,14 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
424 return -EINVAL; 402 return -EINVAL;
425 } 403 }
426 404
427 /* now calculate a jump to the ftrace caller trampoline */ 405 /* create the branch to the trampoline */
428 offset = rec->arch.mod->arch.tramp - ip; 406 op[0] = create_branch((unsigned int *)ip,
429 407 rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
430 if (test_offset(offset)) { 408 if (!op[0]) {
431 printk(KERN_ERR "REL24 %li out of range!\n", 409 printk(KERN_ERR "REL24 out of range!\n");
432 (long int)offset);
433 return -EINVAL; 410 return -EINVAL;
434 } 411 }
435 412
436 /* Set to "bl addr" */
437 op[0] = branch_offset(offset);
438 /* ld r2,40(r1) */ 413 /* ld r2,40(r1) */
439 op[1] = 0xe8410028; 414 op[1] = 0xe8410028;
440 415
@@ -453,7 +428,6 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
453{ 428{
454 unsigned int op; 429 unsigned int op;
455 unsigned long ip = rec->ip; 430 unsigned long ip = rec->ip;
456 unsigned long offset;
457 431
458 /* read where this goes */ 432 /* read where this goes */
459 if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE)) 433 if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
@@ -471,18 +445,14 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
471 return -EINVAL; 445 return -EINVAL;
472 } 446 }
473 447
474 /* now calculate a jump to the ftrace caller trampoline */ 448 /* create the branch to the trampoline */
475 offset = rec->arch.mod->arch.tramp - ip; 449 op = create_branch((unsigned int *)ip,
476 450 rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
477 if (test_offset(offset)) { 451 if (!op) {
478 printk(KERN_ERR "REL24 %li out of range!\n", 452 printk(KERN_ERR "REL24 out of range!\n");
479 (long int)offset);
480 return -EINVAL; 453 return -EINVAL;
481 } 454 }
482 455
483 /* Set to "bl addr" */
484 op = branch_offset(offset);
485
486 DEBUGP("write to %lx\n", rec->ip); 456 DEBUGP("write to %lx\n", rec->ip);
487 457
488 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) 458 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))