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