xref: /openbmc/linux/arch/x86/kernel/ftrace.c (revision 19b3e9671c5a219b8c34da2cc66e0ce7c3a501ae)
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>
17*19b3e967SIngo 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 /*
48caf4b323SFrederic Weisbecker  * Synchronize accesses to return adresses stack with
49caf4b323SFrederic Weisbecker  * interrupts.
50caf4b323SFrederic Weisbecker  */
51caf4b323SFrederic Weisbecker static raw_spinlock_t ret_stack_lock;
52caf4b323SFrederic Weisbecker 
53caf4b323SFrederic Weisbecker /* Add a function return address to the trace stack on thread info.*/
54caf4b323SFrederic Weisbecker static int push_return_trace(unsigned long ret, unsigned long long time,
55caf4b323SFrederic Weisbecker 				unsigned long func)
56caf4b323SFrederic Weisbecker {
57caf4b323SFrederic Weisbecker 	int index;
58caf4b323SFrederic Weisbecker 	struct thread_info *ti;
59caf4b323SFrederic Weisbecker 	unsigned long flags;
60caf4b323SFrederic Weisbecker 	int err = 0;
61caf4b323SFrederic Weisbecker 
62caf4b323SFrederic Weisbecker 	raw_local_irq_save(flags);
63caf4b323SFrederic Weisbecker 	__raw_spin_lock(&ret_stack_lock);
64caf4b323SFrederic Weisbecker 
65caf4b323SFrederic Weisbecker 	ti = current_thread_info();
66caf4b323SFrederic Weisbecker 	/* The return trace stack is full */
67caf4b323SFrederic Weisbecker 	if (ti->curr_ret_stack == FTRACE_RET_STACK_SIZE - 1) {
68caf4b323SFrederic Weisbecker 		err = -EBUSY;
69caf4b323SFrederic Weisbecker 		goto out;
70caf4b323SFrederic Weisbecker 	}
71caf4b323SFrederic Weisbecker 
72caf4b323SFrederic Weisbecker 	index = ++ti->curr_ret_stack;
73caf4b323SFrederic Weisbecker 	ti->ret_stack[index].ret = ret;
74caf4b323SFrederic Weisbecker 	ti->ret_stack[index].func = func;
75caf4b323SFrederic Weisbecker 	ti->ret_stack[index].calltime = time;
76caf4b323SFrederic Weisbecker 
77caf4b323SFrederic Weisbecker out:
78caf4b323SFrederic Weisbecker 	__raw_spin_unlock(&ret_stack_lock);
79caf4b323SFrederic Weisbecker 	raw_local_irq_restore(flags);
80caf4b323SFrederic Weisbecker 	return err;
81caf4b323SFrederic Weisbecker }
82caf4b323SFrederic Weisbecker 
83caf4b323SFrederic Weisbecker /* Retrieve a function return address to the trace stack on thread info.*/
84caf4b323SFrederic Weisbecker static void pop_return_trace(unsigned long *ret, unsigned long long *time,
85caf4b323SFrederic Weisbecker 				unsigned long *func)
86caf4b323SFrederic Weisbecker {
87caf4b323SFrederic Weisbecker 	struct thread_info *ti;
88caf4b323SFrederic Weisbecker 	int index;
89caf4b323SFrederic Weisbecker 	unsigned long flags;
90caf4b323SFrederic Weisbecker 
91caf4b323SFrederic Weisbecker 	raw_local_irq_save(flags);
92caf4b323SFrederic Weisbecker 	__raw_spin_lock(&ret_stack_lock);
93caf4b323SFrederic Weisbecker 
94caf4b323SFrederic Weisbecker 	ti = current_thread_info();
95caf4b323SFrederic Weisbecker 	index = ti->curr_ret_stack;
96caf4b323SFrederic Weisbecker 	*ret = ti->ret_stack[index].ret;
97caf4b323SFrederic Weisbecker 	*func = ti->ret_stack[index].func;
98caf4b323SFrederic Weisbecker 	*time = ti->ret_stack[index].calltime;
99caf4b323SFrederic Weisbecker 	ti->curr_ret_stack--;
100caf4b323SFrederic Weisbecker 
101caf4b323SFrederic Weisbecker 	__raw_spin_unlock(&ret_stack_lock);
102caf4b323SFrederic Weisbecker 	raw_local_irq_restore(flags);
103caf4b323SFrederic Weisbecker }
104caf4b323SFrederic Weisbecker 
105caf4b323SFrederic Weisbecker /*
106caf4b323SFrederic Weisbecker  * Send the trace to the ring-buffer.
107caf4b323SFrederic Weisbecker  * @return the original return address.
108caf4b323SFrederic Weisbecker  */
109caf4b323SFrederic Weisbecker unsigned long ftrace_return_to_handler(void)
110caf4b323SFrederic Weisbecker {
111caf4b323SFrederic Weisbecker 	struct ftrace_retfunc trace;
112caf4b323SFrederic Weisbecker 	pop_return_trace(&trace.ret, &trace.calltime, &trace.func);
113caf4b323SFrederic Weisbecker 	trace.rettime = cpu_clock(raw_smp_processor_id());
114caf4b323SFrederic Weisbecker 	ftrace_function_return(&trace);
115caf4b323SFrederic Weisbecker 
116caf4b323SFrederic Weisbecker 	return trace.ret;
117caf4b323SFrederic Weisbecker }
118caf4b323SFrederic Weisbecker 
119caf4b323SFrederic Weisbecker /*
120caf4b323SFrederic Weisbecker  * Hook the return address and push it in the stack of return addrs
121caf4b323SFrederic Weisbecker  * in current thread info.
122caf4b323SFrederic Weisbecker  */
123caf4b323SFrederic Weisbecker asmlinkage
124caf4b323SFrederic Weisbecker void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
125caf4b323SFrederic Weisbecker {
126caf4b323SFrederic Weisbecker 	unsigned long old;
127caf4b323SFrederic Weisbecker 	unsigned long long calltime;
128caf4b323SFrederic Weisbecker 	int faulted;
129caf4b323SFrederic Weisbecker 	unsigned long return_hooker = (unsigned long)
130caf4b323SFrederic Weisbecker 				&return_to_handler;
131caf4b323SFrederic Weisbecker 
132caf4b323SFrederic Weisbecker 	/* Nmi's are currently unsupported */
133caf4b323SFrederic Weisbecker 	if (atomic_read(&in_nmi))
134caf4b323SFrederic Weisbecker 		return;
135caf4b323SFrederic Weisbecker 
136caf4b323SFrederic Weisbecker 	/*
137caf4b323SFrederic Weisbecker 	 * Protect against fault, even if it shouldn't
138caf4b323SFrederic Weisbecker 	 * happen. This tool is too much intrusive to
139caf4b323SFrederic Weisbecker 	 * ignore such a protection.
140caf4b323SFrederic Weisbecker 	 */
141caf4b323SFrederic Weisbecker 	asm volatile(
142caf4b323SFrederic Weisbecker 		"1: movl (%[parent_old]), %[old]\n"
143caf4b323SFrederic Weisbecker 		"2: movl %[return_hooker], (%[parent_replaced])\n"
144caf4b323SFrederic Weisbecker 		"   movl $0, %[faulted]\n"
145caf4b323SFrederic Weisbecker 
146caf4b323SFrederic Weisbecker 		".section .fixup, \"ax\"\n"
147caf4b323SFrederic Weisbecker 		"3: movl $1, %[faulted]\n"
148caf4b323SFrederic Weisbecker 		".previous\n"
149caf4b323SFrederic Weisbecker 
150caf4b323SFrederic Weisbecker 		".section __ex_table, \"a\"\n"
151caf4b323SFrederic Weisbecker 		"   .long 1b, 3b\n"
152caf4b323SFrederic Weisbecker 		"   .long 2b, 3b\n"
153caf4b323SFrederic Weisbecker 		".previous\n"
154caf4b323SFrederic Weisbecker 
155867f7fb3SIngo Molnar 		: [parent_replaced] "=r" (parent), [old] "=r" (old),
156caf4b323SFrederic Weisbecker 		  [faulted] "=r" (faulted)
157caf4b323SFrederic Weisbecker 		: [parent_old] "0" (parent), [return_hooker] "r" (return_hooker)
158caf4b323SFrederic Weisbecker 		: "memory"
159caf4b323SFrederic Weisbecker 	);
160caf4b323SFrederic Weisbecker 
161caf4b323SFrederic Weisbecker 	if (WARN_ON(faulted)) {
162caf4b323SFrederic Weisbecker 		unregister_ftrace_return();
163caf4b323SFrederic Weisbecker 		return;
164caf4b323SFrederic Weisbecker 	}
165caf4b323SFrederic Weisbecker 
166caf4b323SFrederic Weisbecker 	if (WARN_ON(!__kernel_text_address(old))) {
167caf4b323SFrederic Weisbecker 		unregister_ftrace_return();
168caf4b323SFrederic Weisbecker 		*parent = old;
169caf4b323SFrederic Weisbecker 		return;
170caf4b323SFrederic Weisbecker 	}
171caf4b323SFrederic Weisbecker 
172caf4b323SFrederic Weisbecker 	calltime = cpu_clock(raw_smp_processor_id());
173caf4b323SFrederic Weisbecker 
174caf4b323SFrederic Weisbecker 	if (push_return_trace(old, calltime, self_addr) == -EBUSY)
175caf4b323SFrederic Weisbecker 		*parent = old;
176caf4b323SFrederic Weisbecker }
177caf4b323SFrederic Weisbecker 
178caf4b323SFrederic Weisbecker static int __init init_ftrace_function_return(void)
179caf4b323SFrederic Weisbecker {
180caf4b323SFrederic Weisbecker 	ret_stack_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
181caf4b323SFrederic Weisbecker 	return 0;
182caf4b323SFrederic Weisbecker }
183caf4b323SFrederic Weisbecker device_initcall(init_ftrace_function_return);
184caf4b323SFrederic Weisbecker 
185caf4b323SFrederic Weisbecker 
186caf4b323SFrederic Weisbecker #endif
187caf4b323SFrederic Weisbecker 
188caf4b323SFrederic Weisbecker #ifdef CONFIG_DYNAMIC_FTRACE
1893d083395SSteven Rostedt 
1903d083395SSteven Rostedt union ftrace_code_union {
191395a59d0SAbhishek Sagar 	char code[MCOUNT_INSN_SIZE];
1923d083395SSteven Rostedt 	struct {
1933d083395SSteven Rostedt 		char e8;
1943d083395SSteven Rostedt 		int offset;
1953d083395SSteven Rostedt 	} __attribute__((packed));
1963d083395SSteven Rostedt };
1973d083395SSteven Rostedt 
19815adc048SSteven Rostedt static int ftrace_calc_offset(long ip, long addr)
1993c1720f0SSteven Rostedt {
2003c1720f0SSteven Rostedt 	return (int)(addr - ip);
2013d083395SSteven Rostedt }
2023d083395SSteven Rostedt 
20315adc048SSteven Rostedt unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
2043c1720f0SSteven Rostedt {
2053c1720f0SSteven Rostedt 	static union ftrace_code_union calc;
2063c1720f0SSteven Rostedt 
2073c1720f0SSteven Rostedt 	calc.e8		= 0xe8;
208395a59d0SAbhishek Sagar 	calc.offset	= ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
2093c1720f0SSteven Rostedt 
2103c1720f0SSteven Rostedt 	/*
2113c1720f0SSteven Rostedt 	 * No locking needed, this must be called via kstop_machine
2123c1720f0SSteven Rostedt 	 * which in essence is like running on a uniprocessor machine.
2133c1720f0SSteven Rostedt 	 */
2143c1720f0SSteven Rostedt 	return calc.code;
2153c1720f0SSteven Rostedt }
2163c1720f0SSteven Rostedt 
21717666f02SSteven Rostedt /*
21817666f02SSteven Rostedt  * Modifying code must take extra care. On an SMP machine, if
21917666f02SSteven Rostedt  * the code being modified is also being executed on another CPU
22017666f02SSteven Rostedt  * that CPU will have undefined results and possibly take a GPF.
22117666f02SSteven Rostedt  * We use kstop_machine to stop other CPUS from exectuing code.
22217666f02SSteven Rostedt  * But this does not stop NMIs from happening. We still need
22317666f02SSteven Rostedt  * to protect against that. We separate out the modification of
22417666f02SSteven Rostedt  * the code to take care of this.
22517666f02SSteven Rostedt  *
22617666f02SSteven Rostedt  * Two buffers are added: An IP buffer and a "code" buffer.
22717666f02SSteven Rostedt  *
228a26a2a27SSteven Rostedt  * 1) Put the instruction pointer into the IP buffer
22917666f02SSteven Rostedt  *    and the new code into the "code" buffer.
23017666f02SSteven Rostedt  * 2) Set a flag that says we are modifying code
23117666f02SSteven Rostedt  * 3) Wait for any running NMIs to finish.
23217666f02SSteven Rostedt  * 4) Write the code
23317666f02SSteven Rostedt  * 5) clear the flag.
23417666f02SSteven Rostedt  * 6) Wait for any running NMIs to finish.
23517666f02SSteven Rostedt  *
23617666f02SSteven Rostedt  * If an NMI is executed, the first thing it does is to call
23717666f02SSteven Rostedt  * "ftrace_nmi_enter". This will check if the flag is set to write
23817666f02SSteven Rostedt  * and if it is, it will write what is in the IP and "code" buffers.
23917666f02SSteven Rostedt  *
24017666f02SSteven Rostedt  * The trick is, it does not matter if everyone is writing the same
24117666f02SSteven Rostedt  * content to the code location. Also, if a CPU is executing code
24217666f02SSteven Rostedt  * it is OK to write to that code location if the contents being written
24317666f02SSteven Rostedt  * are the same as what exists.
24417666f02SSteven Rostedt  */
24517666f02SSteven Rostedt 
246a26a2a27SSteven Rostedt static atomic_t in_nmi = ATOMIC_INIT(0);
247a26a2a27SSteven Rostedt static int mod_code_status;		/* holds return value of text write */
248a26a2a27SSteven Rostedt static int mod_code_write;		/* set when NMI should do the write */
249a26a2a27SSteven Rostedt static void *mod_code_ip;		/* holds the IP to write to */
250a26a2a27SSteven Rostedt static void *mod_code_newcode;		/* holds the text to write to the IP */
25117666f02SSteven Rostedt 
252a26a2a27SSteven Rostedt static unsigned nmi_wait_count;
253a26a2a27SSteven Rostedt static atomic_t nmi_update_count = ATOMIC_INIT(0);
254b807c3d0SSteven Rostedt 
255b807c3d0SSteven Rostedt int ftrace_arch_read_dyn_info(char *buf, int size)
256b807c3d0SSteven Rostedt {
257b807c3d0SSteven Rostedt 	int r;
258b807c3d0SSteven Rostedt 
259b807c3d0SSteven Rostedt 	r = snprintf(buf, size, "%u %u",
260b807c3d0SSteven Rostedt 		     nmi_wait_count,
261b807c3d0SSteven Rostedt 		     atomic_read(&nmi_update_count));
262b807c3d0SSteven Rostedt 	return r;
263b807c3d0SSteven Rostedt }
264b807c3d0SSteven Rostedt 
26517666f02SSteven Rostedt static void ftrace_mod_code(void)
26617666f02SSteven Rostedt {
26717666f02SSteven Rostedt 	/*
26817666f02SSteven Rostedt 	 * Yes, more than one CPU process can be writing to mod_code_status.
26917666f02SSteven Rostedt 	 *    (and the code itself)
27017666f02SSteven Rostedt 	 * But if one were to fail, then they all should, and if one were
27117666f02SSteven Rostedt 	 * to succeed, then they all should.
27217666f02SSteven Rostedt 	 */
27317666f02SSteven Rostedt 	mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
27417666f02SSteven Rostedt 					     MCOUNT_INSN_SIZE);
27517666f02SSteven Rostedt 
27617666f02SSteven Rostedt }
27717666f02SSteven Rostedt 
27817666f02SSteven Rostedt void ftrace_nmi_enter(void)
27917666f02SSteven Rostedt {
28017666f02SSteven Rostedt 	atomic_inc(&in_nmi);
28117666f02SSteven Rostedt 	/* Must have in_nmi seen before reading write flag */
28217666f02SSteven Rostedt 	smp_mb();
283b807c3d0SSteven Rostedt 	if (mod_code_write) {
28417666f02SSteven Rostedt 		ftrace_mod_code();
285b807c3d0SSteven Rostedt 		atomic_inc(&nmi_update_count);
286b807c3d0SSteven Rostedt 	}
28717666f02SSteven Rostedt }
28817666f02SSteven Rostedt 
28917666f02SSteven Rostedt void ftrace_nmi_exit(void)
29017666f02SSteven Rostedt {
29117666f02SSteven Rostedt 	/* Finish all executions before clearing in_nmi */
29217666f02SSteven Rostedt 	smp_wmb();
29317666f02SSteven Rostedt 	atomic_dec(&in_nmi);
29417666f02SSteven Rostedt }
29517666f02SSteven Rostedt 
29617666f02SSteven Rostedt static void wait_for_nmi(void)
29717666f02SSteven Rostedt {
298b807c3d0SSteven Rostedt 	int waited = 0;
299b807c3d0SSteven Rostedt 
300b807c3d0SSteven Rostedt 	while (atomic_read(&in_nmi)) {
301b807c3d0SSteven Rostedt 		waited = 1;
30217666f02SSteven Rostedt 		cpu_relax();
30317666f02SSteven Rostedt 	}
30417666f02SSteven Rostedt 
305b807c3d0SSteven Rostedt 	if (waited)
306b807c3d0SSteven Rostedt 		nmi_wait_count++;
307b807c3d0SSteven Rostedt }
308b807c3d0SSteven Rostedt 
30917666f02SSteven Rostedt static int
31017666f02SSteven Rostedt do_ftrace_mod_code(unsigned long ip, void *new_code)
31117666f02SSteven Rostedt {
31217666f02SSteven Rostedt 	mod_code_ip = (void *)ip;
31317666f02SSteven Rostedt 	mod_code_newcode = new_code;
31417666f02SSteven Rostedt 
31517666f02SSteven Rostedt 	/* The buffers need to be visible before we let NMIs write them */
31617666f02SSteven Rostedt 	smp_wmb();
31717666f02SSteven Rostedt 
31817666f02SSteven Rostedt 	mod_code_write = 1;
31917666f02SSteven Rostedt 
32017666f02SSteven Rostedt 	/* Make sure write bit is visible before we wait on NMIs */
32117666f02SSteven Rostedt 	smp_mb();
32217666f02SSteven Rostedt 
32317666f02SSteven Rostedt 	wait_for_nmi();
32417666f02SSteven Rostedt 
32517666f02SSteven Rostedt 	/* Make sure all running NMIs have finished before we write the code */
32617666f02SSteven Rostedt 	smp_mb();
32717666f02SSteven Rostedt 
32817666f02SSteven Rostedt 	ftrace_mod_code();
32917666f02SSteven Rostedt 
33017666f02SSteven Rostedt 	/* Make sure the write happens before clearing the bit */
33117666f02SSteven Rostedt 	smp_wmb();
33217666f02SSteven Rostedt 
33317666f02SSteven Rostedt 	mod_code_write = 0;
33417666f02SSteven Rostedt 
33517666f02SSteven Rostedt 	/* make sure NMIs see the cleared bit */
33617666f02SSteven Rostedt 	smp_mb();
33717666f02SSteven Rostedt 
33817666f02SSteven Rostedt 	wait_for_nmi();
33917666f02SSteven Rostedt 
34017666f02SSteven Rostedt 	return mod_code_status;
34117666f02SSteven Rostedt }
34217666f02SSteven Rostedt 
34317666f02SSteven Rostedt 
344caf4b323SFrederic Weisbecker 
345caf4b323SFrederic Weisbecker 
346caf4b323SFrederic Weisbecker static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
347caf4b323SFrederic Weisbecker 
348caf4b323SFrederic Weisbecker unsigned char *ftrace_nop_replace(void)
349caf4b323SFrederic Weisbecker {
350caf4b323SFrederic Weisbecker 	return ftrace_nop;
351caf4b323SFrederic Weisbecker }
352caf4b323SFrederic Weisbecker 
35315adc048SSteven Rostedt int
3543d083395SSteven Rostedt ftrace_modify_code(unsigned long ip, unsigned char *old_code,
3553d083395SSteven Rostedt 		   unsigned char *new_code)
3563d083395SSteven Rostedt {
3576f93fc07SSteven Rostedt 	unsigned char replaced[MCOUNT_INSN_SIZE];
3583d083395SSteven Rostedt 
3593d083395SSteven Rostedt 	/*
3603d083395SSteven Rostedt 	 * Note: Due to modules and __init, code can
3613d083395SSteven Rostedt 	 *  disappear and change, we need to protect against faulting
36276aefee5SSteven Rostedt 	 *  as well as code changing. We do this by using the
363ab9a0918SSteven Rostedt 	 *  probe_kernel_* functions.
3643d083395SSteven Rostedt 	 *
3653d083395SSteven Rostedt 	 * No real locking needed, this code is run through
3666f93fc07SSteven Rostedt 	 * kstop_machine, or before SMP starts.
3673d083395SSteven Rostedt 	 */
36876aefee5SSteven Rostedt 
36976aefee5SSteven Rostedt 	/* read the text we want to modify */
370ab9a0918SSteven Rostedt 	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
371593eb8a2SSteven Rostedt 		return -EFAULT;
3726f93fc07SSteven Rostedt 
37376aefee5SSteven Rostedt 	/* Make sure it is what we expect it to be */
3746f93fc07SSteven Rostedt 	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
375593eb8a2SSteven Rostedt 		return -EINVAL;
3766f93fc07SSteven Rostedt 
37776aefee5SSteven Rostedt 	/* replace the text with the new text */
37817666f02SSteven Rostedt 	if (do_ftrace_mod_code(ip, new_code))
379593eb8a2SSteven Rostedt 		return -EPERM;
3806f93fc07SSteven Rostedt 
3813d083395SSteven Rostedt 	sync_core();
3823d083395SSteven Rostedt 
3836f93fc07SSteven Rostedt 	return 0;
3843d083395SSteven Rostedt }
3853d083395SSteven Rostedt 
38615adc048SSteven Rostedt int ftrace_update_ftrace_func(ftrace_func_t func)
387d61f82d0SSteven Rostedt {
388d61f82d0SSteven Rostedt 	unsigned long ip = (unsigned long)(&ftrace_call);
389395a59d0SAbhishek Sagar 	unsigned char old[MCOUNT_INSN_SIZE], *new;
390d61f82d0SSteven Rostedt 	int ret;
391d61f82d0SSteven Rostedt 
392395a59d0SAbhishek Sagar 	memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
393d61f82d0SSteven Rostedt 	new = ftrace_call_replace(ip, (unsigned long)func);
394d61f82d0SSteven Rostedt 	ret = ftrace_modify_code(ip, old, new);
395d61f82d0SSteven Rostedt 
396d61f82d0SSteven Rostedt 	return ret;
397d61f82d0SSteven Rostedt }
398d61f82d0SSteven Rostedt 
399d61f82d0SSteven Rostedt int __init ftrace_dyn_arch_init(void *data)
4003d083395SSteven Rostedt {
401732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_p6nop[];
402732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_nop5[];
403732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_jmp[];
404732f3ca7SSteven Rostedt 	int faulted = 0;
4053d083395SSteven Rostedt 
406732f3ca7SSteven Rostedt 	/*
407732f3ca7SSteven Rostedt 	 * There is no good nop for all x86 archs.
408732f3ca7SSteven Rostedt 	 * We will default to using the P6_NOP5, but first we
409732f3ca7SSteven Rostedt 	 * will test to make sure that the nop will actually
410732f3ca7SSteven Rostedt 	 * work on this CPU. If it faults, we will then
411732f3ca7SSteven Rostedt 	 * go to a lesser efficient 5 byte nop. If that fails
412732f3ca7SSteven Rostedt 	 * we then just use a jmp as our nop. This isn't the most
413732f3ca7SSteven Rostedt 	 * efficient nop, but we can not use a multi part nop
414732f3ca7SSteven Rostedt 	 * since we would then risk being preempted in the middle
415732f3ca7SSteven Rostedt 	 * of that nop, and if we enabled tracing then, it might
416732f3ca7SSteven Rostedt 	 * cause a system crash.
417732f3ca7SSteven Rostedt 	 *
418732f3ca7SSteven Rostedt 	 * TODO: check the cpuid to determine the best nop.
419732f3ca7SSteven Rostedt 	 */
420732f3ca7SSteven Rostedt 	asm volatile (
421732f3ca7SSteven Rostedt 		"ftrace_test_jmp:"
422732f3ca7SSteven Rostedt 		"jmp ftrace_test_p6nop\n"
4238b27386aSAnders Kaseorg 		"nop\n"
4248b27386aSAnders Kaseorg 		"nop\n"
4258b27386aSAnders Kaseorg 		"nop\n"  /* 2 byte jmp + 3 bytes */
426732f3ca7SSteven Rostedt 		"ftrace_test_p6nop:"
427732f3ca7SSteven Rostedt 		P6_NOP5
428732f3ca7SSteven Rostedt 		"jmp 1f\n"
429732f3ca7SSteven Rostedt 		"ftrace_test_nop5:"
430732f3ca7SSteven Rostedt 		".byte 0x66,0x66,0x66,0x66,0x90\n"
431732f3ca7SSteven Rostedt 		"1:"
432732f3ca7SSteven Rostedt 		".section .fixup, \"ax\"\n"
433732f3ca7SSteven Rostedt 		"2:	movl $1, %0\n"
434732f3ca7SSteven Rostedt 		"	jmp ftrace_test_nop5\n"
435732f3ca7SSteven Rostedt 		"3:	movl $2, %0\n"
436732f3ca7SSteven Rostedt 		"	jmp 1b\n"
437732f3ca7SSteven Rostedt 		".previous\n"
438732f3ca7SSteven Rostedt 		_ASM_EXTABLE(ftrace_test_p6nop, 2b)
439732f3ca7SSteven Rostedt 		_ASM_EXTABLE(ftrace_test_nop5, 3b)
440732f3ca7SSteven Rostedt 		: "=r"(faulted) : "0" (faulted));
441d61f82d0SSteven Rostedt 
442732f3ca7SSteven Rostedt 	switch (faulted) {
443732f3ca7SSteven Rostedt 	case 0:
444732f3ca7SSteven Rostedt 		pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n");
4458115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
446732f3ca7SSteven Rostedt 		break;
447732f3ca7SSteven Rostedt 	case 1:
448732f3ca7SSteven Rostedt 		pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n");
4498115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
450732f3ca7SSteven Rostedt 		break;
451732f3ca7SSteven Rostedt 	case 2:
4528b27386aSAnders Kaseorg 		pr_info("ftrace: converting mcount calls to jmp . + 5\n");
4538115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
454732f3ca7SSteven Rostedt 		break;
455732f3ca7SSteven Rostedt 	}
456d61f82d0SSteven Rostedt 
457732f3ca7SSteven Rostedt 	/* The return code is retured via data */
458732f3ca7SSteven Rostedt 	*(unsigned long *)data = 0;
459dfa60abaSSteven Rostedt 
4603d083395SSteven Rostedt 	return 0;
4613d083395SSteven Rostedt }
462caf4b323SFrederic Weisbecker #endif
463