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