···12121313#ifndef __ASSEMBLY__14141515+#ifdef CONFIG_DYNAMIC_FTRACE1616+1717+extern void _mcount(void);1818+#define MCOUNT_ADDR ((unsigned long)_mcount)1919+2020+static inline unsigned long ftrace_call_adjust(unsigned long addr)2121+{2222+ return addr;2323+}2424+2525+struct dyn_arch_ftrace {2626+ /* No extra data needed for Blackfin */2727+};2828+2929+#endif3030+1531#ifdef CONFIG_FRAME_POINTER1632#include <linux/mm.h>1733
···10101111.text12121313+#ifdef CONFIG_DYNAMIC_FTRACE1414+1515+/* Simple stub so we can boot the kernel until runtime patching has1616+ * disabled all calls to this. Then it'll be unused.1717+ */1818+ENTRY(__mcount)1919+# if ANOMALY_050003712020+ nop; nop; nop; nop;2121+# endif2222+ rts;2323+ENDPROC(__mcount)2424+1325/* GCC will have called us before setting up the function prologue, so we1426 * can clobber the normal scratch registers, but we need to make sure to1527 * save/restore the registers used for argument passing (R0-R2) in case···3220 * function. And since GCC pushed the previous RETS for us, the previous3321 * function will be waiting there. mmmm pie.3422 */3535-ENTRY(__mcount)3636-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST2323+ENTRY(_ftrace_caller)2424+# ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST3725 /* optional micro optimization: return if stopped */3826 p1.l = _function_trace_stop;3927 p1.h = _function_trace_stop;4028 r3 = [p1];4129 cc = r3 == 0;4230 if ! cc jump _ftrace_stub (bp);4343-#endif3131+# endif3232+3333+ /* save first/second/third function arg and the return register */3434+ [--sp] = r2;3535+ [--sp] = r0;3636+ [--sp] = r1;3737+ [--sp] = rets;3838+3939+ /* function_trace_call(unsigned long ip, unsigned long parent_ip):4040+ * ip: this point was called by ...4141+ * parent_ip: ... this function4242+ * the ip itself will need adjusting for the mcount call4343+ */4444+ r0 = rets;4545+ r1 = [sp + 16]; /* skip the 4 local regs on stack */4646+ r0 += -MCOUNT_INSN_SIZE;4747+4848+.globl _ftrace_call4949+_ftrace_call:5050+ call _ftrace_stub5151+5252+# ifdef CONFIG_FUNCTION_GRAPH_TRACER5353+.globl _ftrace_graph_call5454+_ftrace_graph_call:5555+ nop; /* jump _ftrace_graph_caller; */5656+# endif5757+5858+ /* restore state and get out of dodge */5959+.Lfinish_trace:6060+ rets = [sp++];6161+ r1 = [sp++];6262+ r0 = [sp++];6363+ r2 = [sp++];6464+6565+.globl _ftrace_stub6666+_ftrace_stub:6767+ rts;6868+ENDPROC(_ftrace_caller)6969+7070+#else7171+7272+/* See documentation for _ftrace_caller */7373+ENTRY(__mcount)7474+# ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST7575+ /* optional micro optimization: return if stopped */7676+ p1.l = _function_trace_stop;7777+ p1.h = _function_trace_stop;7878+ r3 = [p1];7979+ cc = r3 == 0;8080+ if ! cc jump _ftrace_stub (bp);8181+# endif44824583 /* save third function arg early so we can do testing below */4684 [--sp] = r2;···10644 cc = r2 == r3;10745 if ! cc jump .Ldo_trace;10846109109-#ifdef CONFIG_FUNCTION_GRAPH_TRACER4747+# ifdef CONFIG_FUNCTION_GRAPH_TRACER11048 /* if the ftrace_graph_return function pointer is not set to11149 * the ftrace_stub entry, call prepare_ftrace_return().11250 */···12664 r3 = [p0];12765 cc = r2 == r3;12866 if ! cc jump _ftrace_graph_caller;129129-#endif6767+# endif1306813169 r2 = [sp++];13270 rts;···165103 rts;166104ENDPROC(__mcount)167105106106+#endif107107+168108#ifdef CONFIG_FUNCTION_GRAPH_TRACER169109/* The prepare_ftrace_return() function is similar to the trace function170110 * except it takes a pointer to the location of the frompc. This is so···174110 * purposes.175111 */176112ENTRY(_ftrace_graph_caller)113113+# ifndef CONFIG_DYNAMIC_FTRACE177114 /* save first/second function arg and the return register */178115 [--sp] = r0;179116 [--sp] = r1;···183118 /* prepare_ftrace_return(parent, self_addr, frame_pointer) */184119 r0 = sp; /* unsigned long *parent */185120 r1 = rets; /* unsigned long self_addr */186186-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST121121+# else122122+ r0 = sp; /* unsigned long *parent */123123+ r1 = [sp]; /* unsigned long self_addr */124124+# endif125125+# ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST187126 r2 = fp; /* unsigned long frame_pointer */188188-#endif127127+# endif189128 r0 += 16; /* skip the 4 local regs on stack */190129 r1 += -MCOUNT_INSN_SIZE;191130 call _prepare_ftrace_return;···208139 [--sp] = r1;209140210141 /* get original return address */211211-#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST142142+# ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST212143 r0 = fp; /* Blackfin is sane, so omit this */213213-#endif144144+# endif214145 call _ftrace_return_to_handler;215146 rets = r0;216147
+85-1
arch/blackfin/kernel/ftrace.c
···11/*22 * ftrace graph code33 *44- * Copyright (C) 2009 Analog Devices Inc.44+ * Copyright (C) 2009-2010 Analog Devices Inc.55 * Licensed under the GPL-2 or later.66 */7788#include <linux/ftrace.h>99#include <linux/kernel.h>1010#include <linux/sched.h>1111+#include <linux/uaccess.h>1112#include <asm/atomic.h>1313+#include <asm/cacheflush.h>1414+1515+#ifdef CONFIG_DYNAMIC_FTRACE1616+1717+static const unsigned char mnop[] = {1818+ 0x03, 0xc0, 0x00, 0x18, /* MNOP; */1919+ 0x03, 0xc0, 0x00, 0x18, /* MNOP; */2020+};2121+2222+static void bfin_make_pcrel24(unsigned char *insn, unsigned long src,2323+ unsigned long dst)2424+{2525+ uint32_t pcrel = (dst - src) >> 1;2626+ insn[0] = pcrel >> 16;2727+ insn[1] = 0xe3;2828+ insn[2] = pcrel;2929+ insn[3] = pcrel >> 8;3030+}3131+#define bfin_make_pcrel24(insn, src, dst) bfin_make_pcrel24(insn, src, (unsigned long)(dst))3232+3333+static int ftrace_modify_code(unsigned long ip, const unsigned char *code,3434+ unsigned long len)3535+{3636+ int ret = probe_kernel_write((void *)ip, (void *)code, len);3737+ flush_icache_range(ip, ip + len);3838+ return ret;3939+}4040+4141+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,4242+ unsigned long addr)4343+{4444+ /* Turn the mcount call site into two MNOPs as those are 32bit insns */4545+ return ftrace_modify_code(rec->ip, mnop, sizeof(mnop));4646+}4747+4848+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)4949+{5050+ /* Restore the mcount call site */5151+ unsigned char call[8];5252+ call[0] = 0x67; /* [--SP] = RETS; */5353+ call[1] = 0x01;5454+ bfin_make_pcrel24(&call[2], rec->ip + 2, addr);5555+ call[6] = 0x27; /* RETS = [SP++]; */5656+ call[7] = 0x01;5757+ return ftrace_modify_code(rec->ip, call, sizeof(call));5858+}5959+6060+int ftrace_update_ftrace_func(ftrace_func_t func)6161+{6262+ unsigned char call[4];6363+ unsigned long ip = (unsigned long)&ftrace_call;6464+ bfin_make_pcrel24(call, ip, func);6565+ return ftrace_modify_code(ip, call, sizeof(call));6666+}6767+6868+int __init ftrace_dyn_arch_init(void *data)6969+{7070+ /* return value is done indirectly via data */7171+ *(unsigned long *)data = 0;7272+7373+ return 0;7474+}7575+7676+#endif12771378#ifdef CONFIG_FUNCTION_GRAPH_TRACER7979+8080+# ifdef CONFIG_DYNAMIC_FTRACE8181+8282+extern void ftrace_graph_call(void);8383+8484+int ftrace_enable_ftrace_graph_caller(void)8585+{8686+ unsigned long ip = (unsigned long)&ftrace_graph_call;8787+ uint16_t jump_pcrel12 = ((unsigned long)&ftrace_graph_caller - ip) >> 1;8888+ jump_pcrel12 |= 0x2000;8989+ return ftrace_modify_code(ip, (void *)&jump_pcrel12, sizeof(jump_pcrel12));9090+}9191+9292+int ftrace_disable_ftrace_graph_caller(void)9393+{9494+ return ftrace_modify_code((unsigned long)&ftrace_graph_call, empty_zero_page, 2);9595+}9696+9797+# endif14981599/*16100 * Hook the return address and push it in the stack of return addrs