xref: /openbmc/linux/arch/x86/kernel/ftrace.c (revision 31e889098a80ceb3e9e3c555d522b2686a6663c6)
13d083395SSteven Rostedt /*
23d083395SSteven Rostedt  * Code for replacing ftrace calls with jumps.
33d083395SSteven Rostedt  *
43d083395SSteven Rostedt  * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
53d083395SSteven Rostedt  *
63d083395SSteven Rostedt  * Thanks goes to Ingo Molnar, for suggesting the idea.
73d083395SSteven Rostedt  * Mathieu Desnoyers, for suggesting postponing the modifications.
83d083395SSteven Rostedt  * Arjan van de Ven, for keeping me straight, and explaining to me
93d083395SSteven Rostedt  * the dangers of modifying code on the run.
103d083395SSteven Rostedt  */
113d083395SSteven Rostedt 
123d083395SSteven Rostedt #include <linux/spinlock.h>
133d083395SSteven Rostedt #include <linux/hardirq.h>
146f93fc07SSteven Rostedt #include <linux/uaccess.h>
153d083395SSteven Rostedt #include <linux/ftrace.h>
163d083395SSteven Rostedt #include <linux/percpu.h>
1719b3e967SIngo Molnar #include <linux/sched.h>
183d083395SSteven Rostedt #include <linux/init.h>
193d083395SSteven Rostedt #include <linux/list.h>
203d083395SSteven Rostedt 
21395a59d0SAbhishek Sagar #include <asm/ftrace.h>
22caf4b323SFrederic Weisbecker #include <linux/ftrace.h>
23732f3ca7SSteven Rostedt #include <asm/nops.h>
24caf4b323SFrederic Weisbecker #include <asm/nmi.h>
25dfa60abaSSteven Rostedt 
263d083395SSteven Rostedt 
27caf4b323SFrederic Weisbecker 
28caf4b323SFrederic Weisbecker #ifdef CONFIG_FUNCTION_RET_TRACER
29caf4b323SFrederic Weisbecker 
30caf4b323SFrederic Weisbecker /*
31caf4b323SFrederic Weisbecker  * These functions are picked from those used on
32caf4b323SFrederic Weisbecker  * this page for dynamic ftrace. They have been
33caf4b323SFrederic Weisbecker  * simplified to ignore all traces in NMI context.
34caf4b323SFrederic Weisbecker  */
35caf4b323SFrederic Weisbecker static atomic_t in_nmi;
36caf4b323SFrederic Weisbecker 
37caf4b323SFrederic Weisbecker void ftrace_nmi_enter(void)
38caf4b323SFrederic Weisbecker {
39caf4b323SFrederic Weisbecker 	atomic_inc(&in_nmi);
40caf4b323SFrederic Weisbecker }
41caf4b323SFrederic Weisbecker 
42caf4b323SFrederic Weisbecker void ftrace_nmi_exit(void)
43caf4b323SFrederic Weisbecker {
44caf4b323SFrederic Weisbecker 	atomic_dec(&in_nmi);
45caf4b323SFrederic Weisbecker }
46caf4b323SFrederic Weisbecker 
47caf4b323SFrederic Weisbecker /* Add a function return address to the trace stack on thread info.*/
48caf4b323SFrederic Weisbecker static int push_return_trace(unsigned long ret, unsigned long long time,
49caf4b323SFrederic Weisbecker 				unsigned long func)
50caf4b323SFrederic Weisbecker {
51caf4b323SFrederic Weisbecker 	int index;
5262d59d17SFrederic Weisbecker 	struct thread_info *ti = current_thread_info();
53caf4b323SFrederic Weisbecker 
54caf4b323SFrederic Weisbecker 	/* The return trace stack is full */
5562d59d17SFrederic Weisbecker 	if (ti->curr_ret_stack == FTRACE_RET_STACK_SIZE - 1)
5662d59d17SFrederic Weisbecker 		return -EBUSY;
57caf4b323SFrederic Weisbecker 
58caf4b323SFrederic Weisbecker 	index = ++ti->curr_ret_stack;
59caf4b323SFrederic Weisbecker 	ti->ret_stack[index].ret = ret;
60caf4b323SFrederic Weisbecker 	ti->ret_stack[index].func = func;
61caf4b323SFrederic Weisbecker 	ti->ret_stack[index].calltime = time;
62caf4b323SFrederic Weisbecker 
6362d59d17SFrederic Weisbecker 	return 0;
64caf4b323SFrederic Weisbecker }
65caf4b323SFrederic Weisbecker 
66caf4b323SFrederic Weisbecker /* Retrieve a function return address to the trace stack on thread info.*/
67caf4b323SFrederic Weisbecker static void pop_return_trace(unsigned long *ret, unsigned long long *time,
68caf4b323SFrederic Weisbecker 				unsigned long *func)
69caf4b323SFrederic Weisbecker {
70caf4b323SFrederic Weisbecker 	int index;
71caf4b323SFrederic Weisbecker 
7262d59d17SFrederic Weisbecker 	struct thread_info *ti = current_thread_info();
73caf4b323SFrederic Weisbecker 	index = ti->curr_ret_stack;
74caf4b323SFrederic Weisbecker 	*ret = ti->ret_stack[index].ret;
75caf4b323SFrederic Weisbecker 	*func = ti->ret_stack[index].func;
76caf4b323SFrederic Weisbecker 	*time = ti->ret_stack[index].calltime;
77caf4b323SFrederic Weisbecker 	ti->curr_ret_stack--;
78caf4b323SFrederic Weisbecker }
79caf4b323SFrederic Weisbecker 
80caf4b323SFrederic Weisbecker /*
81caf4b323SFrederic Weisbecker  * Send the trace to the ring-buffer.
82caf4b323SFrederic Weisbecker  * @return the original return address.
83caf4b323SFrederic Weisbecker  */
84caf4b323SFrederic Weisbecker unsigned long ftrace_return_to_handler(void)
85caf4b323SFrederic Weisbecker {
86caf4b323SFrederic Weisbecker 	struct ftrace_retfunc trace;
87caf4b323SFrederic Weisbecker 	pop_return_trace(&trace.ret, &trace.calltime, &trace.func);
88caf4b323SFrederic Weisbecker 	trace.rettime = cpu_clock(raw_smp_processor_id());
89caf4b323SFrederic Weisbecker 	ftrace_function_return(&trace);
90caf4b323SFrederic Weisbecker 
91caf4b323SFrederic Weisbecker 	return trace.ret;
92caf4b323SFrederic Weisbecker }
93caf4b323SFrederic Weisbecker 
94caf4b323SFrederic Weisbecker /*
95caf4b323SFrederic Weisbecker  * Hook the return address and push it in the stack of return addrs
96caf4b323SFrederic Weisbecker  * in current thread info.
97caf4b323SFrederic Weisbecker  */
98caf4b323SFrederic Weisbecker void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
99caf4b323SFrederic Weisbecker {
100caf4b323SFrederic Weisbecker 	unsigned long old;
101caf4b323SFrederic Weisbecker 	unsigned long long calltime;
102caf4b323SFrederic Weisbecker 	int faulted;
103caf4b323SFrederic Weisbecker 	unsigned long return_hooker = (unsigned long)
104caf4b323SFrederic Weisbecker 				&return_to_handler;
105caf4b323SFrederic Weisbecker 
106caf4b323SFrederic Weisbecker 	/* Nmi's are currently unsupported */
107caf4b323SFrederic Weisbecker 	if (atomic_read(&in_nmi))
108caf4b323SFrederic Weisbecker 		return;
109caf4b323SFrederic Weisbecker 
110caf4b323SFrederic Weisbecker 	/*
111caf4b323SFrederic Weisbecker 	 * Protect against fault, even if it shouldn't
112caf4b323SFrederic Weisbecker 	 * happen. This tool is too much intrusive to
113caf4b323SFrederic Weisbecker 	 * ignore such a protection.
114caf4b323SFrederic Weisbecker 	 */
115caf4b323SFrederic Weisbecker 	asm volatile(
116caf4b323SFrederic Weisbecker 		"1: movl (%[parent_old]), %[old]\n"
117caf4b323SFrederic Weisbecker 		"2: movl %[return_hooker], (%[parent_replaced])\n"
118caf4b323SFrederic Weisbecker 		"   movl $0, %[faulted]\n"
119caf4b323SFrederic Weisbecker 
120caf4b323SFrederic Weisbecker 		".section .fixup, \"ax\"\n"
121caf4b323SFrederic Weisbecker 		"3: movl $1, %[faulted]\n"
122caf4b323SFrederic Weisbecker 		".previous\n"
123caf4b323SFrederic Weisbecker 
124caf4b323SFrederic Weisbecker 		".section __ex_table, \"a\"\n"
125caf4b323SFrederic Weisbecker 		"   .long 1b, 3b\n"
126caf4b323SFrederic Weisbecker 		"   .long 2b, 3b\n"
127caf4b323SFrederic Weisbecker 		".previous\n"
128caf4b323SFrederic Weisbecker 
129867f7fb3SIngo Molnar 		: [parent_replaced] "=r" (parent), [old] "=r" (old),
130caf4b323SFrederic Weisbecker 		  [faulted] "=r" (faulted)
131caf4b323SFrederic Weisbecker 		: [parent_old] "0" (parent), [return_hooker] "r" (return_hooker)
132caf4b323SFrederic Weisbecker 		: "memory"
133caf4b323SFrederic Weisbecker 	);
134caf4b323SFrederic Weisbecker 
135caf4b323SFrederic Weisbecker 	if (WARN_ON(faulted)) {
136caf4b323SFrederic Weisbecker 		unregister_ftrace_return();
137caf4b323SFrederic Weisbecker 		return;
138caf4b323SFrederic Weisbecker 	}
139caf4b323SFrederic Weisbecker 
140caf4b323SFrederic Weisbecker 	if (WARN_ON(!__kernel_text_address(old))) {
141caf4b323SFrederic Weisbecker 		unregister_ftrace_return();
142caf4b323SFrederic Weisbecker 		*parent = old;
143caf4b323SFrederic Weisbecker 		return;
144caf4b323SFrederic Weisbecker 	}
145caf4b323SFrederic Weisbecker 
146caf4b323SFrederic Weisbecker 	calltime = cpu_clock(raw_smp_processor_id());
147caf4b323SFrederic Weisbecker 
148caf4b323SFrederic Weisbecker 	if (push_return_trace(old, calltime, self_addr) == -EBUSY)
149caf4b323SFrederic Weisbecker 		*parent = old;
150caf4b323SFrederic Weisbecker }
151caf4b323SFrederic Weisbecker 
152caf4b323SFrederic Weisbecker #endif
153caf4b323SFrederic Weisbecker 
154caf4b323SFrederic Weisbecker #ifdef CONFIG_DYNAMIC_FTRACE
1553d083395SSteven Rostedt 
1563d083395SSteven Rostedt union ftrace_code_union {
157395a59d0SAbhishek Sagar 	char code[MCOUNT_INSN_SIZE];
1583d083395SSteven Rostedt 	struct {
1593d083395SSteven Rostedt 		char e8;
1603d083395SSteven Rostedt 		int offset;
1613d083395SSteven Rostedt 	} __attribute__((packed));
1623d083395SSteven Rostedt };
1633d083395SSteven Rostedt 
16415adc048SSteven Rostedt static int ftrace_calc_offset(long ip, long addr)
1653c1720f0SSteven Rostedt {
1663c1720f0SSteven Rostedt 	return (int)(addr - ip);
1673d083395SSteven Rostedt }
1683d083395SSteven Rostedt 
169*31e88909SSteven Rostedt static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
1703c1720f0SSteven Rostedt {
1713c1720f0SSteven Rostedt 	static union ftrace_code_union calc;
1723c1720f0SSteven Rostedt 
1733c1720f0SSteven Rostedt 	calc.e8		= 0xe8;
174395a59d0SAbhishek Sagar 	calc.offset	= ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
1753c1720f0SSteven Rostedt 
1763c1720f0SSteven Rostedt 	/*
1773c1720f0SSteven Rostedt 	 * No locking needed, this must be called via kstop_machine
1783c1720f0SSteven Rostedt 	 * which in essence is like running on a uniprocessor machine.
1793c1720f0SSteven Rostedt 	 */
1803c1720f0SSteven Rostedt 	return calc.code;
1813c1720f0SSteven Rostedt }
1823c1720f0SSteven Rostedt 
18317666f02SSteven Rostedt /*
18417666f02SSteven Rostedt  * Modifying code must take extra care. On an SMP machine, if
18517666f02SSteven Rostedt  * the code being modified is also being executed on another CPU
18617666f02SSteven Rostedt  * that CPU will have undefined results and possibly take a GPF.
18717666f02SSteven Rostedt  * We use kstop_machine to stop other CPUS from exectuing code.
18817666f02SSteven Rostedt  * But this does not stop NMIs from happening. We still need
18917666f02SSteven Rostedt  * to protect against that. We separate out the modification of
19017666f02SSteven Rostedt  * the code to take care of this.
19117666f02SSteven Rostedt  *
19217666f02SSteven Rostedt  * Two buffers are added: An IP buffer and a "code" buffer.
19317666f02SSteven Rostedt  *
194a26a2a27SSteven Rostedt  * 1) Put the instruction pointer into the IP buffer
19517666f02SSteven Rostedt  *    and the new code into the "code" buffer.
19617666f02SSteven Rostedt  * 2) Set a flag that says we are modifying code
19717666f02SSteven Rostedt  * 3) Wait for any running NMIs to finish.
19817666f02SSteven Rostedt  * 4) Write the code
19917666f02SSteven Rostedt  * 5) clear the flag.
20017666f02SSteven Rostedt  * 6) Wait for any running NMIs to finish.
20117666f02SSteven Rostedt  *
20217666f02SSteven Rostedt  * If an NMI is executed, the first thing it does is to call
20317666f02SSteven Rostedt  * "ftrace_nmi_enter". This will check if the flag is set to write
20417666f02SSteven Rostedt  * and if it is, it will write what is in the IP and "code" buffers.
20517666f02SSteven Rostedt  *
20617666f02SSteven Rostedt  * The trick is, it does not matter if everyone is writing the same
20717666f02SSteven Rostedt  * content to the code location. Also, if a CPU is executing code
20817666f02SSteven Rostedt  * it is OK to write to that code location if the contents being written
20917666f02SSteven Rostedt  * are the same as what exists.
21017666f02SSteven Rostedt  */
21117666f02SSteven Rostedt 
212a26a2a27SSteven Rostedt static atomic_t in_nmi = ATOMIC_INIT(0);
213a26a2a27SSteven Rostedt static int mod_code_status;		/* holds return value of text write */
214a26a2a27SSteven Rostedt static int mod_code_write;		/* set when NMI should do the write */
215a26a2a27SSteven Rostedt static void *mod_code_ip;		/* holds the IP to write to */
216a26a2a27SSteven Rostedt static void *mod_code_newcode;		/* holds the text to write to the IP */
21717666f02SSteven Rostedt 
218a26a2a27SSteven Rostedt static unsigned nmi_wait_count;
219a26a2a27SSteven Rostedt static atomic_t nmi_update_count = ATOMIC_INIT(0);
220b807c3d0SSteven Rostedt 
221b807c3d0SSteven Rostedt int ftrace_arch_read_dyn_info(char *buf, int size)
222b807c3d0SSteven Rostedt {
223b807c3d0SSteven Rostedt 	int r;
224b807c3d0SSteven Rostedt 
225b807c3d0SSteven Rostedt 	r = snprintf(buf, size, "%u %u",
226b807c3d0SSteven Rostedt 		     nmi_wait_count,
227b807c3d0SSteven Rostedt 		     atomic_read(&nmi_update_count));
228b807c3d0SSteven Rostedt 	return r;
229b807c3d0SSteven Rostedt }
230b807c3d0SSteven Rostedt 
23117666f02SSteven Rostedt static void ftrace_mod_code(void)
23217666f02SSteven Rostedt {
23317666f02SSteven Rostedt 	/*
23417666f02SSteven Rostedt 	 * Yes, more than one CPU process can be writing to mod_code_status.
23517666f02SSteven Rostedt 	 *    (and the code itself)
23617666f02SSteven Rostedt 	 * But if one were to fail, then they all should, and if one were
23717666f02SSteven Rostedt 	 * to succeed, then they all should.
23817666f02SSteven Rostedt 	 */
23917666f02SSteven Rostedt 	mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
24017666f02SSteven Rostedt 					     MCOUNT_INSN_SIZE);
24117666f02SSteven Rostedt 
24217666f02SSteven Rostedt }
24317666f02SSteven Rostedt 
24417666f02SSteven Rostedt void ftrace_nmi_enter(void)
24517666f02SSteven Rostedt {
24617666f02SSteven Rostedt 	atomic_inc(&in_nmi);
24717666f02SSteven Rostedt 	/* Must have in_nmi seen before reading write flag */
24817666f02SSteven Rostedt 	smp_mb();
249b807c3d0SSteven Rostedt 	if (mod_code_write) {
25017666f02SSteven Rostedt 		ftrace_mod_code();
251b807c3d0SSteven Rostedt 		atomic_inc(&nmi_update_count);
252b807c3d0SSteven Rostedt 	}
25317666f02SSteven Rostedt }
25417666f02SSteven Rostedt 
25517666f02SSteven Rostedt void ftrace_nmi_exit(void)
25617666f02SSteven Rostedt {
25717666f02SSteven Rostedt 	/* Finish all executions before clearing in_nmi */
25817666f02SSteven Rostedt 	smp_wmb();
25917666f02SSteven Rostedt 	atomic_dec(&in_nmi);
26017666f02SSteven Rostedt }
26117666f02SSteven Rostedt 
26217666f02SSteven Rostedt static void wait_for_nmi(void)
26317666f02SSteven Rostedt {
264b807c3d0SSteven Rostedt 	int waited = 0;
265b807c3d0SSteven Rostedt 
266b807c3d0SSteven Rostedt 	while (atomic_read(&in_nmi)) {
267b807c3d0SSteven Rostedt 		waited = 1;
26817666f02SSteven Rostedt 		cpu_relax();
26917666f02SSteven Rostedt 	}
27017666f02SSteven Rostedt 
271b807c3d0SSteven Rostedt 	if (waited)
272b807c3d0SSteven Rostedt 		nmi_wait_count++;
273b807c3d0SSteven Rostedt }
274b807c3d0SSteven Rostedt 
27517666f02SSteven Rostedt static int
27617666f02SSteven Rostedt do_ftrace_mod_code(unsigned long ip, void *new_code)
27717666f02SSteven Rostedt {
27817666f02SSteven Rostedt 	mod_code_ip = (void *)ip;
27917666f02SSteven Rostedt 	mod_code_newcode = new_code;
28017666f02SSteven Rostedt 
28117666f02SSteven Rostedt 	/* The buffers need to be visible before we let NMIs write them */
28217666f02SSteven Rostedt 	smp_wmb();
28317666f02SSteven Rostedt 
28417666f02SSteven Rostedt 	mod_code_write = 1;
28517666f02SSteven Rostedt 
28617666f02SSteven Rostedt 	/* Make sure write bit is visible before we wait on NMIs */
28717666f02SSteven Rostedt 	smp_mb();
28817666f02SSteven Rostedt 
28917666f02SSteven Rostedt 	wait_for_nmi();
29017666f02SSteven Rostedt 
29117666f02SSteven Rostedt 	/* Make sure all running NMIs have finished before we write the code */
29217666f02SSteven Rostedt 	smp_mb();
29317666f02SSteven Rostedt 
29417666f02SSteven Rostedt 	ftrace_mod_code();
29517666f02SSteven Rostedt 
29617666f02SSteven Rostedt 	/* Make sure the write happens before clearing the bit */
29717666f02SSteven Rostedt 	smp_wmb();
29817666f02SSteven Rostedt 
29917666f02SSteven Rostedt 	mod_code_write = 0;
30017666f02SSteven Rostedt 
30117666f02SSteven Rostedt 	/* make sure NMIs see the cleared bit */
30217666f02SSteven Rostedt 	smp_mb();
30317666f02SSteven Rostedt 
30417666f02SSteven Rostedt 	wait_for_nmi();
30517666f02SSteven Rostedt 
30617666f02SSteven Rostedt 	return mod_code_status;
30717666f02SSteven Rostedt }
30817666f02SSteven Rostedt 
30917666f02SSteven Rostedt 
310caf4b323SFrederic Weisbecker 
311caf4b323SFrederic Weisbecker 
312caf4b323SFrederic Weisbecker static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
313caf4b323SFrederic Weisbecker 
314*31e88909SSteven Rostedt static unsigned char *ftrace_nop_replace(void)
315caf4b323SFrederic Weisbecker {
316caf4b323SFrederic Weisbecker 	return ftrace_nop;
317caf4b323SFrederic Weisbecker }
318caf4b323SFrederic Weisbecker 
319*31e88909SSteven Rostedt static int
3203d083395SSteven Rostedt ftrace_modify_code(unsigned long ip, unsigned char *old_code,
3213d083395SSteven Rostedt 		   unsigned char *new_code)
3223d083395SSteven Rostedt {
3236f93fc07SSteven Rostedt 	unsigned char replaced[MCOUNT_INSN_SIZE];
3243d083395SSteven Rostedt 
3253d083395SSteven Rostedt 	/*
3263d083395SSteven Rostedt 	 * Note: Due to modules and __init, code can
3273d083395SSteven Rostedt 	 *  disappear and change, we need to protect against faulting
32876aefee5SSteven Rostedt 	 *  as well as code changing. We do this by using the
329ab9a0918SSteven Rostedt 	 *  probe_kernel_* functions.
3303d083395SSteven Rostedt 	 *
3313d083395SSteven Rostedt 	 * No real locking needed, this code is run through
3326f93fc07SSteven Rostedt 	 * kstop_machine, or before SMP starts.
3333d083395SSteven Rostedt 	 */
33476aefee5SSteven Rostedt 
33576aefee5SSteven Rostedt 	/* read the text we want to modify */
336ab9a0918SSteven Rostedt 	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
337593eb8a2SSteven Rostedt 		return -EFAULT;
3386f93fc07SSteven Rostedt 
33976aefee5SSteven Rostedt 	/* Make sure it is what we expect it to be */
3406f93fc07SSteven Rostedt 	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
341593eb8a2SSteven Rostedt 		return -EINVAL;
3426f93fc07SSteven Rostedt 
34376aefee5SSteven Rostedt 	/* replace the text with the new text */
34417666f02SSteven Rostedt 	if (do_ftrace_mod_code(ip, new_code))
345593eb8a2SSteven Rostedt 		return -EPERM;
3466f93fc07SSteven Rostedt 
3473d083395SSteven Rostedt 	sync_core();
3483d083395SSteven Rostedt 
3496f93fc07SSteven Rostedt 	return 0;
3503d083395SSteven Rostedt }
3513d083395SSteven Rostedt 
352*31e88909SSteven Rostedt int ftrace_make_nop(struct module *mod,
353*31e88909SSteven Rostedt 		    struct dyn_ftrace *rec, unsigned long addr)
354*31e88909SSteven Rostedt {
355*31e88909SSteven Rostedt 	unsigned char *new, *old;
356*31e88909SSteven Rostedt 	unsigned long ip = rec->ip;
357*31e88909SSteven Rostedt 
358*31e88909SSteven Rostedt 	old = ftrace_call_replace(ip, addr);
359*31e88909SSteven Rostedt 	new = ftrace_nop_replace();
360*31e88909SSteven Rostedt 
361*31e88909SSteven Rostedt 	return ftrace_modify_code(rec->ip, old, new);
362*31e88909SSteven Rostedt }
363*31e88909SSteven Rostedt 
364*31e88909SSteven Rostedt int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
365*31e88909SSteven Rostedt {
366*31e88909SSteven Rostedt 	unsigned char *new, *old;
367*31e88909SSteven Rostedt 	unsigned long ip = rec->ip;
368*31e88909SSteven Rostedt 
369*31e88909SSteven Rostedt 	old = ftrace_nop_replace();
370*31e88909SSteven Rostedt 	new = ftrace_call_replace(ip, addr);
371*31e88909SSteven Rostedt 
372*31e88909SSteven Rostedt 	return ftrace_modify_code(rec->ip, old, new);
373*31e88909SSteven Rostedt }
374*31e88909SSteven Rostedt 
37515adc048SSteven Rostedt int ftrace_update_ftrace_func(ftrace_func_t func)
376d61f82d0SSteven Rostedt {
377d61f82d0SSteven Rostedt 	unsigned long ip = (unsigned long)(&ftrace_call);
378395a59d0SAbhishek Sagar 	unsigned char old[MCOUNT_INSN_SIZE], *new;
379d61f82d0SSteven Rostedt 	int ret;
380d61f82d0SSteven Rostedt 
381395a59d0SAbhishek Sagar 	memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
382d61f82d0SSteven Rostedt 	new = ftrace_call_replace(ip, (unsigned long)func);
383d61f82d0SSteven Rostedt 	ret = ftrace_modify_code(ip, old, new);
384d61f82d0SSteven Rostedt 
385d61f82d0SSteven Rostedt 	return ret;
386d61f82d0SSteven Rostedt }
387d61f82d0SSteven Rostedt 
388d61f82d0SSteven Rostedt int __init ftrace_dyn_arch_init(void *data)
3893d083395SSteven Rostedt {
390732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_p6nop[];
391732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_nop5[];
392732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_jmp[];
393732f3ca7SSteven Rostedt 	int faulted = 0;
3943d083395SSteven Rostedt 
395732f3ca7SSteven Rostedt 	/*
396732f3ca7SSteven Rostedt 	 * There is no good nop for all x86 archs.
397732f3ca7SSteven Rostedt 	 * We will default to using the P6_NOP5, but first we
398732f3ca7SSteven Rostedt 	 * will test to make sure that the nop will actually
399732f3ca7SSteven Rostedt 	 * work on this CPU. If it faults, we will then
400732f3ca7SSteven Rostedt 	 * go to a lesser efficient 5 byte nop. If that fails
401732f3ca7SSteven Rostedt 	 * we then just use a jmp as our nop. This isn't the most
402732f3ca7SSteven Rostedt 	 * efficient nop, but we can not use a multi part nop
403732f3ca7SSteven Rostedt 	 * since we would then risk being preempted in the middle
404732f3ca7SSteven Rostedt 	 * of that nop, and if we enabled tracing then, it might
405732f3ca7SSteven Rostedt 	 * cause a system crash.
406732f3ca7SSteven Rostedt 	 *
407732f3ca7SSteven Rostedt 	 * TODO: check the cpuid to determine the best nop.
408732f3ca7SSteven Rostedt 	 */
409732f3ca7SSteven Rostedt 	asm volatile (
410732f3ca7SSteven Rostedt 		"ftrace_test_jmp:"
411732f3ca7SSteven Rostedt 		"jmp ftrace_test_p6nop\n"
4128b27386aSAnders Kaseorg 		"nop\n"
4138b27386aSAnders Kaseorg 		"nop\n"
4148b27386aSAnders Kaseorg 		"nop\n"  /* 2 byte jmp + 3 bytes */
415732f3ca7SSteven Rostedt 		"ftrace_test_p6nop:"
416732f3ca7SSteven Rostedt 		P6_NOP5
417732f3ca7SSteven Rostedt 		"jmp 1f\n"
418732f3ca7SSteven Rostedt 		"ftrace_test_nop5:"
419732f3ca7SSteven Rostedt 		".byte 0x66,0x66,0x66,0x66,0x90\n"
420732f3ca7SSteven Rostedt 		"1:"
421732f3ca7SSteven Rostedt 		".section .fixup, \"ax\"\n"
422732f3ca7SSteven Rostedt 		"2:	movl $1, %0\n"
423732f3ca7SSteven Rostedt 		"	jmp ftrace_test_nop5\n"
424732f3ca7SSteven Rostedt 		"3:	movl $2, %0\n"
425732f3ca7SSteven Rostedt 		"	jmp 1b\n"
426732f3ca7SSteven Rostedt 		".previous\n"
427732f3ca7SSteven Rostedt 		_ASM_EXTABLE(ftrace_test_p6nop, 2b)
428732f3ca7SSteven Rostedt 		_ASM_EXTABLE(ftrace_test_nop5, 3b)
429732f3ca7SSteven Rostedt 		: "=r"(faulted) : "0" (faulted));
430d61f82d0SSteven Rostedt 
431732f3ca7SSteven Rostedt 	switch (faulted) {
432732f3ca7SSteven Rostedt 	case 0:
433732f3ca7SSteven Rostedt 		pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n");
4348115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
435732f3ca7SSteven Rostedt 		break;
436732f3ca7SSteven Rostedt 	case 1:
437732f3ca7SSteven Rostedt 		pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n");
4388115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
439732f3ca7SSteven Rostedt 		break;
440732f3ca7SSteven Rostedt 	case 2:
4418b27386aSAnders Kaseorg 		pr_info("ftrace: converting mcount calls to jmp . + 5\n");
4428115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
443732f3ca7SSteven Rostedt 		break;
444732f3ca7SSteven Rostedt 	}
445d61f82d0SSteven Rostedt 
446732f3ca7SSteven Rostedt 	/* The return code is retured via data */
447732f3ca7SSteven Rostedt 	*(unsigned long *)data = 0;
448dfa60abaSSteven Rostedt 
4493d083395SSteven Rostedt 	return 0;
4503d083395SSteven Rostedt }
451caf4b323SFrederic Weisbecker #endif
452