blob: 5b5d16b2cac86b0dad038cdcc13c2cc686bd41a2 [file] [log] [blame]
Steven Rostedt4e491d12008-05-14 23:49:44 -04001/*
2 * Code for replacing ftrace calls with jumps.
3 *
4 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
5 *
6 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
7 *
Steven Rostedt6794c782009-02-09 21:10:27 -08008 * Added function graph tracer code, taken from x86 that was written
9 * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
10 *
Steven Rostedt4e491d12008-05-14 23:49:44 -040011 */
12
13#include <linux/spinlock.h>
14#include <linux/hardirq.h>
Steven Rostedte4486fe2008-11-14 16:21:20 -080015#include <linux/uaccess.h>
Steven Rostedtf48cb8b2008-11-14 20:47:03 -080016#include <linux/module.h>
Steven Rostedt4e491d12008-05-14 23:49:44 -040017#include <linux/ftrace.h>
18#include <linux/percpu.h>
19#include <linux/init.h>
20#include <linux/list.h>
21
22#include <asm/cacheflush.h>
Steven Rostedtf48cb8b2008-11-14 20:47:03 -080023#include <asm/code-patching.h>
Abhishek Sagar395a59d2008-06-21 23:47:27 +053024#include <asm/ftrace.h>
Steven Rostedt4e491d12008-05-14 23:49:44 -040025
Steven Rostedt4e491d12008-05-14 23:49:44 -040026#ifdef CONFIG_PPC32
27# define GET_ADDR(addr) addr
28#else
29/* PowerPC64's functions are data that points to the functions */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -080030# define GET_ADDR(addr) (*(unsigned long *)addr)
Steven Rostedt4e491d12008-05-14 23:49:44 -040031#endif
32
Steven Rostedt6794c782009-02-09 21:10:27 -080033#ifdef CONFIG_DYNAMIC_FTRACE
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080034static unsigned int ftrace_nop_replace(void)
Steven Rostedt4e491d12008-05-14 23:49:44 -040035{
Kumar Gala16c57b32009-02-10 20:10:44 +000036 return PPC_INST_NOP;
Steven Rostedt4e491d12008-05-14 23:49:44 -040037}
38
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080039static unsigned int
Steven Rostedt46542882009-02-10 22:19:54 -080040ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
Steven Rostedt4e491d12008-05-14 23:49:44 -040041{
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080042 unsigned int op;
Steven Rostedt4e491d12008-05-14 23:49:44 -040043
44 addr = GET_ADDR(addr);
45
Steven Rostedt46542882009-02-10 22:19:54 -080046 /* if (link) set op to 'bl' else 'b' */
Steven Rostedtbb9b9032009-02-13 06:45:27 -080047 op = create_branch((unsigned int *)ip, addr, link ? 1 : 0);
Steven Rostedt4e491d12008-05-14 23:49:44 -040048
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080049 return op;
Steven Rostedt4e491d12008-05-14 23:49:44 -040050}
51
52#ifdef CONFIG_PPC64
53# define _ASM_ALIGN " .align 3 "
54# define _ASM_PTR " .llong "
55#else
56# define _ASM_ALIGN " .align 2 "
57# define _ASM_PTR " .long "
58#endif
59
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -080060static int
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080061ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
Steven Rostedt4e491d12008-05-14 23:49:44 -040062{
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080063 unsigned int replaced;
Steven Rostedt4e491d12008-05-14 23:49:44 -040064
Steven Rostedt4e491d12008-05-14 23:49:44 -040065 /*
66 * Note: Due to modules and __init, code can
67 * disappear and change, we need to protect against faulting
Steven Rostedte4486fe2008-11-14 16:21:20 -080068 * as well as code changing. We do this by using the
69 * probe_kernel_* functions.
Steven Rostedt4e491d12008-05-14 23:49:44 -040070 *
71 * No real locking needed, this code is run through
Steven Rostedte4486fe2008-11-14 16:21:20 -080072 * kstop_machine, or before SMP starts.
Steven Rostedt4e491d12008-05-14 23:49:44 -040073 */
Steven Rostedt4e491d12008-05-14 23:49:44 -040074
Steven Rostedte4486fe2008-11-14 16:21:20 -080075 /* read the text we want to modify */
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080076 if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE))
Steven Rostedte4486fe2008-11-14 16:21:20 -080077 return -EFAULT;
Steven Rostedt4e491d12008-05-14 23:49:44 -040078
Steven Rostedte4486fe2008-11-14 16:21:20 -080079 /* Make sure it is what we expect it to be */
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080080 if (replaced != old)
Steven Rostedte4486fe2008-11-14 16:21:20 -080081 return -EINVAL;
Steven Rostedt4e491d12008-05-14 23:49:44 -040082
Steven Rostedte4486fe2008-11-14 16:21:20 -080083 /* replace the text with the new text */
Steven Rostedtb54dcfe2009-02-13 06:31:39 -080084 if (probe_kernel_write((void *)ip, &new, MCOUNT_INSN_SIZE))
Steven Rostedte4486fe2008-11-14 16:21:20 -080085 return -EPERM;
86
87 flush_icache_range(ip, ip + 8);
88
89 return 0;
Steven Rostedt4e491d12008-05-14 23:49:44 -040090}
91
Steven Rostedtf48cb8b2008-11-14 20:47:03 -080092/*
93 * Helper functions that are the same for both PPC64 and PPC32.
94 */
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -080095static int test_24bit_addr(unsigned long ip, unsigned long addr)
96{
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -080097
Steven Rostedt0029ff82008-11-25 14:06:19 -080098 /* use the create_branch to verify that this offset can be branched */
99 return create_branch((unsigned int *)ip, addr, 0);
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800100}
101
Steven Rostedt17be5b32009-02-05 21:33:09 -0800102#ifdef CONFIG_MODULES
103
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800104static int is_bl_op(unsigned int op)
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800105{
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800106 return (op & 0xfc000003) == 0x48000001;
107}
108
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800109static unsigned long find_bl_target(unsigned long ip, unsigned int op)
110{
111 static int offset;
112
113 offset = (op & 0x03fffffc);
114 /* make it signed */
115 if (offset & 0x02000000)
116 offset |= 0xfe000000;
117
118 return ip + (long)offset;
119}
120
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800121#ifdef CONFIG_PPC64
122static int
123__ftrace_make_nop(struct module *mod,
124 struct dyn_ftrace *rec, unsigned long addr)
125{
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800126 unsigned int op;
127 unsigned int jmp[5];
128 unsigned long ptr;
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800129 unsigned long ip = rec->ip;
130 unsigned long tramp;
131 int offset;
132
133 /* read where this goes */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800134 if (probe_kernel_read(&op, (void *)ip, sizeof(int)))
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800135 return -EFAULT;
136
137 /* Make sure that that this is still a 24bit jump */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800138 if (!is_bl_op(op)) {
139 printk(KERN_ERR "Not expected bl: opcode is %x\n", op);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800140 return -EINVAL;
141 }
142
143 /* lets find where the pointer goes */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800144 tramp = find_bl_target(ip, op);
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800145
146 /*
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800147 * On PPC64 the trampoline looks like:
148 * 0x3d, 0x82, 0x00, 0x00, addis r12,r2, <high>
149 * 0x39, 0x8c, 0x00, 0x00, addi r12,r12, <low>
150 * Where the bytes 2,3,6 and 7 make up the 32bit offset
151 * to the TOC that holds the pointer.
152 * to jump to.
153 * 0xf8, 0x41, 0x00, 0x28, std r2,40(r1)
154 * 0xe9, 0x6c, 0x00, 0x20, ld r11,32(r12)
155 * The actually address is 32 bytes from the offset
156 * into the TOC.
157 * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12)
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800158 */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800159
Steven Rostedt44e1d062009-02-04 18:29:03 -0800160 pr_debug("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800161
162 /* Find where the trampoline jumps to */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800163 if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800164 printk(KERN_ERR "Failed to read %lx\n", tramp);
165 return -EFAULT;
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800166 }
167
Steven Rostedt44e1d062009-02-04 18:29:03 -0800168 pr_debug(" %08x %08x", jmp[0], jmp[1]);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800169
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800170 /* verify that this is what we expect it to be */
171 if (((jmp[0] & 0xffff0000) != 0x3d820000) ||
172 ((jmp[1] & 0xffff0000) != 0x398c0000) ||
173 (jmp[2] != 0xf8410028) ||
174 (jmp[3] != 0xe96c0020) ||
175 (jmp[4] != 0xe84c0028)) {
176 printk(KERN_ERR "Not a trampoline\n");
177 return -EINVAL;
178 }
179
Steven Rostedtf25f9072009-02-07 20:22:40 +0000180 /* The bottom half is signed extended */
181 offset = ((unsigned)((unsigned short)jmp[0]) << 16) +
182 (int)((short)jmp[1]);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800183
Steven Rostedt44e1d062009-02-04 18:29:03 -0800184 pr_debug(" %x ", offset);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800185
186 /* get the address this jumps too */
187 tramp = mod->arch.toc + offset + 32;
Steven Rostedt44e1d062009-02-04 18:29:03 -0800188 pr_debug("toc: %lx", tramp);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800189
190 if (probe_kernel_read(jmp, (void *)tramp, 8)) {
191 printk(KERN_ERR "Failed to read %lx\n", tramp);
192 return -EFAULT;
193 }
194
Steven Rostedt44e1d062009-02-04 18:29:03 -0800195 pr_debug(" %08x %08x\n", jmp[0], jmp[1]);
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800196
197 ptr = ((unsigned long)jmp[0] << 32) + jmp[1];
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800198
199 /* This should match what was called */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800200 if (ptr != GET_ADDR(addr)) {
201 printk(KERN_ERR "addr does not match %lx\n", ptr);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800202 return -EINVAL;
203 }
204
205 /*
206 * We want to nop the line, but the next line is
207 * 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1)
208 * This needs to be turned to a nop too.
209 */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800210 if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE))
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800211 return -EFAULT;
212
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800213 if (op != 0xe8410028) {
214 printk(KERN_ERR "Next line is not ld! (%08x)\n", op);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800215 return -EINVAL;
216 }
217
218 /*
219 * Milton Miller pointed out that we can not blindly do nops.
220 * If a task was preempted when calling a trace function,
221 * the nops will remove the way to restore the TOC in r2
222 * and the r2 TOC will get corrupted.
223 */
224
225 /*
226 * Replace:
227 * bl <tramp> <==== will be replaced with "b 1f"
228 * ld r2,40(r1)
229 * 1:
230 */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800231 op = 0x48000008; /* b +8 */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800232
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800233 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800234 return -EPERM;
235
Steven Rostedtec682ce2008-11-25 10:22:48 -0800236
237 flush_icache_range(ip, ip + 8);
238
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800239 return 0;
240}
241
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800242#else /* !PPC64 */
243static int
244__ftrace_make_nop(struct module *mod,
245 struct dyn_ftrace *rec, unsigned long addr)
246{
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800247 unsigned int op;
248 unsigned int jmp[4];
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500249 unsigned long ip = rec->ip;
250 unsigned long tramp;
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500251
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800252 if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500253 return -EFAULT;
254
255 /* Make sure that that this is still a 24bit jump */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800256 if (!is_bl_op(op)) {
257 printk(KERN_ERR "Not expected bl: opcode is %x\n", op);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500258 return -EINVAL;
259 }
260
261 /* lets find where the pointer goes */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800262 tramp = find_bl_target(ip, op);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500263
264 /*
265 * On PPC32 the trampoline looks like:
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800266 * 0x3d, 0x60, 0x00, 0x00 lis r11,sym@ha
267 * 0x39, 0x6b, 0x00, 0x00 addi r11,r11,sym@l
268 * 0x7d, 0x69, 0x03, 0xa6 mtctr r11
269 * 0x4e, 0x80, 0x04, 0x20 bctr
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500270 */
271
Steven Rostedt44e1d062009-02-04 18:29:03 -0800272 pr_debug("ip:%lx jumps to %lx", ip, tramp);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500273
274 /* Find where the trampoline jumps to */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800275 if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500276 printk(KERN_ERR "Failed to read %lx\n", tramp);
277 return -EFAULT;
278 }
279
Steven Rostedt44e1d062009-02-04 18:29:03 -0800280 pr_debug(" %08x %08x ", jmp[0], jmp[1]);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500281
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800282 /* verify that this is what we expect it to be */
283 if (((jmp[0] & 0xffff0000) != 0x3d600000) ||
284 ((jmp[1] & 0xffff0000) != 0x396b0000) ||
285 (jmp[2] != 0x7d6903a6) ||
286 (jmp[3] != 0x4e800420)) {
287 printk(KERN_ERR "Not a trampoline\n");
288 return -EINVAL;
289 }
290
291 tramp = (jmp[1] & 0xffff) |
292 ((jmp[0] & 0xffff) << 16);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500293 if (tramp & 0x8000)
294 tramp -= 0x10000;
295
Steven Rostedt44e1d062009-02-04 18:29:03 -0800296 pr_debug(" %x ", tramp);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500297
298 if (tramp != addr) {
299 printk(KERN_ERR
300 "Trampoline location %08lx does not match addr\n",
301 tramp);
302 return -EINVAL;
303 }
304
Kumar Gala16c57b32009-02-10 20:10:44 +0000305 op = PPC_INST_NOP;
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500306
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800307 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500308 return -EPERM;
309
Steven Rostedtec682ce2008-11-25 10:22:48 -0800310 flush_icache_range(ip, ip + 8);
311
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800312 return 0;
313}
314#endif /* PPC64 */
Steven Rostedt17be5b32009-02-05 21:33:09 -0800315#endif /* CONFIG_MODULES */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800316
317int ftrace_make_nop(struct module *mod,
318 struct dyn_ftrace *rec, unsigned long addr)
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800319{
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800320 unsigned long ip = rec->ip;
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800321 unsigned int old, new;
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800322
323 /*
324 * If the calling address is more that 24 bits away,
325 * then we had to use a trampoline to make the call.
326 * Otherwise just update the call site.
327 */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800328 if (test_24bit_addr(ip, addr)) {
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800329 /* within range */
Steven Rostedt46542882009-02-10 22:19:54 -0800330 old = ftrace_call_replace(ip, addr, 1);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800331 new = ftrace_nop_replace();
332 return ftrace_modify_code(ip, old, new);
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800333 }
334
Steven Rostedt17be5b32009-02-05 21:33:09 -0800335#ifdef CONFIG_MODULES
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800336 /*
337 * Out of range jumps are called from modules.
338 * We should either already have a pointer to the module
339 * or it has been passed in.
340 */
341 if (!rec->arch.mod) {
342 if (!mod) {
343 printk(KERN_ERR "No module loaded addr=%lx\n",
344 addr);
345 return -EFAULT;
346 }
347 rec->arch.mod = mod;
348 } else if (mod) {
349 if (mod != rec->arch.mod) {
350 printk(KERN_ERR
351 "Record mod %p not equal to passed in mod %p\n",
352 rec->arch.mod, mod);
353 return -EINVAL;
354 }
355 /* nothing to do if mod == rec->arch.mod */
356 } else
357 mod = rec->arch.mod;
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800358
359 return __ftrace_make_nop(mod, rec, addr);
Steven Rostedt17be5b32009-02-05 21:33:09 -0800360#else
361 /* We should not get here without modules */
362 return -EINVAL;
363#endif /* CONFIG_MODULES */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800364}
365
Steven Rostedt17be5b32009-02-05 21:33:09 -0800366#ifdef CONFIG_MODULES
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800367#ifdef CONFIG_PPC64
368static int
369__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
370{
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800371 unsigned int op[2];
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800372 unsigned long ip = rec->ip;
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800373
374 /* read where this goes */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800375 if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800376 return -EFAULT;
377
378 /*
379 * It should be pointing to two nops or
380 * b +8; ld r2,40(r1)
381 */
382 if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) &&
Kumar Gala16c57b32009-02-10 20:10:44 +0000383 ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) {
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800384 printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]);
385 return -EINVAL;
386 }
387
388 /* If we never set up a trampoline to ftrace_caller, then bail */
389 if (!rec->arch.mod->arch.tramp) {
390 printk(KERN_ERR "No ftrace trampoline\n");
391 return -EINVAL;
392 }
393
Steven Rostedt0029ff82008-11-25 14:06:19 -0800394 /* create the branch to the trampoline */
395 op[0] = create_branch((unsigned int *)ip,
396 rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
397 if (!op[0]) {
398 printk(KERN_ERR "REL24 out of range!\n");
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800399 return -EINVAL;
400 }
401
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800402 /* ld r2,40(r1) */
403 op[1] = 0xe8410028;
404
Steven Rostedt44e1d062009-02-04 18:29:03 -0800405 pr_debug("write to %lx\n", rec->ip);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800406
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800407 if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800408 return -EPERM;
409
Steven Rostedtec682ce2008-11-25 10:22:48 -0800410 flush_icache_range(ip, ip + 8);
411
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800412 return 0;
413}
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800414#else
415static int
416__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
417{
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800418 unsigned int op;
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500419 unsigned long ip = rec->ip;
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500420
421 /* read where this goes */
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800422 if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500423 return -EFAULT;
424
425 /* It should be pointing to a nop */
Kumar Gala16c57b32009-02-10 20:10:44 +0000426 if (op != PPC_INST_NOP) {
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800427 printk(KERN_ERR "Expected NOP but have %x\n", op);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500428 return -EINVAL;
429 }
430
431 /* If we never set up a trampoline to ftrace_caller, then bail */
432 if (!rec->arch.mod->arch.tramp) {
433 printk(KERN_ERR "No ftrace trampoline\n");
434 return -EINVAL;
435 }
436
Steven Rostedt0029ff82008-11-25 14:06:19 -0800437 /* create the branch to the trampoline */
438 op = create_branch((unsigned int *)ip,
439 rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
440 if (!op) {
441 printk(KERN_ERR "REL24 out of range!\n");
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500442 return -EINVAL;
443 }
444
Steven Rostedt44e1d062009-02-04 18:29:03 -0800445 pr_debug("write to %lx\n", rec->ip);
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500446
Steven Rostedtd9af12b72008-11-25 06:39:18 -0800447 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
Steven Rostedt7cc45e62008-11-15 02:39:05 -0500448 return -EPERM;
449
Steven Rostedtec682ce2008-11-25 10:22:48 -0800450 flush_icache_range(ip, ip + 8);
451
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800452 return 0;
453}
454#endif /* CONFIG_PPC64 */
Steven Rostedt17be5b32009-02-05 21:33:09 -0800455#endif /* CONFIG_MODULES */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800456
457int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
458{
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800459 unsigned long ip = rec->ip;
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800460 unsigned int old, new;
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800461
462 /*
463 * If the calling address is more that 24 bits away,
464 * then we had to use a trampoline to make the call.
465 * Otherwise just update the call site.
466 */
467 if (test_24bit_addr(ip, addr)) {
468 /* within range */
469 old = ftrace_nop_replace();
Steven Rostedt46542882009-02-10 22:19:54 -0800470 new = ftrace_call_replace(ip, addr, 1);
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800471 return ftrace_modify_code(ip, old, new);
472 }
473
Steven Rostedt17be5b32009-02-05 21:33:09 -0800474#ifdef CONFIG_MODULES
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800475 /*
476 * Out of range jumps are called from modules.
477 * Being that we are converting from nop, it had better
478 * already have a module defined.
479 */
480 if (!rec->arch.mod) {
481 printk(KERN_ERR "No module loaded\n");
482 return -EINVAL;
483 }
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800484
485 return __ftrace_make_call(rec, addr);
Steven Rostedt17be5b32009-02-05 21:33:09 -0800486#else
487 /* We should not get here without modules */
488 return -EINVAL;
489#endif /* CONFIG_MODULES */
Steven Rostedtf48cb8b2008-11-14 20:47:03 -0800490}
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800491
Steven Rostedt15adc042008-10-23 09:33:08 -0400492int ftrace_update_ftrace_func(ftrace_func_t func)
Steven Rostedt4e491d12008-05-14 23:49:44 -0400493{
494 unsigned long ip = (unsigned long)(&ftrace_call);
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800495 unsigned int old, new;
Steven Rostedt4e491d12008-05-14 23:49:44 -0400496 int ret;
497
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800498 old = *(unsigned int *)&ftrace_call;
Steven Rostedt46542882009-02-10 22:19:54 -0800499 new = ftrace_call_replace(ip, (unsigned long)func, 1);
Steven Rostedt4e491d12008-05-14 23:49:44 -0400500 ret = ftrace_modify_code(ip, old, new);
501
502 return ret;
503}
504
Steven Rostedt4e491d12008-05-14 23:49:44 -0400505int __init ftrace_dyn_arch_init(void *data)
506{
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800507 /* caller expects data to be zero */
508 unsigned long *p = data;
Steven Rostedt4e491d12008-05-14 23:49:44 -0400509
Steven Rostedt8fd6e5a2008-11-14 16:21:19 -0800510 *p = 0;
Steven Rostedt4e491d12008-05-14 23:49:44 -0400511
512 return 0;
513}
Steven Rostedt6794c782009-02-09 21:10:27 -0800514#endif /* CONFIG_DYNAMIC_FTRACE */
515
516#ifdef CONFIG_FUNCTION_GRAPH_TRACER
517
Steven Rostedt46542882009-02-10 22:19:54 -0800518#ifdef CONFIG_DYNAMIC_FTRACE
519extern void ftrace_graph_call(void);
520extern void ftrace_graph_stub(void);
521
522int ftrace_enable_ftrace_graph_caller(void)
523{
524 unsigned long ip = (unsigned long)(&ftrace_graph_call);
525 unsigned long addr = (unsigned long)(&ftrace_graph_caller);
526 unsigned long stub = (unsigned long)(&ftrace_graph_stub);
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800527 unsigned int old, new;
Steven Rostedt46542882009-02-10 22:19:54 -0800528
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800529 old = ftrace_call_replace(ip, stub, 0);
Steven Rostedt46542882009-02-10 22:19:54 -0800530 new = ftrace_call_replace(ip, addr, 0);
531
532 return ftrace_modify_code(ip, old, new);
533}
534
535int ftrace_disable_ftrace_graph_caller(void)
536{
537 unsigned long ip = (unsigned long)(&ftrace_graph_call);
538 unsigned long addr = (unsigned long)(&ftrace_graph_caller);
539 unsigned long stub = (unsigned long)(&ftrace_graph_stub);
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800540 unsigned int old, new;
Steven Rostedt46542882009-02-10 22:19:54 -0800541
Steven Rostedtb54dcfe2009-02-13 06:31:39 -0800542 old = ftrace_call_replace(ip, addr, 0);
Steven Rostedt46542882009-02-10 22:19:54 -0800543 new = ftrace_call_replace(ip, stub, 0);
544
545 return ftrace_modify_code(ip, old, new);
546}
547#endif /* CONFIG_DYNAMIC_FTRACE */
548
Steven Rostedtbb725342009-02-11 12:45:49 -0800549#ifdef CONFIG_PPC64
550extern void mod_return_to_handler(void);
551#endif
552
Steven Rostedt6794c782009-02-09 21:10:27 -0800553/*
554 * Hook the return address and push it in the stack of return addrs
555 * in current thread info.
556 */
557void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
558{
559 unsigned long old;
560 unsigned long long calltime;
561 int faulted;
562 struct ftrace_graph_ent trace;
Steven Rostedtbb725342009-02-11 12:45:49 -0800563 unsigned long return_hooker = (unsigned long)&return_to_handler;
Steven Rostedt6794c782009-02-09 21:10:27 -0800564
565 if (unlikely(atomic_read(&current->tracing_graph_pause)))
566 return;
567
Steven Rostedtbb725342009-02-11 12:45:49 -0800568#if CONFIG_PPC64
569 /* non core kernel code needs to save and restore the TOC */
570 if (REGION_ID(self_addr) != KERNEL_REGION_ID)
571 return_hooker = (unsigned long)&mod_return_to_handler;
572#endif
573
Steven Rostedt6794c782009-02-09 21:10:27 -0800574 return_hooker = GET_ADDR(return_hooker);
575
576 /*
577 * Protect against fault, even if it shouldn't
578 * happen. This tool is too much intrusive to
579 * ignore such a protection.
580 */
581 asm volatile(
582 "1: " PPC_LL "%[old], 0(%[parent])\n"
583 "2: " PPC_STL "%[return_hooker], 0(%[parent])\n"
584 " li %[faulted], 0\n"
Steven Rostedtfad4f472009-02-11 19:10:57 -0500585 "3:\n"
Steven Rostedt6794c782009-02-09 21:10:27 -0800586
587 ".section .fixup, \"ax\"\n"
588 "4: li %[faulted], 1\n"
589 " b 3b\n"
590 ".previous\n"
591
592 ".section __ex_table,\"a\"\n"
593 PPC_LONG_ALIGN "\n"
594 PPC_LONG "1b,4b\n"
595 PPC_LONG "2b,4b\n"
596 ".previous"
597
598 : [old] "=r" (old), [faulted] "=r" (faulted)
599 : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
600 : "memory"
601 );
602
603 if (unlikely(faulted)) {
604 ftrace_graph_stop();
605 WARN_ON(1);
606 return;
607 }
608
609 calltime = cpu_clock(raw_smp_processor_id());
610
611 if (ftrace_push_return_trace(old, calltime,
612 self_addr, &trace.depth) == -EBUSY) {
613 *parent = old;
614 return;
615 }
616
617 trace.func = self_addr;
618
619 /* Only trace if the calling function expects to */
620 if (!ftrace_graph_entry(&trace)) {
621 current->curr_ret_stack--;
622 *parent = old;
623 }
624}
625#endif /* CONFIG_FUNCTION_GRAPH_TRACER */