Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Christophe Leroy and committed by
Michael Ellerman
7dfbfb87 c93d4f6e

+126 -13
+2 -2
arch/powerpc/Kconfig
··· 206 206 select HAVE_DEBUG_KMEMLEAK 207 207 select HAVE_DEBUG_STACKOVERFLOW 208 208 select HAVE_DYNAMIC_FTRACE 209 - select HAVE_DYNAMIC_FTRACE_WITH_REGS if MPROFILE_KERNEL 209 + select HAVE_DYNAMIC_FTRACE_WITH_REGS if MPROFILE_KERNEL || PPC32 210 210 select HAVE_EBPF_JIT 211 211 select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU) 212 212 select HAVE_FAST_GUP ··· 230 230 select HAVE_KPROBES_ON_FTRACE 231 231 select HAVE_KRETPROBES 232 232 select HAVE_LD_DEAD_CODE_DATA_ELIMINATION 233 - select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS 233 + select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS && PPC64 234 234 select HAVE_MOD_ARCH_SPECIFIC 235 235 select HAVE_NMI if PERF_EVENTS || (PPC64 && PPC_BOOK3S) 236 236 select HAVE_OPTPROBES
+8
arch/powerpc/kernel/module_32.c
··· 306 306 if (!module->arch.tramp) 307 307 return -ENOENT; 308 308 309 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 310 + module->arch.tramp_regs = do_plt_call(module->core_layout.base, 311 + (unsigned long)ftrace_regs_caller, 312 + sechdrs, module); 313 + if (!module->arch.tramp_regs) 314 + return -ENOENT; 315 + #endif 316 + 309 317 return 0; 310 318 } 311 319 #endif
+14 -2
arch/powerpc/kernel/trace/ftrace.c
··· 561 561 int err; 562 562 struct ppc_inst op; 563 563 u32 *ip = (u32 *)rec->ip; 564 + struct module *mod = rec->arch.mod; 565 + unsigned long tramp; 564 566 565 567 /* read where this goes */ 566 568 if (copy_inst_from_kernel_nofault(&op, ip)) ··· 575 573 } 576 574 577 575 /* If we never set up a trampoline to ftrace_caller, then bail */ 578 - if (!rec->arch.mod->arch.tramp) { 576 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 577 + if (!mod->arch.tramp || !mod->arch.tramp_regs) { 578 + #else 579 + if (!mod->arch.tramp) { 580 + #endif 579 581 pr_err("No ftrace trampoline\n"); 580 582 return -EINVAL; 581 583 } 582 584 585 + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 586 + if (rec->flags & FTRACE_FL_REGS) 587 + tramp = mod->arch.tramp_regs; 588 + else 589 + #endif 590 + tramp = mod->arch.tramp; 583 591 /* create the branch to the trampoline */ 584 - err = create_branch(&op, ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK); 592 + err = create_branch(&op, ip, tramp, BRANCH_SET_LINK); 585 593 if (err) { 586 594 pr_err("REL24 out of range!\n"); 587 595 return -EINVAL;
+102 -9
arch/powerpc/kernel/trace/ftrace_32.S
··· 9 9 #include <asm/asm-offsets.h> 10 10 #include <asm/ftrace.h> 11 11 #include <asm/export.h> 12 + #include <asm/ptrace.h> 12 13 13 14 _GLOBAL(mcount) 14 15 _GLOBAL(_mcount) ··· 30 29 MCOUNT_SAVE_FRAME 31 30 /* r3 ends up with link register */ 32 31 subi r3, r3, MCOUNT_INSN_SIZE 32 + lis r5,function_trace_op@ha 33 + lwz r5,function_trace_op@l(r5) 34 + li r6, 0 33 35 .globl ftrace_call 34 36 ftrace_call: 35 37 bl ftrace_stub 36 38 nop 39 + MCOUNT_RESTORE_FRAME 40 + ftrace_caller_common: 37 41 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 38 42 .globl ftrace_graph_call 39 43 ftrace_graph_call: 40 44 b ftrace_graph_stub 41 45 _GLOBAL(ftrace_graph_stub) 42 46 #endif 43 - MCOUNT_RESTORE_FRAME 44 47 /* old link register ends up in ctr reg */ 45 48 bctr 46 49 ··· 52 47 _GLOBAL(ftrace_stub) 53 48 blr 54 49 50 + _GLOBAL(ftrace_regs_caller) 51 + /* Save the original return address in A's stack frame */ 52 + stw r0,LRSAVE(r1) 53 + 54 + /* Create our stack frame + pt_regs */ 55 + stwu r1,-INT_FRAME_SIZE(r1) 56 + 57 + /* Save all gprs to pt_regs */ 58 + stw r0, GPR0(r1) 59 + stmw r2, GPR2(r1) 60 + 61 + /* Save previous stack pointer (r1) */ 62 + addi r8, r1, INT_FRAME_SIZE 63 + stw r8, GPR1(r1) 64 + 65 + /* Load special regs for save below */ 66 + mfmsr r8 67 + mfctr r9 68 + mfxer r10 69 + mfcr r11 70 + 71 + /* Get the _mcount() call site out of LR */ 72 + mflr r7 73 + /* Save it as pt_regs->nip */ 74 + stw r7, _NIP(r1) 75 + /* Save the read LR in pt_regs->link */ 76 + stw r0, _LINK(r1) 77 + 78 + lis r3,function_trace_op@ha 79 + lwz r5,function_trace_op@l(r3) 80 + 81 + /* Calculate ip from nip-4 into r3 for call below */ 82 + subi r3, r7, MCOUNT_INSN_SIZE 83 + 84 + /* Put the original return address in r4 as parent_ip */ 85 + mr r4, r0 86 + 87 + /* Save special regs */ 88 + stw r8, _MSR(r1) 89 + stw r9, _CTR(r1) 90 + stw r10, _XER(r1) 91 + stw r11, _CCR(r1) 92 + 93 + /* Load &pt_regs in r6 for call below */ 94 + addi r6, r1, STACK_FRAME_OVERHEAD 95 + 96 + /* ftrace_call(r3, r4, r5, r6) */ 97 + .globl ftrace_regs_call 98 + ftrace_regs_call: 99 + bl ftrace_stub 100 + nop 101 + 102 + /* Load ctr with the possibly modified NIP */ 103 + lwz r3, _NIP(r1) 104 + mtctr r3 105 + 106 + /* Restore gprs */ 107 + lmw r2, GPR2(r1) 108 + 109 + /* Restore possibly modified LR */ 110 + lwz r0, _LINK(r1) 111 + mtlr r0 112 + 113 + /* Pop our stack frame */ 114 + addi r1, r1, INT_FRAME_SIZE 115 + 116 + b ftrace_caller_common 117 + 55 118 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 56 119 _GLOBAL(ftrace_graph_caller) 57 - addi r5, r1, 48 58 - /* load r4 with local address */ 59 - lwz r4, 44(r1) 60 - subi r4, r4, MCOUNT_INSN_SIZE 120 + stwu r1,-48(r1) 121 + stw r3, 12(r1) 122 + stw r4, 16(r1) 123 + stw r5, 20(r1) 124 + stw r6, 24(r1) 125 + stw r7, 28(r1) 126 + stw r8, 32(r1) 127 + stw r9, 36(r1) 128 + stw r10,40(r1) 61 129 62 - /* Grab the LR out of the caller stack frame */ 63 - lwz r3,52(r1) 130 + addi r5, r1, 48 131 + mfctr r4 /* ftrace_caller has moved local addr here */ 132 + stw r4, 44(r1) 133 + mflr r3 /* ftrace_caller has restored LR from stack */ 134 + subi r4, r4, MCOUNT_INSN_SIZE 64 135 65 136 bl prepare_ftrace_return 66 137 nop ··· 146 65 * Change the LR in the callers stack frame to this. 147 66 */ 148 67 stw r3,52(r1) 68 + mtlr r3 69 + lwz r0,44(r1) 70 + mtctr r0 149 71 150 - MCOUNT_RESTORE_FRAME 151 - /* old link register ends up in ctr reg */ 72 + lwz r3, 12(r1) 73 + lwz r4, 16(r1) 74 + lwz r5, 20(r1) 75 + lwz r6, 24(r1) 76 + lwz r7, 28(r1) 77 + lwz r8, 32(r1) 78 + lwz r9, 36(r1) 79 + lwz r10,40(r1) 80 + 81 + addi r1, r1, 48 82 + 152 83 bctr 153 84 154 85 _GLOBAL(return_to_handler)