xref: /openbmc/linux/arch/x86/kernel/ftrace.c (revision caf4b323b02a16c92fba449952ac6515ddc76d7a)
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>
173d083395SSteven Rostedt #include <linux/init.h>
183d083395SSteven Rostedt #include <linux/list.h>
193d083395SSteven Rostedt 
20395a59d0SAbhishek Sagar #include <asm/ftrace.h>
21*caf4b323SFrederic Weisbecker #include <linux/ftrace.h>
22732f3ca7SSteven Rostedt #include <asm/nops.h>
23*caf4b323SFrederic Weisbecker #include <asm/nmi.h>
24dfa60abaSSteven Rostedt 
253d083395SSteven Rostedt 
26*caf4b323SFrederic Weisbecker 
27*caf4b323SFrederic Weisbecker #ifdef CONFIG_FUNCTION_RET_TRACER
28*caf4b323SFrederic Weisbecker 
29*caf4b323SFrederic Weisbecker /*
30*caf4b323SFrederic Weisbecker  * These functions are picked from those used on
31*caf4b323SFrederic Weisbecker  * this page for dynamic ftrace. They have been
32*caf4b323SFrederic Weisbecker  * simplified to ignore all traces in NMI context.
33*caf4b323SFrederic Weisbecker  */
34*caf4b323SFrederic Weisbecker static atomic_t in_nmi;
35*caf4b323SFrederic Weisbecker 
36*caf4b323SFrederic Weisbecker void ftrace_nmi_enter(void)
37*caf4b323SFrederic Weisbecker {
38*caf4b323SFrederic Weisbecker 	atomic_inc(&in_nmi);
39*caf4b323SFrederic Weisbecker }
40*caf4b323SFrederic Weisbecker 
41*caf4b323SFrederic Weisbecker void ftrace_nmi_exit(void)
42*caf4b323SFrederic Weisbecker {
43*caf4b323SFrederic Weisbecker 	atomic_dec(&in_nmi);
44*caf4b323SFrederic Weisbecker }
45*caf4b323SFrederic Weisbecker 
46*caf4b323SFrederic Weisbecker /*
47*caf4b323SFrederic Weisbecker  * Synchronize accesses to return adresses stack with
48*caf4b323SFrederic Weisbecker  * interrupts.
49*caf4b323SFrederic Weisbecker  */
50*caf4b323SFrederic Weisbecker static raw_spinlock_t ret_stack_lock;
51*caf4b323SFrederic Weisbecker 
52*caf4b323SFrederic Weisbecker /* Add a function return address to the trace stack on thread info.*/
53*caf4b323SFrederic Weisbecker static int push_return_trace(unsigned long ret, unsigned long long time,
54*caf4b323SFrederic Weisbecker 				unsigned long func)
55*caf4b323SFrederic Weisbecker {
56*caf4b323SFrederic Weisbecker 	int index;
57*caf4b323SFrederic Weisbecker 	struct thread_info *ti;
58*caf4b323SFrederic Weisbecker 	unsigned long flags;
59*caf4b323SFrederic Weisbecker 	int err = 0;
60*caf4b323SFrederic Weisbecker 
61*caf4b323SFrederic Weisbecker 	raw_local_irq_save(flags);
62*caf4b323SFrederic Weisbecker 	__raw_spin_lock(&ret_stack_lock);
63*caf4b323SFrederic Weisbecker 
64*caf4b323SFrederic Weisbecker 	ti = current_thread_info();
65*caf4b323SFrederic Weisbecker 	/* The return trace stack is full */
66*caf4b323SFrederic Weisbecker 	if (ti->curr_ret_stack == FTRACE_RET_STACK_SIZE - 1) {
67*caf4b323SFrederic Weisbecker 		err = -EBUSY;
68*caf4b323SFrederic Weisbecker 		goto out;
69*caf4b323SFrederic Weisbecker 	}
70*caf4b323SFrederic Weisbecker 
71*caf4b323SFrederic Weisbecker 	index = ++ti->curr_ret_stack;
72*caf4b323SFrederic Weisbecker 	ti->ret_stack[index].ret = ret;
73*caf4b323SFrederic Weisbecker 	ti->ret_stack[index].func = func;
74*caf4b323SFrederic Weisbecker 	ti->ret_stack[index].calltime = time;
75*caf4b323SFrederic Weisbecker 
76*caf4b323SFrederic Weisbecker out:
77*caf4b323SFrederic Weisbecker 	__raw_spin_unlock(&ret_stack_lock);
78*caf4b323SFrederic Weisbecker 	raw_local_irq_restore(flags);
79*caf4b323SFrederic Weisbecker 	return err;
80*caf4b323SFrederic Weisbecker }
81*caf4b323SFrederic Weisbecker 
82*caf4b323SFrederic Weisbecker /* Retrieve a function return address to the trace stack on thread info.*/
83*caf4b323SFrederic Weisbecker static void pop_return_trace(unsigned long *ret, unsigned long long *time,
84*caf4b323SFrederic Weisbecker 				unsigned long *func)
85*caf4b323SFrederic Weisbecker {
86*caf4b323SFrederic Weisbecker 	struct thread_info *ti;
87*caf4b323SFrederic Weisbecker 	int index;
88*caf4b323SFrederic Weisbecker 	unsigned long flags;
89*caf4b323SFrederic Weisbecker 
90*caf4b323SFrederic Weisbecker 	raw_local_irq_save(flags);
91*caf4b323SFrederic Weisbecker 	__raw_spin_lock(&ret_stack_lock);
92*caf4b323SFrederic Weisbecker 
93*caf4b323SFrederic Weisbecker 	ti = current_thread_info();
94*caf4b323SFrederic Weisbecker 	index = ti->curr_ret_stack;
95*caf4b323SFrederic Weisbecker 	*ret = ti->ret_stack[index].ret;
96*caf4b323SFrederic Weisbecker 	*func = ti->ret_stack[index].func;
97*caf4b323SFrederic Weisbecker 	*time = ti->ret_stack[index].calltime;
98*caf4b323SFrederic Weisbecker 	ti->curr_ret_stack--;
99*caf4b323SFrederic Weisbecker 
100*caf4b323SFrederic Weisbecker 	__raw_spin_unlock(&ret_stack_lock);
101*caf4b323SFrederic Weisbecker 	raw_local_irq_restore(flags);
102*caf4b323SFrederic Weisbecker }
103*caf4b323SFrederic Weisbecker 
104*caf4b323SFrederic Weisbecker /*
105*caf4b323SFrederic Weisbecker  * Send the trace to the ring-buffer.
106*caf4b323SFrederic Weisbecker  * @return the original return address.
107*caf4b323SFrederic Weisbecker  */
108*caf4b323SFrederic Weisbecker unsigned long ftrace_return_to_handler(void)
109*caf4b323SFrederic Weisbecker {
110*caf4b323SFrederic Weisbecker 	struct ftrace_retfunc trace;
111*caf4b323SFrederic Weisbecker 	pop_return_trace(&trace.ret, &trace.calltime, &trace.func);
112*caf4b323SFrederic Weisbecker 	trace.rettime = cpu_clock(raw_smp_processor_id());
113*caf4b323SFrederic Weisbecker 	ftrace_function_return(&trace);
114*caf4b323SFrederic Weisbecker 
115*caf4b323SFrederic Weisbecker 	return trace.ret;
116*caf4b323SFrederic Weisbecker }
117*caf4b323SFrederic Weisbecker 
118*caf4b323SFrederic Weisbecker /*
119*caf4b323SFrederic Weisbecker  * Hook the return address and push it in the stack of return addrs
120*caf4b323SFrederic Weisbecker  * in current thread info.
121*caf4b323SFrederic Weisbecker  */
122*caf4b323SFrederic Weisbecker asmlinkage
123*caf4b323SFrederic Weisbecker void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
124*caf4b323SFrederic Weisbecker {
125*caf4b323SFrederic Weisbecker 	unsigned long old;
126*caf4b323SFrederic Weisbecker 	unsigned long long calltime;
127*caf4b323SFrederic Weisbecker 	int faulted;
128*caf4b323SFrederic Weisbecker 	unsigned long return_hooker = (unsigned long)
129*caf4b323SFrederic Weisbecker 				&return_to_handler;
130*caf4b323SFrederic Weisbecker 
131*caf4b323SFrederic Weisbecker 	/* Nmi's are currently unsupported */
132*caf4b323SFrederic Weisbecker 	if (atomic_read(&in_nmi))
133*caf4b323SFrederic Weisbecker 		return;
134*caf4b323SFrederic Weisbecker 
135*caf4b323SFrederic Weisbecker 	/*
136*caf4b323SFrederic Weisbecker 	 * Protect against fault, even if it shouldn't
137*caf4b323SFrederic Weisbecker 	 * happen. This tool is too much intrusive to
138*caf4b323SFrederic Weisbecker 	 * ignore such a protection.
139*caf4b323SFrederic Weisbecker 	 */
140*caf4b323SFrederic Weisbecker 	asm volatile(
141*caf4b323SFrederic Weisbecker 		"1: movl (%[parent_old]), %[old]\n"
142*caf4b323SFrederic Weisbecker 		"2: movl %[return_hooker], (%[parent_replaced])\n"
143*caf4b323SFrederic Weisbecker 		"   movl $0, %[faulted]\n"
144*caf4b323SFrederic Weisbecker 
145*caf4b323SFrederic Weisbecker 		".section .fixup, \"ax\"\n"
146*caf4b323SFrederic Weisbecker 		"3: movl $1, %[faulted]\n"
147*caf4b323SFrederic Weisbecker 		".previous\n"
148*caf4b323SFrederic Weisbecker 
149*caf4b323SFrederic Weisbecker 		".section __ex_table, \"a\"\n"
150*caf4b323SFrederic Weisbecker 		"   .long 1b, 3b\n"
151*caf4b323SFrederic Weisbecker 		"   .long 2b, 3b\n"
152*caf4b323SFrederic Weisbecker 		".previous\n"
153*caf4b323SFrederic Weisbecker 
154*caf4b323SFrederic Weisbecker 		: [parent_replaced] "=rm" (parent), [old] "=r" (old),
155*caf4b323SFrederic Weisbecker 		  [faulted] "=r" (faulted)
156*caf4b323SFrederic Weisbecker 		: [parent_old] "0" (parent), [return_hooker] "r" (return_hooker)
157*caf4b323SFrederic Weisbecker 		: "memory"
158*caf4b323SFrederic Weisbecker 	);
159*caf4b323SFrederic Weisbecker 
160*caf4b323SFrederic Weisbecker 	if (WARN_ON(faulted)) {
161*caf4b323SFrederic Weisbecker 		unregister_ftrace_return();
162*caf4b323SFrederic Weisbecker 		return;
163*caf4b323SFrederic Weisbecker 	}
164*caf4b323SFrederic Weisbecker 
165*caf4b323SFrederic Weisbecker 	if (WARN_ON(!__kernel_text_address(old))) {
166*caf4b323SFrederic Weisbecker 		unregister_ftrace_return();
167*caf4b323SFrederic Weisbecker 		*parent = old;
168*caf4b323SFrederic Weisbecker 		return;
169*caf4b323SFrederic Weisbecker 	}
170*caf4b323SFrederic Weisbecker 
171*caf4b323SFrederic Weisbecker 	calltime = cpu_clock(raw_smp_processor_id());
172*caf4b323SFrederic Weisbecker 
173*caf4b323SFrederic Weisbecker 	if (push_return_trace(old, calltime, self_addr) == -EBUSY)
174*caf4b323SFrederic Weisbecker 		*parent = old;
175*caf4b323SFrederic Weisbecker }
176*caf4b323SFrederic Weisbecker 
177*caf4b323SFrederic Weisbecker static int __init init_ftrace_function_return(void)
178*caf4b323SFrederic Weisbecker {
179*caf4b323SFrederic Weisbecker 	ret_stack_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
180*caf4b323SFrederic Weisbecker 	return 0;
181*caf4b323SFrederic Weisbecker }
182*caf4b323SFrederic Weisbecker device_initcall(init_ftrace_function_return);
183*caf4b323SFrederic Weisbecker 
184*caf4b323SFrederic Weisbecker 
185*caf4b323SFrederic Weisbecker #endif
186*caf4b323SFrederic Weisbecker 
187*caf4b323SFrederic Weisbecker #ifdef CONFIG_DYNAMIC_FTRACE
1883d083395SSteven Rostedt 
1893d083395SSteven Rostedt union ftrace_code_union {
190395a59d0SAbhishek Sagar 	char code[MCOUNT_INSN_SIZE];
1913d083395SSteven Rostedt 	struct {
1923d083395SSteven Rostedt 		char e8;
1933d083395SSteven Rostedt 		int offset;
1943d083395SSteven Rostedt 	} __attribute__((packed));
1953d083395SSteven Rostedt };
1963d083395SSteven Rostedt 
19715adc048SSteven Rostedt static int ftrace_calc_offset(long ip, long addr)
1983c1720f0SSteven Rostedt {
1993c1720f0SSteven Rostedt 	return (int)(addr - ip);
2003d083395SSteven Rostedt }
2013d083395SSteven Rostedt 
20215adc048SSteven Rostedt unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
2033c1720f0SSteven Rostedt {
2043c1720f0SSteven Rostedt 	static union ftrace_code_union calc;
2053c1720f0SSteven Rostedt 
2063c1720f0SSteven Rostedt 	calc.e8		= 0xe8;
207395a59d0SAbhishek Sagar 	calc.offset	= ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
2083c1720f0SSteven Rostedt 
2093c1720f0SSteven Rostedt 	/*
2103c1720f0SSteven Rostedt 	 * No locking needed, this must be called via kstop_machine
2113c1720f0SSteven Rostedt 	 * which in essence is like running on a uniprocessor machine.
2123c1720f0SSteven Rostedt 	 */
2133c1720f0SSteven Rostedt 	return calc.code;
2143c1720f0SSteven Rostedt }
2153c1720f0SSteven Rostedt 
21617666f02SSteven Rostedt /*
21717666f02SSteven Rostedt  * Modifying code must take extra care. On an SMP machine, if
21817666f02SSteven Rostedt  * the code being modified is also being executed on another CPU
21917666f02SSteven Rostedt  * that CPU will have undefined results and possibly take a GPF.
22017666f02SSteven Rostedt  * We use kstop_machine to stop other CPUS from exectuing code.
22117666f02SSteven Rostedt  * But this does not stop NMIs from happening. We still need
22217666f02SSteven Rostedt  * to protect against that. We separate out the modification of
22317666f02SSteven Rostedt  * the code to take care of this.
22417666f02SSteven Rostedt  *
22517666f02SSteven Rostedt  * Two buffers are added: An IP buffer and a "code" buffer.
22617666f02SSteven Rostedt  *
227a26a2a27SSteven Rostedt  * 1) Put the instruction pointer into the IP buffer
22817666f02SSteven Rostedt  *    and the new code into the "code" buffer.
22917666f02SSteven Rostedt  * 2) Set a flag that says we are modifying code
23017666f02SSteven Rostedt  * 3) Wait for any running NMIs to finish.
23117666f02SSteven Rostedt  * 4) Write the code
23217666f02SSteven Rostedt  * 5) clear the flag.
23317666f02SSteven Rostedt  * 6) Wait for any running NMIs to finish.
23417666f02SSteven Rostedt  *
23517666f02SSteven Rostedt  * If an NMI is executed, the first thing it does is to call
23617666f02SSteven Rostedt  * "ftrace_nmi_enter". This will check if the flag is set to write
23717666f02SSteven Rostedt  * and if it is, it will write what is in the IP and "code" buffers.
23817666f02SSteven Rostedt  *
23917666f02SSteven Rostedt  * The trick is, it does not matter if everyone is writing the same
24017666f02SSteven Rostedt  * content to the code location. Also, if a CPU is executing code
24117666f02SSteven Rostedt  * it is OK to write to that code location if the contents being written
24217666f02SSteven Rostedt  * are the same as what exists.
24317666f02SSteven Rostedt  */
24417666f02SSteven Rostedt 
245a26a2a27SSteven Rostedt static atomic_t in_nmi = ATOMIC_INIT(0);
246a26a2a27SSteven Rostedt static int mod_code_status;		/* holds return value of text write */
247a26a2a27SSteven Rostedt static int mod_code_write;		/* set when NMI should do the write */
248a26a2a27SSteven Rostedt static void *mod_code_ip;		/* holds the IP to write to */
249a26a2a27SSteven Rostedt static void *mod_code_newcode;		/* holds the text to write to the IP */
25017666f02SSteven Rostedt 
251a26a2a27SSteven Rostedt static unsigned nmi_wait_count;
252a26a2a27SSteven Rostedt static atomic_t nmi_update_count = ATOMIC_INIT(0);
253b807c3d0SSteven Rostedt 
254b807c3d0SSteven Rostedt int ftrace_arch_read_dyn_info(char *buf, int size)
255b807c3d0SSteven Rostedt {
256b807c3d0SSteven Rostedt 	int r;
257b807c3d0SSteven Rostedt 
258b807c3d0SSteven Rostedt 	r = snprintf(buf, size, "%u %u",
259b807c3d0SSteven Rostedt 		     nmi_wait_count,
260b807c3d0SSteven Rostedt 		     atomic_read(&nmi_update_count));
261b807c3d0SSteven Rostedt 	return r;
262b807c3d0SSteven Rostedt }
263b807c3d0SSteven Rostedt 
26417666f02SSteven Rostedt static void ftrace_mod_code(void)
26517666f02SSteven Rostedt {
26617666f02SSteven Rostedt 	/*
26717666f02SSteven Rostedt 	 * Yes, more than one CPU process can be writing to mod_code_status.
26817666f02SSteven Rostedt 	 *    (and the code itself)
26917666f02SSteven Rostedt 	 * But if one were to fail, then they all should, and if one were
27017666f02SSteven Rostedt 	 * to succeed, then they all should.
27117666f02SSteven Rostedt 	 */
27217666f02SSteven Rostedt 	mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
27317666f02SSteven Rostedt 					     MCOUNT_INSN_SIZE);
27417666f02SSteven Rostedt 
27517666f02SSteven Rostedt }
27617666f02SSteven Rostedt 
27717666f02SSteven Rostedt void ftrace_nmi_enter(void)
27817666f02SSteven Rostedt {
27917666f02SSteven Rostedt 	atomic_inc(&in_nmi);
28017666f02SSteven Rostedt 	/* Must have in_nmi seen before reading write flag */
28117666f02SSteven Rostedt 	smp_mb();
282b807c3d0SSteven Rostedt 	if (mod_code_write) {
28317666f02SSteven Rostedt 		ftrace_mod_code();
284b807c3d0SSteven Rostedt 		atomic_inc(&nmi_update_count);
285b807c3d0SSteven Rostedt 	}
28617666f02SSteven Rostedt }
28717666f02SSteven Rostedt 
28817666f02SSteven Rostedt void ftrace_nmi_exit(void)
28917666f02SSteven Rostedt {
29017666f02SSteven Rostedt 	/* Finish all executions before clearing in_nmi */
29117666f02SSteven Rostedt 	smp_wmb();
29217666f02SSteven Rostedt 	atomic_dec(&in_nmi);
29317666f02SSteven Rostedt }
29417666f02SSteven Rostedt 
29517666f02SSteven Rostedt static void wait_for_nmi(void)
29617666f02SSteven Rostedt {
297b807c3d0SSteven Rostedt 	int waited = 0;
298b807c3d0SSteven Rostedt 
299b807c3d0SSteven Rostedt 	while (atomic_read(&in_nmi)) {
300b807c3d0SSteven Rostedt 		waited = 1;
30117666f02SSteven Rostedt 		cpu_relax();
30217666f02SSteven Rostedt 	}
30317666f02SSteven Rostedt 
304b807c3d0SSteven Rostedt 	if (waited)
305b807c3d0SSteven Rostedt 		nmi_wait_count++;
306b807c3d0SSteven Rostedt }
307b807c3d0SSteven Rostedt 
30817666f02SSteven Rostedt static int
30917666f02SSteven Rostedt do_ftrace_mod_code(unsigned long ip, void *new_code)
31017666f02SSteven Rostedt {
31117666f02SSteven Rostedt 	mod_code_ip = (void *)ip;
31217666f02SSteven Rostedt 	mod_code_newcode = new_code;
31317666f02SSteven Rostedt 
31417666f02SSteven Rostedt 	/* The buffers need to be visible before we let NMIs write them */
31517666f02SSteven Rostedt 	smp_wmb();
31617666f02SSteven Rostedt 
31717666f02SSteven Rostedt 	mod_code_write = 1;
31817666f02SSteven Rostedt 
31917666f02SSteven Rostedt 	/* Make sure write bit is visible before we wait on NMIs */
32017666f02SSteven Rostedt 	smp_mb();
32117666f02SSteven Rostedt 
32217666f02SSteven Rostedt 	wait_for_nmi();
32317666f02SSteven Rostedt 
32417666f02SSteven Rostedt 	/* Make sure all running NMIs have finished before we write the code */
32517666f02SSteven Rostedt 	smp_mb();
32617666f02SSteven Rostedt 
32717666f02SSteven Rostedt 	ftrace_mod_code();
32817666f02SSteven Rostedt 
32917666f02SSteven Rostedt 	/* Make sure the write happens before clearing the bit */
33017666f02SSteven Rostedt 	smp_wmb();
33117666f02SSteven Rostedt 
33217666f02SSteven Rostedt 	mod_code_write = 0;
33317666f02SSteven Rostedt 
33417666f02SSteven Rostedt 	/* make sure NMIs see the cleared bit */
33517666f02SSteven Rostedt 	smp_mb();
33617666f02SSteven Rostedt 
33717666f02SSteven Rostedt 	wait_for_nmi();
33817666f02SSteven Rostedt 
33917666f02SSteven Rostedt 	return mod_code_status;
34017666f02SSteven Rostedt }
34117666f02SSteven Rostedt 
34217666f02SSteven Rostedt 
343*caf4b323SFrederic Weisbecker 
344*caf4b323SFrederic Weisbecker 
345*caf4b323SFrederic Weisbecker static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
346*caf4b323SFrederic Weisbecker 
347*caf4b323SFrederic Weisbecker unsigned char *ftrace_nop_replace(void)
348*caf4b323SFrederic Weisbecker {
349*caf4b323SFrederic Weisbecker 	return ftrace_nop;
350*caf4b323SFrederic Weisbecker }
351*caf4b323SFrederic Weisbecker 
35215adc048SSteven Rostedt int
3533d083395SSteven Rostedt ftrace_modify_code(unsigned long ip, unsigned char *old_code,
3543d083395SSteven Rostedt 		   unsigned char *new_code)
3553d083395SSteven Rostedt {
3566f93fc07SSteven Rostedt 	unsigned char replaced[MCOUNT_INSN_SIZE];
3573d083395SSteven Rostedt 
3583d083395SSteven Rostedt 	/*
3593d083395SSteven Rostedt 	 * Note: Due to modules and __init, code can
3603d083395SSteven Rostedt 	 *  disappear and change, we need to protect against faulting
36176aefee5SSteven Rostedt 	 *  as well as code changing. We do this by using the
362ab9a0918SSteven Rostedt 	 *  probe_kernel_* functions.
3633d083395SSteven Rostedt 	 *
3643d083395SSteven Rostedt 	 * No real locking needed, this code is run through
3656f93fc07SSteven Rostedt 	 * kstop_machine, or before SMP starts.
3663d083395SSteven Rostedt 	 */
36776aefee5SSteven Rostedt 
36876aefee5SSteven Rostedt 	/* read the text we want to modify */
369ab9a0918SSteven Rostedt 	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
370593eb8a2SSteven Rostedt 		return -EFAULT;
3716f93fc07SSteven Rostedt 
37276aefee5SSteven Rostedt 	/* Make sure it is what we expect it to be */
3736f93fc07SSteven Rostedt 	if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
374593eb8a2SSteven Rostedt 		return -EINVAL;
3756f93fc07SSteven Rostedt 
37676aefee5SSteven Rostedt 	/* replace the text with the new text */
37717666f02SSteven Rostedt 	if (do_ftrace_mod_code(ip, new_code))
378593eb8a2SSteven Rostedt 		return -EPERM;
3796f93fc07SSteven Rostedt 
3803d083395SSteven Rostedt 	sync_core();
3813d083395SSteven Rostedt 
3826f93fc07SSteven Rostedt 	return 0;
3833d083395SSteven Rostedt }
3843d083395SSteven Rostedt 
38515adc048SSteven Rostedt int ftrace_update_ftrace_func(ftrace_func_t func)
386d61f82d0SSteven Rostedt {
387d61f82d0SSteven Rostedt 	unsigned long ip = (unsigned long)(&ftrace_call);
388395a59d0SAbhishek Sagar 	unsigned char old[MCOUNT_INSN_SIZE], *new;
389d61f82d0SSteven Rostedt 	int ret;
390d61f82d0SSteven Rostedt 
391395a59d0SAbhishek Sagar 	memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
392d61f82d0SSteven Rostedt 	new = ftrace_call_replace(ip, (unsigned long)func);
393d61f82d0SSteven Rostedt 	ret = ftrace_modify_code(ip, old, new);
394d61f82d0SSteven Rostedt 
395d61f82d0SSteven Rostedt 	return ret;
396d61f82d0SSteven Rostedt }
397d61f82d0SSteven Rostedt 
398d61f82d0SSteven Rostedt int __init ftrace_dyn_arch_init(void *data)
3993d083395SSteven Rostedt {
400732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_p6nop[];
401732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_nop5[];
402732f3ca7SSteven Rostedt 	extern const unsigned char ftrace_test_jmp[];
403732f3ca7SSteven Rostedt 	int faulted = 0;
4043d083395SSteven Rostedt 
405732f3ca7SSteven Rostedt 	/*
406732f3ca7SSteven Rostedt 	 * There is no good nop for all x86 archs.
407732f3ca7SSteven Rostedt 	 * We will default to using the P6_NOP5, but first we
408732f3ca7SSteven Rostedt 	 * will test to make sure that the nop will actually
409732f3ca7SSteven Rostedt 	 * work on this CPU. If it faults, we will then
410732f3ca7SSteven Rostedt 	 * go to a lesser efficient 5 byte nop. If that fails
411732f3ca7SSteven Rostedt 	 * we then just use a jmp as our nop. This isn't the most
412732f3ca7SSteven Rostedt 	 * efficient nop, but we can not use a multi part nop
413732f3ca7SSteven Rostedt 	 * since we would then risk being preempted in the middle
414732f3ca7SSteven Rostedt 	 * of that nop, and if we enabled tracing then, it might
415732f3ca7SSteven Rostedt 	 * cause a system crash.
416732f3ca7SSteven Rostedt 	 *
417732f3ca7SSteven Rostedt 	 * TODO: check the cpuid to determine the best nop.
418732f3ca7SSteven Rostedt 	 */
419732f3ca7SSteven Rostedt 	asm volatile (
420732f3ca7SSteven Rostedt 		"ftrace_test_jmp:"
421732f3ca7SSteven Rostedt 		"jmp ftrace_test_p6nop\n"
4228b27386aSAnders Kaseorg 		"nop\n"
4238b27386aSAnders Kaseorg 		"nop\n"
4248b27386aSAnders Kaseorg 		"nop\n"  /* 2 byte jmp + 3 bytes */
425732f3ca7SSteven Rostedt 		"ftrace_test_p6nop:"
426732f3ca7SSteven Rostedt 		P6_NOP5
427732f3ca7SSteven Rostedt 		"jmp 1f\n"
428732f3ca7SSteven Rostedt 		"ftrace_test_nop5:"
429732f3ca7SSteven Rostedt 		".byte 0x66,0x66,0x66,0x66,0x90\n"
430732f3ca7SSteven Rostedt 		"1:"
431732f3ca7SSteven Rostedt 		".section .fixup, \"ax\"\n"
432732f3ca7SSteven Rostedt 		"2:	movl $1, %0\n"
433732f3ca7SSteven Rostedt 		"	jmp ftrace_test_nop5\n"
434732f3ca7SSteven Rostedt 		"3:	movl $2, %0\n"
435732f3ca7SSteven Rostedt 		"	jmp 1b\n"
436732f3ca7SSteven Rostedt 		".previous\n"
437732f3ca7SSteven Rostedt 		_ASM_EXTABLE(ftrace_test_p6nop, 2b)
438732f3ca7SSteven Rostedt 		_ASM_EXTABLE(ftrace_test_nop5, 3b)
439732f3ca7SSteven Rostedt 		: "=r"(faulted) : "0" (faulted));
440d61f82d0SSteven Rostedt 
441732f3ca7SSteven Rostedt 	switch (faulted) {
442732f3ca7SSteven Rostedt 	case 0:
443732f3ca7SSteven Rostedt 		pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n");
4448115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
445732f3ca7SSteven Rostedt 		break;
446732f3ca7SSteven Rostedt 	case 1:
447732f3ca7SSteven Rostedt 		pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n");
4488115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
449732f3ca7SSteven Rostedt 		break;
450732f3ca7SSteven Rostedt 	case 2:
4518b27386aSAnders Kaseorg 		pr_info("ftrace: converting mcount calls to jmp . + 5\n");
4528115f3f0SSteven Rostedt 		memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
453732f3ca7SSteven Rostedt 		break;
454732f3ca7SSteven Rostedt 	}
455d61f82d0SSteven Rostedt 
456732f3ca7SSteven Rostedt 	/* The return code is retured via data */
457732f3ca7SSteven Rostedt 	*(unsigned long *)data = 0;
458dfa60abaSSteven Rostedt 
4593d083395SSteven Rostedt 	return 0;
4603d083395SSteven Rostedt }
461*caf4b323SFrederic Weisbecker #endif
462