mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
powerpc/ftrace: Activate HAVE_DYNAMIC_FTRACE_WITH_REGS on PPC32
Unlike PPC64, PPC32 doesn't require any special compiler option to get _mcount() call not clobbering registers. Provide ftrace_regs_caller() and ftrace_regs_call() and activate HAVE_DYNAMIC_FTRACE_WITH_REGS. That's heavily copied from ftrace_64_mprofile.S For the time being leave livepatching aside, it will come with following patch. Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/1862dc7719855cc2a4eec80920d94c955877557e.1635423081.git.christophe.leroy@csgroup.eu
This commit is contained in:
parent
c93d4f6ecf
commit
7dfbfb87c2
4 changed files with 126 additions and 13 deletions
|
@ -206,7 +206,7 @@ config PPC
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DEBUG_STACKOVERFLOW
|
select HAVE_DEBUG_STACKOVERFLOW
|
||||||
select HAVE_DYNAMIC_FTRACE
|
select HAVE_DYNAMIC_FTRACE
|
||||||
select HAVE_DYNAMIC_FTRACE_WITH_REGS if MPROFILE_KERNEL
|
select HAVE_DYNAMIC_FTRACE_WITH_REGS if MPROFILE_KERNEL || PPC32
|
||||||
select HAVE_EBPF_JIT
|
select HAVE_EBPF_JIT
|
||||||
select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU)
|
select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU)
|
||||||
select HAVE_FAST_GUP
|
select HAVE_FAST_GUP
|
||||||
|
@ -230,7 +230,7 @@ config PPC
|
||||||
select HAVE_KPROBES_ON_FTRACE
|
select HAVE_KPROBES_ON_FTRACE
|
||||||
select HAVE_KRETPROBES
|
select HAVE_KRETPROBES
|
||||||
select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
|
select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
|
||||||
select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS
|
select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS && PPC64
|
||||||
select HAVE_MOD_ARCH_SPECIFIC
|
select HAVE_MOD_ARCH_SPECIFIC
|
||||||
select HAVE_NMI if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
|
select HAVE_NMI if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
|
||||||
select HAVE_OPTPROBES
|
select HAVE_OPTPROBES
|
||||||
|
|
|
@ -306,6 +306,14 @@ int module_finalize_ftrace(struct module *module, const Elf_Shdr *sechdrs)
|
||||||
if (!module->arch.tramp)
|
if (!module->arch.tramp)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||||
|
module->arch.tramp_regs = do_plt_call(module->core_layout.base,
|
||||||
|
(unsigned long)ftrace_regs_caller,
|
||||||
|
sechdrs, module);
|
||||||
|
if (!module->arch.tramp_regs)
|
||||||
|
return -ENOENT;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -561,6 +561,8 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||||
int err;
|
int err;
|
||||||
struct ppc_inst op;
|
struct ppc_inst op;
|
||||||
u32 *ip = (u32 *)rec->ip;
|
u32 *ip = (u32 *)rec->ip;
|
||||||
|
struct module *mod = rec->arch.mod;
|
||||||
|
unsigned long tramp;
|
||||||
|
|
||||||
/* read where this goes */
|
/* read where this goes */
|
||||||
if (copy_inst_from_kernel_nofault(&op, ip))
|
if (copy_inst_from_kernel_nofault(&op, ip))
|
||||||
|
@ -573,13 +575,23 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we never set up a trampoline to ftrace_caller, then bail */
|
/* If we never set up a trampoline to ftrace_caller, then bail */
|
||||||
if (!rec->arch.mod->arch.tramp) {
|
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||||
|
if (!mod->arch.tramp || !mod->arch.tramp_regs) {
|
||||||
|
#else
|
||||||
|
if (!mod->arch.tramp) {
|
||||||
|
#endif
|
||||||
pr_err("No ftrace trampoline\n");
|
pr_err("No ftrace trampoline\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||||
|
if (rec->flags & FTRACE_FL_REGS)
|
||||||
|
tramp = mod->arch.tramp_regs;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
tramp = mod->arch.tramp;
|
||||||
/* create the branch to the trampoline */
|
/* create the branch to the trampoline */
|
||||||
err = create_branch(&op, ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
|
err = create_branch(&op, ip, tramp, BRANCH_SET_LINK);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("REL24 out of range!\n");
|
pr_err("REL24 out of range!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <asm/asm-offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/ftrace.h>
|
#include <asm/ftrace.h>
|
||||||
#include <asm/export.h>
|
#include <asm/export.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
_GLOBAL(mcount)
|
_GLOBAL(mcount)
|
||||||
_GLOBAL(_mcount)
|
_GLOBAL(_mcount)
|
||||||
|
@ -29,17 +30,21 @@ _GLOBAL(ftrace_caller)
|
||||||
MCOUNT_SAVE_FRAME
|
MCOUNT_SAVE_FRAME
|
||||||
/* r3 ends up with link register */
|
/* r3 ends up with link register */
|
||||||
subi r3, r3, MCOUNT_INSN_SIZE
|
subi r3, r3, MCOUNT_INSN_SIZE
|
||||||
|
lis r5,function_trace_op@ha
|
||||||
|
lwz r5,function_trace_op@l(r5)
|
||||||
|
li r6, 0
|
||||||
.globl ftrace_call
|
.globl ftrace_call
|
||||||
ftrace_call:
|
ftrace_call:
|
||||||
bl ftrace_stub
|
bl ftrace_stub
|
||||||
nop
|
nop
|
||||||
|
MCOUNT_RESTORE_FRAME
|
||||||
|
ftrace_caller_common:
|
||||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
.globl ftrace_graph_call
|
.globl ftrace_graph_call
|
||||||
ftrace_graph_call:
|
ftrace_graph_call:
|
||||||
b ftrace_graph_stub
|
b ftrace_graph_stub
|
||||||
_GLOBAL(ftrace_graph_stub)
|
_GLOBAL(ftrace_graph_stub)
|
||||||
#endif
|
#endif
|
||||||
MCOUNT_RESTORE_FRAME
|
|
||||||
/* old link register ends up in ctr reg */
|
/* old link register ends up in ctr reg */
|
||||||
bctr
|
bctr
|
||||||
|
|
||||||
|
@ -47,15 +52,91 @@ _GLOBAL(ftrace_graph_stub)
|
||||||
_GLOBAL(ftrace_stub)
|
_GLOBAL(ftrace_stub)
|
||||||
blr
|
blr
|
||||||
|
|
||||||
|
_GLOBAL(ftrace_regs_caller)
|
||||||
|
/* Save the original return address in A's stack frame */
|
||||||
|
stw r0,LRSAVE(r1)
|
||||||
|
|
||||||
|
/* Create our stack frame + pt_regs */
|
||||||
|
stwu r1,-INT_FRAME_SIZE(r1)
|
||||||
|
|
||||||
|
/* Save all gprs to pt_regs */
|
||||||
|
stw r0, GPR0(r1)
|
||||||
|
stmw r2, GPR2(r1)
|
||||||
|
|
||||||
|
/* Save previous stack pointer (r1) */
|
||||||
|
addi r8, r1, INT_FRAME_SIZE
|
||||||
|
stw r8, GPR1(r1)
|
||||||
|
|
||||||
|
/* Load special regs for save below */
|
||||||
|
mfmsr r8
|
||||||
|
mfctr r9
|
||||||
|
mfxer r10
|
||||||
|
mfcr r11
|
||||||
|
|
||||||
|
/* Get the _mcount() call site out of LR */
|
||||||
|
mflr r7
|
||||||
|
/* Save it as pt_regs->nip */
|
||||||
|
stw r7, _NIP(r1)
|
||||||
|
/* Save the read LR in pt_regs->link */
|
||||||
|
stw r0, _LINK(r1)
|
||||||
|
|
||||||
|
lis r3,function_trace_op@ha
|
||||||
|
lwz r5,function_trace_op@l(r3)
|
||||||
|
|
||||||
|
/* Calculate ip from nip-4 into r3 for call below */
|
||||||
|
subi r3, r7, MCOUNT_INSN_SIZE
|
||||||
|
|
||||||
|
/* Put the original return address in r4 as parent_ip */
|
||||||
|
mr r4, r0
|
||||||
|
|
||||||
|
/* Save special regs */
|
||||||
|
stw r8, _MSR(r1)
|
||||||
|
stw r9, _CTR(r1)
|
||||||
|
stw r10, _XER(r1)
|
||||||
|
stw r11, _CCR(r1)
|
||||||
|
|
||||||
|
/* Load &pt_regs in r6 for call below */
|
||||||
|
addi r6, r1, STACK_FRAME_OVERHEAD
|
||||||
|
|
||||||
|
/* ftrace_call(r3, r4, r5, r6) */
|
||||||
|
.globl ftrace_regs_call
|
||||||
|
ftrace_regs_call:
|
||||||
|
bl ftrace_stub
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* Load ctr with the possibly modified NIP */
|
||||||
|
lwz r3, _NIP(r1)
|
||||||
|
mtctr r3
|
||||||
|
|
||||||
|
/* Restore gprs */
|
||||||
|
lmw r2, GPR2(r1)
|
||||||
|
|
||||||
|
/* Restore possibly modified LR */
|
||||||
|
lwz r0, _LINK(r1)
|
||||||
|
mtlr r0
|
||||||
|
|
||||||
|
/* Pop our stack frame */
|
||||||
|
addi r1, r1, INT_FRAME_SIZE
|
||||||
|
|
||||||
|
b ftrace_caller_common
|
||||||
|
|
||||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
_GLOBAL(ftrace_graph_caller)
|
_GLOBAL(ftrace_graph_caller)
|
||||||
addi r5, r1, 48
|
stwu r1,-48(r1)
|
||||||
/* load r4 with local address */
|
stw r3, 12(r1)
|
||||||
lwz r4, 44(r1)
|
stw r4, 16(r1)
|
||||||
subi r4, r4, MCOUNT_INSN_SIZE
|
stw r5, 20(r1)
|
||||||
|
stw r6, 24(r1)
|
||||||
|
stw r7, 28(r1)
|
||||||
|
stw r8, 32(r1)
|
||||||
|
stw r9, 36(r1)
|
||||||
|
stw r10,40(r1)
|
||||||
|
|
||||||
/* Grab the LR out of the caller stack frame */
|
addi r5, r1, 48
|
||||||
lwz r3,52(r1)
|
mfctr r4 /* ftrace_caller has moved local addr here */
|
||||||
|
stw r4, 44(r1)
|
||||||
|
mflr r3 /* ftrace_caller has restored LR from stack */
|
||||||
|
subi r4, r4, MCOUNT_INSN_SIZE
|
||||||
|
|
||||||
bl prepare_ftrace_return
|
bl prepare_ftrace_return
|
||||||
nop
|
nop
|
||||||
|
@ -65,9 +146,21 @@ _GLOBAL(ftrace_graph_caller)
|
||||||
* Change the LR in the callers stack frame to this.
|
* Change the LR in the callers stack frame to this.
|
||||||
*/
|
*/
|
||||||
stw r3,52(r1)
|
stw r3,52(r1)
|
||||||
|
mtlr r3
|
||||||
|
lwz r0,44(r1)
|
||||||
|
mtctr r0
|
||||||
|
|
||||||
|
lwz r3, 12(r1)
|
||||||
|
lwz r4, 16(r1)
|
||||||
|
lwz r5, 20(r1)
|
||||||
|
lwz r6, 24(r1)
|
||||||
|
lwz r7, 28(r1)
|
||||||
|
lwz r8, 32(r1)
|
||||||
|
lwz r9, 36(r1)
|
||||||
|
lwz r10,40(r1)
|
||||||
|
|
||||||
|
addi r1, r1, 48
|
||||||
|
|
||||||
MCOUNT_RESTORE_FRAME
|
|
||||||
/* old link register ends up in ctr reg */
|
|
||||||
bctr
|
bctr
|
||||||
|
|
||||||
_GLOBAL(return_to_handler)
|
_GLOBAL(return_to_handler)
|
||||||
|
|
Loading…
Reference in a new issue