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