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> 143d083395SSteven Rostedt #include <linux/ftrace.h> 153d083395SSteven Rostedt #include <linux/percpu.h> 163d083395SSteven Rostedt #include <linux/init.h> 173d083395SSteven Rostedt #include <linux/list.h> 183d083395SSteven Rostedt 19*dfa60abaSSteven Rostedt #include <asm/alternative.h> 20*dfa60abaSSteven Rostedt 213d083395SSteven Rostedt #define CALL_BACK 5 223d083395SSteven Rostedt 23*dfa60abaSSteven Rostedt /* Long is fine, even if it is only 4 bytes ;-) */ 24*dfa60abaSSteven Rostedt static long *ftrace_nop; 253d083395SSteven Rostedt 263d083395SSteven Rostedt struct ftrace_record { 273d083395SSteven Rostedt struct dyn_ftrace rec; 283d083395SSteven Rostedt int failed; 293d083395SSteven Rostedt } __attribute__((packed)); 303d083395SSteven Rostedt 313d083395SSteven Rostedt struct ftrace_page { 323d083395SSteven Rostedt struct ftrace_page *next; 333d083395SSteven Rostedt int index; 343d083395SSteven Rostedt struct ftrace_record records[]; 353d083395SSteven Rostedt } __attribute__((packed)); 363d083395SSteven Rostedt 373d083395SSteven Rostedt #define ENTRIES_PER_PAGE \ 383d083395SSteven Rostedt ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct ftrace_record)) 393d083395SSteven Rostedt 403d083395SSteven Rostedt /* estimate from running different kernels */ 413d083395SSteven Rostedt #define NR_TO_INIT 10000 423d083395SSteven Rostedt 433d083395SSteven Rostedt #define MCOUNT_ADDR ((long)(&mcount)) 443d083395SSteven Rostedt 453d083395SSteven Rostedt union ftrace_code_union { 463d083395SSteven Rostedt char code[5]; 473d083395SSteven Rostedt struct { 483d083395SSteven Rostedt char e8; 493d083395SSteven Rostedt int offset; 503d083395SSteven Rostedt } __attribute__((packed)); 513d083395SSteven Rostedt }; 523d083395SSteven Rostedt 533d083395SSteven Rostedt static struct ftrace_page *ftrace_pages_start; 543d083395SSteven Rostedt static struct ftrace_page *ftrace_pages; 553d083395SSteven Rostedt 563d083395SSteven Rostedt notrace struct dyn_ftrace *ftrace_alloc_shutdown_node(unsigned long ip) 573d083395SSteven Rostedt { 583d083395SSteven Rostedt struct ftrace_record *rec; 59*dfa60abaSSteven Rostedt unsigned long save; 603d083395SSteven Rostedt 613d083395SSteven Rostedt ip -= CALL_BACK; 62*dfa60abaSSteven Rostedt save = *(long *)ip; 633d083395SSteven Rostedt 643d083395SSteven Rostedt /* If this was already converted, skip it */ 65*dfa60abaSSteven Rostedt if (save == *ftrace_nop) 663d083395SSteven Rostedt return NULL; 673d083395SSteven Rostedt 683d083395SSteven Rostedt if (ftrace_pages->index == ENTRIES_PER_PAGE) { 693d083395SSteven Rostedt if (!ftrace_pages->next) 703d083395SSteven Rostedt return NULL; 713d083395SSteven Rostedt ftrace_pages = ftrace_pages->next; 723d083395SSteven Rostedt } 733d083395SSteven Rostedt 743d083395SSteven Rostedt rec = &ftrace_pages->records[ftrace_pages->index++]; 753d083395SSteven Rostedt 763d083395SSteven Rostedt return &rec->rec; 773d083395SSteven Rostedt } 783d083395SSteven Rostedt 793d083395SSteven Rostedt static int notrace 803d083395SSteven Rostedt ftrace_modify_code(unsigned long ip, unsigned char *old_code, 813d083395SSteven Rostedt unsigned char *new_code) 823d083395SSteven Rostedt { 83*dfa60abaSSteven Rostedt unsigned replaced; 84*dfa60abaSSteven Rostedt unsigned old = *(unsigned *)old_code; /* 4 bytes */ 85*dfa60abaSSteven Rostedt unsigned new = *(unsigned *)new_code; /* 4 bytes */ 86*dfa60abaSSteven Rostedt unsigned char newch = new_code[4]; 873d083395SSteven Rostedt int faulted = 0; 883d083395SSteven Rostedt 893d083395SSteven Rostedt /* 903d083395SSteven Rostedt * Note: Due to modules and __init, code can 913d083395SSteven Rostedt * disappear and change, we need to protect against faulting 923d083395SSteven Rostedt * as well as code changing. 933d083395SSteven Rostedt * 943d083395SSteven Rostedt * No real locking needed, this code is run through 953d083395SSteven Rostedt * kstop_machine. 963d083395SSteven Rostedt */ 973d083395SSteven Rostedt asm volatile ( 983d083395SSteven Rostedt "1: lock\n" 99*dfa60abaSSteven Rostedt " cmpxchg %3, (%2)\n" 100*dfa60abaSSteven Rostedt " jnz 2f\n" 101*dfa60abaSSteven Rostedt " movb %b4, 4(%2)\n" 1023d083395SSteven Rostedt "2:\n" 1033d083395SSteven Rostedt ".section .fixup, \"ax\"\n" 1043d083395SSteven Rostedt " movl $1, %0\n" 1053d083395SSteven Rostedt "3: jmp 2b\n" 1063d083395SSteven Rostedt ".previous\n" 1073d083395SSteven Rostedt _ASM_EXTABLE(1b, 3b) 1083d083395SSteven Rostedt : "=r"(faulted), "=a"(replaced) 109*dfa60abaSSteven Rostedt : "r"(ip), "r"(new), "r"(newch), 110*dfa60abaSSteven Rostedt "0"(faulted), "a"(old) 1113d083395SSteven Rostedt : "memory"); 1123d083395SSteven Rostedt sync_core(); 1133d083395SSteven Rostedt 114*dfa60abaSSteven Rostedt if (replaced != old && replaced != new) 1153d083395SSteven Rostedt faulted = 2; 1163d083395SSteven Rostedt 1173d083395SSteven Rostedt return faulted; 1183d083395SSteven Rostedt } 1193d083395SSteven Rostedt 1203d083395SSteven Rostedt static int notrace ftrace_calc_offset(long ip) 1213d083395SSteven Rostedt { 1223d083395SSteven Rostedt return (int)(MCOUNT_ADDR - ip); 1233d083395SSteven Rostedt } 1243d083395SSteven Rostedt 1253d083395SSteven Rostedt notrace void ftrace_code_disable(struct dyn_ftrace *rec) 1263d083395SSteven Rostedt { 1273d083395SSteven Rostedt unsigned long ip; 1283d083395SSteven Rostedt union ftrace_code_union save; 1293d083395SSteven Rostedt struct ftrace_record *r = 1303d083395SSteven Rostedt container_of(rec, struct ftrace_record, rec); 1313d083395SSteven Rostedt 1323d083395SSteven Rostedt ip = rec->ip; 1333d083395SSteven Rostedt 1343d083395SSteven Rostedt save.e8 = 0xe8; 1353d083395SSteven Rostedt save.offset = ftrace_calc_offset(ip); 1363d083395SSteven Rostedt 1373d083395SSteven Rostedt /* move the IP back to the start of the call */ 1383d083395SSteven Rostedt ip -= CALL_BACK; 1393d083395SSteven Rostedt 140*dfa60abaSSteven Rostedt r->failed = ftrace_modify_code(ip, save.code, (char *)ftrace_nop); 1413d083395SSteven Rostedt } 1423d083395SSteven Rostedt 1433d083395SSteven Rostedt static void notrace ftrace_replace_code(int saved) 1443d083395SSteven Rostedt { 1453d083395SSteven Rostedt unsigned char *new = NULL, *old = NULL; 1463d083395SSteven Rostedt struct ftrace_record *rec; 1473d083395SSteven Rostedt struct ftrace_page *pg; 1483d083395SSteven Rostedt unsigned long ip; 1493d083395SSteven Rostedt int i; 1503d083395SSteven Rostedt 1513d083395SSteven Rostedt if (saved) 152*dfa60abaSSteven Rostedt old = (char *)ftrace_nop; 1533d083395SSteven Rostedt else 154*dfa60abaSSteven Rostedt new = (char *)ftrace_nop; 1553d083395SSteven Rostedt 1563d083395SSteven Rostedt for (pg = ftrace_pages_start; pg; pg = pg->next) { 1573d083395SSteven Rostedt for (i = 0; i < pg->index; i++) { 1583d083395SSteven Rostedt union ftrace_code_union calc; 1593d083395SSteven Rostedt rec = &pg->records[i]; 1603d083395SSteven Rostedt 1613d083395SSteven Rostedt /* don't modify code that has already faulted */ 1623d083395SSteven Rostedt if (rec->failed) 1633d083395SSteven Rostedt continue; 1643d083395SSteven Rostedt 1653d083395SSteven Rostedt ip = rec->rec.ip; 1663d083395SSteven Rostedt 1673d083395SSteven Rostedt calc.e8 = 0xe8; 1683d083395SSteven Rostedt calc.offset = ftrace_calc_offset(ip); 1693d083395SSteven Rostedt 1703d083395SSteven Rostedt if (saved) 1713d083395SSteven Rostedt new = calc.code; 1723d083395SSteven Rostedt else 1733d083395SSteven Rostedt old = calc.code; 1743d083395SSteven Rostedt 1753d083395SSteven Rostedt ip -= CALL_BACK; 1763d083395SSteven Rostedt 1773d083395SSteven Rostedt rec->failed = ftrace_modify_code(ip, old, new); 1783d083395SSteven Rostedt } 1793d083395SSteven Rostedt } 1803d083395SSteven Rostedt 1813d083395SSteven Rostedt } 1823d083395SSteven Rostedt 1833d083395SSteven Rostedt notrace void ftrace_startup_code(void) 1843d083395SSteven Rostedt { 1853d083395SSteven Rostedt ftrace_replace_code(1); 1863d083395SSteven Rostedt } 1873d083395SSteven Rostedt 1883d083395SSteven Rostedt notrace void ftrace_shutdown_code(void) 1893d083395SSteven Rostedt { 1903d083395SSteven Rostedt ftrace_replace_code(0); 1913d083395SSteven Rostedt } 1923d083395SSteven Rostedt 1933d083395SSteven Rostedt notrace void ftrace_shutdown_replenish(void) 1943d083395SSteven Rostedt { 1953d083395SSteven Rostedt if (ftrace_pages->next) 1963d083395SSteven Rostedt return; 1973d083395SSteven Rostedt 1983d083395SSteven Rostedt /* allocate another page */ 1993d083395SSteven Rostedt ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL); 2003d083395SSteven Rostedt } 2013d083395SSteven Rostedt 202*dfa60abaSSteven Rostedt notrace int __init ftrace_shutdown_arch_init(void) 2033d083395SSteven Rostedt { 204*dfa60abaSSteven Rostedt const unsigned char *const *noptable = find_nop_table(); 2053d083395SSteven Rostedt struct ftrace_page *pg; 2063d083395SSteven Rostedt int cnt; 2073d083395SSteven Rostedt int i; 2083d083395SSteven Rostedt 209*dfa60abaSSteven Rostedt ftrace_nop = (unsigned long *)noptable[CALL_BACK]; 210*dfa60abaSSteven Rostedt 2113d083395SSteven Rostedt /* allocate a few pages */ 2123d083395SSteven Rostedt ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL); 2133d083395SSteven Rostedt if (!ftrace_pages_start) 2143d083395SSteven Rostedt return -1; 2153d083395SSteven Rostedt 2163d083395SSteven Rostedt /* 2173d083395SSteven Rostedt * Allocate a few more pages. 2183d083395SSteven Rostedt * 2193d083395SSteven Rostedt * TODO: have some parser search vmlinux before 2203d083395SSteven Rostedt * final linking to find all calls to ftrace. 2213d083395SSteven Rostedt * Then we can: 2223d083395SSteven Rostedt * a) know how many pages to allocate. 2233d083395SSteven Rostedt * and/or 2243d083395SSteven Rostedt * b) set up the table then. 2253d083395SSteven Rostedt * 2263d083395SSteven Rostedt * The dynamic code is still necessary for 2273d083395SSteven Rostedt * modules. 2283d083395SSteven Rostedt */ 2293d083395SSteven Rostedt 2303d083395SSteven Rostedt pg = ftrace_pages = ftrace_pages_start; 2313d083395SSteven Rostedt 2323d083395SSteven Rostedt cnt = NR_TO_INIT / ENTRIES_PER_PAGE; 2333d083395SSteven Rostedt 2343d083395SSteven Rostedt for (i = 0; i < cnt; i++) { 2353d083395SSteven Rostedt pg->next = (void *)get_zeroed_page(GFP_KERNEL); 2363d083395SSteven Rostedt 2373d083395SSteven Rostedt /* If we fail, we'll try later anyway */ 2383d083395SSteven Rostedt if (!pg->next) 2393d083395SSteven Rostedt break; 2403d083395SSteven Rostedt 2413d083395SSteven Rostedt pg = pg->next; 2423d083395SSteven Rostedt } 2433d083395SSteven Rostedt 2443d083395SSteven Rostedt return 0; 2453d083395SSteven Rostedt } 246