diff options
-rw-r--r-- | arch/powerpc/include/asm/ftrace.h | 14 | ||||
-rw-r--r-- | arch/powerpc/kernel/ftrace.c | 67 |
2 files changed, 75 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index b298f7a631e6..17efecc2bf03 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h | |||
@@ -7,7 +7,19 @@ | |||
7 | 7 | ||
8 | #ifndef __ASSEMBLY__ | 8 | #ifndef __ASSEMBLY__ |
9 | extern void _mcount(void); | 9 | extern void _mcount(void); |
10 | #endif | 10 | |
11 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
12 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | ||
13 | { | ||
14 | /* reloction of mcount call site is the same as the address */ | ||
15 | return addr; | ||
16 | } | ||
17 | |||
18 | struct dyn_arch_ftrace { | ||
19 | /* nothing yet */ | ||
20 | }; | ||
21 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
22 | #endif /* __ASSEMBLY__ */ | ||
11 | 23 | ||
12 | #endif | 24 | #endif |
13 | 25 | ||
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index f4b006ed0ab1..24c023a5cae8 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c | |||
@@ -33,12 +33,12 @@ static unsigned int ftrace_calc_offset(long ip, long addr) | |||
33 | return (int)(addr - ip); | 33 | return (int)(addr - ip); |
34 | } | 34 | } |
35 | 35 | ||
36 | unsigned char *ftrace_nop_replace(void) | 36 | static unsigned char *ftrace_nop_replace(void) |
37 | { | 37 | { |
38 | return (char *)&ftrace_nop; | 38 | return (char *)&ftrace_nop; |
39 | } | 39 | } |
40 | 40 | ||
41 | unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | 41 | static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) |
42 | { | 42 | { |
43 | static unsigned int op; | 43 | static unsigned int op; |
44 | 44 | ||
@@ -68,7 +68,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
68 | # define _ASM_PTR " .long " | 68 | # define _ASM_PTR " .long " |
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | int | 71 | static int |
72 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 72 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, |
73 | unsigned char *new_code) | 73 | unsigned char *new_code) |
74 | { | 74 | { |
@@ -113,6 +113,62 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
113 | return faulted; | 113 | return faulted; |
114 | } | 114 | } |
115 | 115 | ||
116 | static int test_24bit_addr(unsigned long ip, unsigned long addr) | ||
117 | { | ||
118 | long diff; | ||
119 | |||
120 | /* | ||
121 | * Can we get to addr from ip in 24 bits? | ||
122 | * (26 really, since we mulitply by 4 for 4 byte alignment) | ||
123 | */ | ||
124 | diff = addr - ip; | ||
125 | |||
126 | /* | ||
127 | * Return true if diff is less than 1 << 25 | ||
128 | * and greater than -1 << 26. | ||
129 | */ | ||
130 | return (diff < (1 << 25)) && (diff > (-1 << 26)); | ||
131 | } | ||
132 | |||
133 | int ftrace_make_nop(struct module *mod, | ||
134 | struct dyn_ftrace *rec, unsigned long addr) | ||
135 | { | ||
136 | unsigned char *old, *new; | ||
137 | |||
138 | /* | ||
139 | * If the calling address is more that 24 bits away, | ||
140 | * then we had to use a trampoline to make the call. | ||
141 | * Otherwise just update the call site. | ||
142 | */ | ||
143 | if (test_24bit_addr(rec->ip, addr)) { | ||
144 | /* within range */ | ||
145 | old = ftrace_call_replace(rec->ip, addr); | ||
146 | new = ftrace_nop_replace(); | ||
147 | return ftrace_modify_code(rec->ip, old, new); | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
154 | { | ||
155 | unsigned char *old, *new; | ||
156 | |||
157 | /* | ||
158 | * If the calling address is more that 24 bits away, | ||
159 | * then we had to use a trampoline to make the call. | ||
160 | * Otherwise just update the call site. | ||
161 | */ | ||
162 | if (test_24bit_addr(rec->ip, addr)) { | ||
163 | /* within range */ | ||
164 | old = ftrace_nop_replace(); | ||
165 | new = ftrace_call_replace(rec->ip, addr); | ||
166 | return ftrace_modify_code(rec->ip, old, new); | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
116 | int ftrace_update_ftrace_func(ftrace_func_t func) | 172 | int ftrace_update_ftrace_func(ftrace_func_t func) |
117 | { | 173 | { |
118 | unsigned long ip = (unsigned long)(&ftrace_call); | 174 | unsigned long ip = (unsigned long)(&ftrace_call); |
@@ -128,9 +184,10 @@ int ftrace_update_ftrace_func(ftrace_func_t func) | |||
128 | 184 | ||
129 | int __init ftrace_dyn_arch_init(void *data) | 185 | int __init ftrace_dyn_arch_init(void *data) |
130 | { | 186 | { |
131 | /* This is running in kstop_machine */ | 187 | /* caller expects data to be zero */ |
188 | unsigned long *p = data; | ||
132 | 189 | ||
133 | ftrace_mcount_set(data); | 190 | *p = 0; |
134 | 191 | ||
135 | return 0; | 192 | return 0; |
136 | } | 193 | } |