Skip to content

Commit 33bb8a0

Browse files
rnavmpe
authored andcommitted
powerpc/ftrace: Stop re-purposing linker generated long branches for ftrace
Commit 67361cf ("powerpc/ftrace: Handle large kernel configs") added ftrace support for ppc64 kernel images with a text section larger than 32MB. The patch did two things: 1. Add stubs at the end of .text to branch into ftrace_[regs_]caller for functions that were out of branch range. 2. Re-purpose linker-generated long branches to _mcount to instead branch to ftrace_[regs_]caller. Before that, we only supported kernel .text up to ~32MB. With the above, we now support up to ~96MB: - The first 32MB of kernel text can branch directly into ftrace_[regs_]caller since that symbol is usually at the beginning. - The modified long_branch from (2) above is used by the next 32MB of kernel text. - The next 32MB of kernel text can use the stub at the end of text to branch back to ftrace_[regs_]caller. While re-purposing the long branch works in practice, it still restricts ftrace to kernel text up to ~96MB. The stub at the end of kernel text from (1) already enables us to extend ftrace support for kernel text up to 64MB, which fulfils the original requirement. Further, once we switch to -fpatchable-function-entry, there will not be a long branch that we can use. Stop re-purposing the linker-generated long branches for ftrace to simplify the code. If there are good reasons to support ftrace on kernels beyond 64MB, we can consider adding support by using -fpatchable-function-entry. Signed-off-by: Naveen N Rao <naveen@kernel.org> Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/33fa3be97f8e1f2171254ef2e1b0d5c8836c11fd.1687166935.git.naveen@kernel.org
1 parent f4fcbf2 commit 33bb8a0

1 file changed

Lines changed: 17 additions & 93 deletions

File tree

arch/powerpc/kernel/trace/ftrace.c

Lines changed: 17 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@
2828
#include <asm/syscall.h>
2929
#include <asm/inst.h>
3030

31-
/*
32-
* We generally only have a single long_branch tramp and at most 2 or 3 plt
33-
* tramps generated. But, we don't use the plt tramps currently. We also allot
34-
* 2 tramps after .text and .init.text. So, we only end up with around 3 usable
35-
* tramps in total. Set aside 8 just to be sure.
36-
*/
37-
#define NUM_FTRACE_TRAMPS 8
31+
#define NUM_FTRACE_TRAMPS 2
3832
static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS];
3933

4034
static ppc_inst_t
@@ -100,11 +94,6 @@ static int is_bl_op(ppc_inst_t op)
10094
return (ppc_inst_val(op) & ~PPC_LI_MASK) == PPC_RAW_BL(0);
10195
}
10296

103-
static int is_b_op(ppc_inst_t op)
104-
{
105-
return (ppc_inst_val(op) & ~PPC_LI_MASK) == PPC_RAW_BRANCH(0);
106-
}
107-
10897
static unsigned long find_bl_target(unsigned long ip, ppc_inst_t op)
10998
{
11099
int offset;
@@ -227,11 +216,7 @@ static unsigned long find_ftrace_tramp(unsigned long ip)
227216
{
228217
int i;
229218

230-
/*
231-
* We have the compiler generated long_branch tramps at the end
232-
* and we prefer those
233-
*/
234-
for (i = NUM_FTRACE_TRAMPS - 1; i >= 0; i--)
219+
for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
235220
if (!ftrace_tramps[i])
236221
continue;
237222
else if (is_offset_in_branch_range(ftrace_tramps[i] - ip))
@@ -240,75 +225,6 @@ static unsigned long find_ftrace_tramp(unsigned long ip)
240225
return 0;
241226
}
242227

243-
static int add_ftrace_tramp(unsigned long tramp)
244-
{
245-
int i;
246-
247-
for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
248-
if (!ftrace_tramps[i]) {
249-
ftrace_tramps[i] = tramp;
250-
return 0;
251-
}
252-
253-
return -1;
254-
}
255-
256-
/*
257-
* If this is a compiler generated long_branch trampoline (essentially, a
258-
* trampoline that has a branch to _mcount()), we re-write the branch to
259-
* instead go to ftrace_[regs_]caller() and note down the location of this
260-
* trampoline.
261-
*/
262-
static int setup_mcount_compiler_tramp(unsigned long tramp)
263-
{
264-
int i;
265-
ppc_inst_t op;
266-
unsigned long ptr;
267-
268-
/* Is this a known long jump tramp? */
269-
for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
270-
if (ftrace_tramps[i] == tramp)
271-
return 0;
272-
273-
/* New trampoline -- read where this goes */
274-
if (copy_inst_from_kernel_nofault(&op, (void *)tramp)) {
275-
pr_debug("Fetching opcode failed.\n");
276-
return -1;
277-
}
278-
279-
/* Is this a 24 bit branch? */
280-
if (!is_b_op(op)) {
281-
pr_debug("Trampoline is not a long branch tramp.\n");
282-
return -1;
283-
}
284-
285-
/* lets find where the pointer goes */
286-
ptr = find_bl_target(tramp, op);
287-
288-
if (ptr != ppc_global_function_entry((void *)_mcount)) {
289-
pr_debug("Trampoline target %p is not _mcount\n", (void *)ptr);
290-
return -1;
291-
}
292-
293-
/* Let's re-write the tramp to go to ftrace_[regs_]caller */
294-
if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
295-
ptr = ppc_global_function_entry((void *)ftrace_regs_caller);
296-
else
297-
ptr = ppc_global_function_entry((void *)ftrace_caller);
298-
299-
if (patch_branch((u32 *)tramp, ptr, 0)) {
300-
pr_debug("REL24 out of range!\n");
301-
return -1;
302-
}
303-
304-
if (add_ftrace_tramp(tramp)) {
305-
pr_debug("No tramp locations left\n");
306-
return -1;
307-
}
308-
309-
return 0;
310-
}
311-
312228
static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
313229
{
314230
unsigned long tramp, ip = rec->ip;
@@ -331,13 +247,10 @@ static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
331247

332248
pr_devel("ip:%lx jumps to %lx", ip, tramp);
333249

334-
if (setup_mcount_compiler_tramp(tramp)) {
335-
/* Are other trampolines reachable? */
336-
if (!find_ftrace_tramp(ip)) {
337-
pr_err("No ftrace trampolines reachable from %ps\n",
338-
(void *)ip);
339-
return -EINVAL;
340-
}
250+
/* Are ftrace trampolines reachable? */
251+
if (!find_ftrace_tramp(ip)) {
252+
pr_err("No ftrace trampolines reachable from %ps\n", (void *)ip);
253+
return -EINVAL;
341254
}
342255

343256
if (patch_instruction((u32 *)ip, ppc_inst(PPC_RAW_NOP()))) {
@@ -725,6 +638,17 @@ void ftrace_free_init_tramp(void)
725638
}
726639
}
727640

641+
static void __init add_ftrace_tramp(unsigned long tramp)
642+
{
643+
int i;
644+
645+
for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
646+
if (!ftrace_tramps[i]) {
647+
ftrace_tramps[i] = tramp;
648+
return;
649+
}
650+
}
651+
728652
int __init ftrace_dyn_arch_init(void)
729653
{
730654
unsigned int *tramp[] = { ftrace_tramp_text, ftrace_tramp_init };

0 commit comments

Comments
 (0)