285 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#include <linux/module.h>3#include <linux/kthread.h>4#include <linux/ftrace.h>5#ifndef CONFIG_ARM646#include <asm/asm-offsets.h>7#endif8 9extern void my_direct_func1(unsigned long ip);10extern void my_direct_func2(unsigned long ip);11 12void my_direct_func1(unsigned long ip)13{14 trace_printk("my direct func1 ip %lx\n", ip);15}16 17void my_direct_func2(unsigned long ip)18{19 trace_printk("my direct func2 ip %lx\n", ip);20}21 22extern void my_tramp1(void *);23extern void my_tramp2(void *);24 25#ifdef CONFIG_RISCV26#include <asm/asm.h>27 28asm (29" .pushsection .text, \"ax\", @progbits\n"30" .type my_tramp1, @function\n"31" .globl my_tramp1\n"32" my_tramp1:\n"33" addi sp,sp,-3*"SZREG"\n"34" "REG_S" a0,0*"SZREG"(sp)\n"35" "REG_S" t0,1*"SZREG"(sp)\n"36" "REG_S" ra,2*"SZREG"(sp)\n"37" mv a0,t0\n"38" call my_direct_func1\n"39" "REG_L" a0,0*"SZREG"(sp)\n"40" "REG_L" t0,1*"SZREG"(sp)\n"41" "REG_L" ra,2*"SZREG"(sp)\n"42" addi sp,sp,3*"SZREG"\n"43" jr t0\n"44" .size my_tramp1, .-my_tramp1\n"45 46" .type my_tramp2, @function\n"47" .globl my_tramp2\n"48" my_tramp2:\n"49" addi sp,sp,-3*"SZREG"\n"50" "REG_S" a0,0*"SZREG"(sp)\n"51" "REG_S" t0,1*"SZREG"(sp)\n"52" "REG_S" ra,2*"SZREG"(sp)\n"53" mv a0,t0\n"54" call my_direct_func2\n"55" "REG_L" a0,0*"SZREG"(sp)\n"56" "REG_L" t0,1*"SZREG"(sp)\n"57" "REG_L" ra,2*"SZREG"(sp)\n"58" addi sp,sp,3*"SZREG"\n"59" jr t0\n"60" .size my_tramp2, .-my_tramp2\n"61" .popsection\n"62);63 64#endif /* CONFIG_RISCV */65 66#ifdef CONFIG_X86_6467 68#include <asm/ibt.h>69#include <asm/nospec-branch.h>70 71asm (72" .pushsection .text, \"ax\", @progbits\n"73" .type my_tramp1, @function\n"74" .globl my_tramp1\n"75" my_tramp1:"76 ASM_ENDBR77" pushq %rbp\n"78" movq %rsp, %rbp\n"79 CALL_DEPTH_ACCOUNT80" pushq %rdi\n"81" movq 8(%rbp), %rdi\n"82" call my_direct_func1\n"83" popq %rdi\n"84" leave\n"85 ASM_RET86" .size my_tramp1, .-my_tramp1\n"87 88" .type my_tramp2, @function\n"89" .globl my_tramp2\n"90" my_tramp2:"91 ASM_ENDBR92" pushq %rbp\n"93" movq %rsp, %rbp\n"94 CALL_DEPTH_ACCOUNT95" pushq %rdi\n"96" movq 8(%rbp), %rdi\n"97" call my_direct_func2\n"98" popq %rdi\n"99" leave\n"100 ASM_RET101" .size my_tramp2, .-my_tramp2\n"102" .popsection\n"103);104 105#endif /* CONFIG_X86_64 */106 107#ifdef CONFIG_S390108 109asm (110" .pushsection .text, \"ax\", @progbits\n"111" .type my_tramp1, @function\n"112" .globl my_tramp1\n"113" my_tramp1:"114" lgr %r1,%r15\n"115" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"116" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"117" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"118" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"119" lgr %r2,%r0\n"120" brasl %r14,my_direct_func1\n"121" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"122" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"123" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"124" lgr %r1,%r0\n"125" br %r1\n"126" .size my_tramp1, .-my_tramp1\n"127"\n"128" .type my_tramp2, @function\n"129" .globl my_tramp2\n"130" my_tramp2:"131" lgr %r1,%r15\n"132" stmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"133" stg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"134" aghi %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"135" stg %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"136" lgr %r2,%r0\n"137" brasl %r14,my_direct_func2\n"138" aghi %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"139" lmg %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"140" lg %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"141" lgr %r1,%r0\n"142" br %r1\n"143" .size my_tramp2, .-my_tramp2\n"144" .popsection\n"145);146 147#endif /* CONFIG_S390 */148 149#ifdef CONFIG_ARM64150 151asm (152" .pushsection .text, \"ax\", @progbits\n"153" .type my_tramp1, @function\n"154" .globl my_tramp1\n"155" my_tramp1:"156" hint 34\n" // bti c157" sub sp, sp, #32\n"158" stp x9, x30, [sp]\n"159" str x0, [sp, #16]\n"160" mov x0, x30\n"161" bl my_direct_func1\n"162" ldp x30, x9, [sp]\n"163" ldr x0, [sp, #16]\n"164" add sp, sp, #32\n"165" ret x9\n"166" .size my_tramp1, .-my_tramp1\n"167 168" .type my_tramp2, @function\n"169" .globl my_tramp2\n"170" my_tramp2:"171" hint 34\n" // bti c172" sub sp, sp, #32\n"173" stp x9, x30, [sp]\n"174" str x0, [sp, #16]\n"175" mov x0, x30\n"176" bl my_direct_func2\n"177" ldp x30, x9, [sp]\n"178" ldr x0, [sp, #16]\n"179" add sp, sp, #32\n"180" ret x9\n"181" .size my_tramp2, .-my_tramp2\n"182" .popsection\n"183);184 185#endif /* CONFIG_ARM64 */186 187#ifdef CONFIG_LOONGARCH188#include <asm/asm.h>189 190asm (191" .pushsection .text, \"ax\", @progbits\n"192" .type my_tramp1, @function\n"193" .globl my_tramp1\n"194" my_tramp1:\n"195" addi.d $sp, $sp, -32\n"196" st.d $a0, $sp, 0\n"197" st.d $t0, $sp, 8\n"198" st.d $ra, $sp, 16\n"199" move $a0, $t0\n"200" bl my_direct_func1\n"201" ld.d $a0, $sp, 0\n"202" ld.d $t0, $sp, 8\n"203" ld.d $ra, $sp, 16\n"204" addi.d $sp, $sp, 32\n"205" jr $t0\n"206" .size my_tramp1, .-my_tramp1\n"207 208" .type my_tramp2, @function\n"209" .globl my_tramp2\n"210" my_tramp2:\n"211" addi.d $sp, $sp, -32\n"212" st.d $a0, $sp, 0\n"213" st.d $t0, $sp, 8\n"214" st.d $ra, $sp, 16\n"215" move $a0, $t0\n"216" bl my_direct_func2\n"217" ld.d $a0, $sp, 0\n"218" ld.d $t0, $sp, 8\n"219" ld.d $ra, $sp, 16\n"220" addi.d $sp, $sp, 32\n"221" jr $t0\n"222" .size my_tramp2, .-my_tramp2\n"223" .popsection\n"224);225 226#endif /* CONFIG_LOONGARCH */227 228static unsigned long my_tramp = (unsigned long)my_tramp1;229static unsigned long tramps[2] = {230 (unsigned long)my_tramp1,231 (unsigned long)my_tramp2,232};233 234static struct ftrace_ops direct;235 236static int simple_thread(void *arg)237{238 static int t;239 int ret = 0;240 241 while (!kthread_should_stop()) {242 set_current_state(TASK_INTERRUPTIBLE);243 schedule_timeout(2 * HZ);244 245 if (ret)246 continue;247 t ^= 1;248 ret = modify_ftrace_direct(&direct, tramps[t]);249 if (!ret)250 my_tramp = tramps[t];251 WARN_ON_ONCE(ret);252 }253 254 return 0;255}256 257static struct task_struct *simple_tsk;258 259static int __init ftrace_direct_multi_init(void)260{261 int ret;262 263 ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);264 ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);265 266 ret = register_ftrace_direct(&direct, my_tramp);267 268 if (!ret)269 simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");270 return ret;271}272 273static void __exit ftrace_direct_multi_exit(void)274{275 kthread_stop(simple_tsk);276 unregister_ftrace_direct(&direct, my_tramp, true);277}278 279module_init(ftrace_direct_multi_init);280module_exit(ftrace_direct_multi_exit);281 282MODULE_AUTHOR("Jiri Olsa");283MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct()");284MODULE_LICENSE("GPL");285