• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/kernel/
1/*
2 * Dynamic function tracing support.
3 *
4 * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com>
5 *
6 * For licencing details, see COPYING.
7 *
8 * Defines low-level handling of mcount calls when the kernel
9 * is compiled with the -pg flag. When using dynamic ftrace, the
10 * mcount call-sites get patched lazily with NOP till they are
11 * enabled. All code mutation routines here take effect atomically.
12 */
13
14#include <linux/ftrace.h>
15
16#include <asm/cacheflush.h>
17#include <asm/ftrace.h>
18
19#define PC_OFFSET      8
20#define BL_OPCODE      0xeb000000
21#define BL_OFFSET_MASK 0x00ffffff
22
23static unsigned long bl_insn;
24static const unsigned long NOP = 0xe1a00000; /* mov r0, r0 */
25
26unsigned char *ftrace_nop_replace(void)
27{
28	return (char *)&NOP;
29}
30
31/* construct a branch (BL) instruction to addr */
32unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr)
33{
34	long offset;
35
36	offset = (long)addr - (long)(pc + PC_OFFSET);
37	if (unlikely(offset < -33554432 || offset > 33554428)) {
38		/* Can't generate branches that far (from ARM ARM). Ftrace
39		 * doesn't generate branches outside of kernel text.
40		 */
41		WARN_ON_ONCE(1);
42		return NULL;
43	}
44	offset = (offset >> 2) & BL_OFFSET_MASK;
45	bl_insn = BL_OPCODE | offset;
46	return (unsigned char *)&bl_insn;
47}
48
49int ftrace_modify_code(unsigned long pc, unsigned char *old_code,
50		       unsigned char *new_code)
51{
52	unsigned long err = 0, replaced = 0, old, new;
53
54	old = *(unsigned long *)old_code;
55	new = *(unsigned long *)new_code;
56
57	__asm__ __volatile__ (
58		"1:  ldr    %1, [%2]  \n"
59		"    cmp    %1, %4    \n"
60		"2:  streq  %3, [%2]  \n"
61		"    cmpne  %1, %3    \n"
62		"    movne  %0, #2    \n"
63		"3:\n"
64
65		".pushsection .fixup, \"ax\"\n"
66		"4:  mov  %0, #1  \n"
67		"    b    3b      \n"
68		".popsection\n"
69
70		".pushsection __ex_table, \"a\"\n"
71		"    .long 1b, 4b \n"
72		"    .long 2b, 4b \n"
73		".popsection\n"
74
75		: "=r"(err), "=r"(replaced)
76		: "r"(pc), "r"(new), "r"(old), "0"(err), "1"(replaced)
77		: "memory");
78
79	if (!err && (replaced == old))
80		flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
81
82	return err;
83}
84
85int ftrace_update_ftrace_func(ftrace_func_t func)
86{
87	int ret;
88	unsigned long pc, old;
89	unsigned char *new;
90
91	pc = (unsigned long)&ftrace_call;
92	memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
93	new = ftrace_call_replace(pc, (unsigned long)func);
94	ret = ftrace_modify_code(pc, (unsigned char *)&old, new);
95	return ret;
96}
97
98/* run from ftrace_init with irqs disabled */
99int __init ftrace_dyn_arch_init(void *data)
100{
101	ftrace_mcount_set(data);
102	return 0;
103}
104