Blackfin: add support for dynamic ftrace
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
@@ -1,17 +1,101 @@
|
||||
/*
|
||||
* ftrace graph code
|
||||
*
|
||||
* Copyright (C) 2009 Analog Devices Inc.
|
||||
* Copyright (C) 2009-2010 Analog Devices Inc.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
static const unsigned char mnop[] = {
|
||||
0x03, 0xc0, 0x00, 0x18, /* MNOP; */
|
||||
0x03, 0xc0, 0x00, 0x18, /* MNOP; */
|
||||
};
|
||||
|
||||
static void bfin_make_pcrel24(unsigned char *insn, unsigned long src,
|
||||
unsigned long dst)
|
||||
{
|
||||
uint32_t pcrel = (dst - src) >> 1;
|
||||
insn[0] = pcrel >> 16;
|
||||
insn[1] = 0xe3;
|
||||
insn[2] = pcrel;
|
||||
insn[3] = pcrel >> 8;
|
||||
}
|
||||
#define bfin_make_pcrel24(insn, src, dst) bfin_make_pcrel24(insn, src, (unsigned long)(dst))
|
||||
|
||||
static int ftrace_modify_code(unsigned long ip, const unsigned char *code,
|
||||
unsigned long len)
|
||||
{
|
||||
int ret = probe_kernel_write((void *)ip, (void *)code, len);
|
||||
flush_icache_range(ip, ip + len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
|
||||
unsigned long addr)
|
||||
{
|
||||
/* Turn the mcount call site into two MNOPs as those are 32bit insns */
|
||||
return ftrace_modify_code(rec->ip, mnop, sizeof(mnop));
|
||||
}
|
||||
|
||||
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
/* Restore the mcount call site */
|
||||
unsigned char call[8];
|
||||
call[0] = 0x67; /* [--SP] = RETS; */
|
||||
call[1] = 0x01;
|
||||
bfin_make_pcrel24(&call[2], rec->ip + 2, addr);
|
||||
call[6] = 0x27; /* RETS = [SP++]; */
|
||||
call[7] = 0x01;
|
||||
return ftrace_modify_code(rec->ip, call, sizeof(call));
|
||||
}
|
||||
|
||||
int ftrace_update_ftrace_func(ftrace_func_t func)
|
||||
{
|
||||
unsigned char call[4];
|
||||
unsigned long ip = (unsigned long)&ftrace_call;
|
||||
bfin_make_pcrel24(call, ip, func);
|
||||
return ftrace_modify_code(ip, call, sizeof(call));
|
||||
}
|
||||
|
||||
int __init ftrace_dyn_arch_init(void *data)
|
||||
{
|
||||
/* return value is done indirectly via data */
|
||||
*(unsigned long *)data = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
|
||||
# ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
extern void ftrace_graph_call(void);
|
||||
|
||||
int ftrace_enable_ftrace_graph_caller(void)
|
||||
{
|
||||
unsigned long ip = (unsigned long)&ftrace_graph_call;
|
||||
uint16_t jump_pcrel12 = ((unsigned long)&ftrace_graph_caller - ip) >> 1;
|
||||
jump_pcrel12 |= 0x2000;
|
||||
return ftrace_modify_code(ip, (void *)&jump_pcrel12, sizeof(jump_pcrel12));
|
||||
}
|
||||
|
||||
int ftrace_disable_ftrace_graph_caller(void)
|
||||
{
|
||||
return ftrace_modify_code((unsigned long)&ftrace_graph_call, empty_zero_page, 2);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Hook the return address and push it in the stack of return addrs
|
||||
* in current thread info.
|
||||
|
Reference in New Issue
Block a user