1 /* 1 2 * Ftrace support for Microblaze. 3 * 4 * Copyright (C) 2009 Michal Simek <monstr@mon 5 * Copyright (C) 2009 PetaLogix 6 * 7 * Based on MIPS and PowerPC ftrace code 8 * 9 * This file is subject to the terms and condi 10 * License. See the file "COPYING" in the main 11 * for more details. 12 */ 13 14 #include <asm/cacheflush.h> 15 #include <linux/ftrace.h> 16 17 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 18 /* 19 * Hook the return address and push it in the 20 * in current thread info. 21 */ 22 void prepare_ftrace_return(unsigned long *pare 23 { 24 unsigned long old; 25 int faulted; 26 unsigned long return_hooker = (unsigne 27 &return_to_han 28 29 if (unlikely(ftrace_graph_is_dead())) 30 return; 31 32 if (unlikely(atomic_read(¤t->tra 33 return; 34 35 /* 36 * Protect against fault, even if it s 37 * happen. This tool is too much intru 38 * ignore such a protection. 39 */ 40 asm volatile(" 1: lwi %0, %2 41 "2: swi %3, %2 42 " addik %1, r0 43 "3:" 44 " .section .fixu 45 "4: brid 3b;" 46 " addik %1, r0 47 " .previous;" 48 " .section __ex_ 49 " .word 1b,4b; 50 " .word 2b,4b; 51 " .previous;" 52 : "=&r" (old), "=r" (f 53 : "r" (parent), "r" (r 54 ); 55 56 flush_dcache_range((u32)parent, (u32)p 57 flush_icache_range((u32)parent, (u32)p 58 59 if (unlikely(faulted)) { 60 ftrace_graph_stop(); 61 WARN_ON(1); 62 return; 63 } 64 65 if (function_graph_enter(old, self_add 66 *parent = old; 67 } 68 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 69 70 #ifdef CONFIG_DYNAMIC_FTRACE 71 /* save value to addr - it is save to do it in 72 static int ftrace_modify_code(unsigned long ad 73 { 74 int faulted = 0; 75 76 __asm__ __volatile__(" 1: swi 77 " addik 78 "2:" 79 " .secti 80 "3: brid 81 " addik 82 " .previ 83 " .secti 84 " .word 85 " .previ 86 : "=r" (faulte 87 : "r" (addr), 88 ); 89 90 if (unlikely(faulted)) 91 return -EFAULT; 92 93 flush_dcache_range(addr, addr + 4); 94 flush_icache_range(addr, addr + 4); 95 96 return 0; 97 } 98 99 #define MICROBLAZE_NOP 0x80000000 100 #define MICROBLAZE_BRI 0xb800000C 101 102 static unsigned int recorded; /* if save was o 103 static unsigned int imm; /* saving whole imm i 104 105 /* There are two approaches howto solve ftrace 106 #undef USE_FTRACE_NOP 107 108 #ifdef USE_FTRACE_NOP 109 static unsigned int bralid; /* saving whole br 110 #endif 111 112 int ftrace_make_nop(struct module *mod, 113 struct dyn_ftrace *rec 114 { 115 /* we have this part of code which we 116 * b000c000 imm -16384 117 * b9fc8e30 bralid r15, -29136 118 * 80000000 or r0, r0, r0 119 * 120 * The first solution (!USE_FTRACE_NOP 121 * b000c000 bri 12 (0xC - jump 122 * b9fc8e30 bralid r15, -29136 123 * 80000000 or r0, r0, r0 124 * any other instruction 125 * 126 * The second solution (USE_FTRACE_NOP 127 * 80000000 or r0, r0, r0 128 * 80000000 or r0, r0, r0 129 * 80000000 or r0, r0, r0 130 */ 131 int ret = 0; 132 133 if (recorded == 0) { 134 recorded = 1; 135 imm = *(unsigned int *)rec->ip 136 pr_debug("%s: imm:0x%x\n", __f 137 #ifdef USE_FTRACE_NOP 138 bralid = *(unsigned int *)(rec 139 pr_debug("%s: bralid 0x%x\n", 140 #endif /* USE_FTRACE_NOP */ 141 } 142 143 #ifdef USE_FTRACE_NOP 144 ret = ftrace_modify_code(rec->ip, MICR 145 ret += ftrace_modify_code(rec->ip + 4, 146 #else /* USE_FTRACE_NOP */ 147 ret = ftrace_modify_code(rec->ip, MICR 148 #endif /* USE_FTRACE_NOP */ 149 return ret; 150 } 151 152 /* I believe that first is called ftrace_make_ 153 int ftrace_make_call(struct dyn_ftrace *rec, u 154 { 155 int ret; 156 pr_debug("%s: addr:0x%x, rec->ip: 0x%x 157 __func__, (unsigned int)addr, 158 ret = ftrace_modify_code(rec->ip, imm) 159 #ifdef USE_FTRACE_NOP 160 pr_debug("%s: bralid:0x%x\n", __func__ 161 ret += ftrace_modify_code(rec->ip + 4, 162 #endif /* USE_FTRACE_NOP */ 163 return ret; 164 } 165 166 int ftrace_update_ftrace_func(ftrace_func_t fu 167 { 168 unsigned long ip = (unsigned long)(&ft 169 unsigned int upper = (unsigned int)fun 170 unsigned int lower = (unsigned int)fun 171 int ret = 0; 172 173 /* create proper saving to ftrace_call 174 upper = 0xb0000000 + (upper >> 16); /* 175 lower = 0x32800000 + (lower & 0xFFFF); 176 177 pr_debug("%s: func=0x%x, ip=0x%x, uppe 178 __func__, (unsigned int)func, 179 180 /* save upper and lower code */ 181 ret = ftrace_modify_code(ip, upper); 182 ret += ftrace_modify_code(ip + 4, lowe 183 184 /* We just need to replace the rtsd r1 185 ret += ftrace_modify_code((unsigned lo 186 MICROBLAZE_N 187 188 return ret; 189 } 190 191 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 192 unsigned int old_jump; /* saving place for jum 193 194 int ftrace_enable_ftrace_graph_caller(void) 195 { 196 unsigned int ret; 197 unsigned long ip = (unsigned long)(&ft 198 199 old_jump = *(unsigned int *)ip; /* sav 200 ret = ftrace_modify_code(ip, MICROBLAZ 201 202 pr_debug("%s: Replace instruction: 0x% 203 return ret; 204 } 205 206 int ftrace_disable_ftrace_graph_caller(void) 207 { 208 unsigned int ret; 209 unsigned long ip = (unsigned long)(&ft 210 211 ret = ftrace_modify_code(ip, old_jump) 212 213 pr_debug("%s\n", __func__); 214 return ret; 215 } 216 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 217 #endif /* CONFIG_DYNAMIC_FTRACE */ 218
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.