1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/module.h> 3 #include <linux/kthread.h> 4 #include <linux/ftrace.h> 5 #if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32) 6 #include <asm/asm-offsets.h> 7 #endif 8 9 extern void my_direct_func1(unsigned long ip); 10 extern void my_direct_func2(unsigned long ip); 11 12 void my_direct_func1(unsigned long ip) 13 { 14 trace_printk("my direct func1 ip %lx\n", ip); 15 } 16 17 void my_direct_func2(unsigned long ip) 18 { 19 trace_printk("my direct func2 ip %lx\n", ip); 20 } 21 22 extern void my_tramp1(void *); 23 extern void my_tramp2(void *); 24 25 #ifdef CONFIG_RISCV 26 #include <asm/asm.h> 27 28 asm ( 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_64 67 68 #include <asm/ibt.h> 69 #include <asm/nospec-branch.h> 70 71 asm ( 72 " .pushsection .text, \"ax\", @progbits\n" 73 " .type my_tramp1, @function\n" 74 " .globl my_tramp1\n" 75 " my_tramp1:" 76 ASM_ENDBR 77 " pushq %rbp\n" 78 " movq %rsp, %rbp\n" 79 CALL_DEPTH_ACCOUNT 80 " pushq %rdi\n" 81 " movq 8(%rbp), %rdi\n" 82 " call my_direct_func1\n" 83 " popq %rdi\n" 84 " leave\n" 85 ASM_RET 86 " .size my_tramp1, .-my_tramp1\n" 87 88 " .type my_tramp2, @function\n" 89 " .globl my_tramp2\n" 90 " my_tramp2:" 91 ASM_ENDBR 92 " pushq %rbp\n" 93 " movq %rsp, %rbp\n" 94 CALL_DEPTH_ACCOUNT 95 " pushq %rdi\n" 96 " movq 8(%rbp), %rdi\n" 97 " call my_direct_func2\n" 98 " popq %rdi\n" 99 " leave\n" 100 ASM_RET 101 " .size my_tramp2, .-my_tramp2\n" 102 " .popsection\n" 103 ); 104 105 #endif /* CONFIG_X86_64 */ 106 107 #ifdef CONFIG_S390 108 109 asm ( 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_ARM64 150 151 asm ( 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 c 157 " 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 c 172 " 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_LOONGARCH 188 #include <asm/asm.h> 189 190 asm ( 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 228 #ifdef CONFIG_PPC 229 #include <asm/ppc_asm.h> 230 231 #ifdef CONFIG_PPC64 232 #define STACK_FRAME_SIZE 48 233 #else 234 #define STACK_FRAME_SIZE 24 235 #endif 236 237 #if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL) 238 #define PPC64_TOC_SAVE_AND_UPDATE \ 239 " std 2, 24(1)\n" \ 240 " bcl 20, 31, 1f\n" \ 241 " 1: mflr 12\n" \ 242 " ld 2, (99f - 1b)(12)\n" 243 #define PPC64_TOC_RESTORE \ 244 " ld 2, 24(1)\n" 245 #define PPC64_TOC \ 246 " 99: .quad .TOC.@tocbase\n" 247 #else 248 #define PPC64_TOC_SAVE_AND_UPDATE "" 249 #define PPC64_TOC_RESTORE "" 250 #define PPC64_TOC "" 251 #endif 252 253 #ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE 254 #define PPC_FTRACE_RESTORE_LR \ 255 PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ 256 " mtlr 0\n" 257 #define PPC_FTRACE_RET \ 258 " blr\n" 259 #define PPC_FTRACE_RECOVER_IP \ 260 " lwz 8, 4(3)\n" \ 261 " li 9, 6\n" \ 262 " slw 8, 8, 9\n" \ 263 " sraw 8, 8, 9\n" \ 264 " add 3, 3, 8\n" \ 265 " addi 3, 3, 4\n" 266 #else 267 #define PPC_FTRACE_RESTORE_LR \ 268 PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ 269 " mtctr 0\n" 270 #define PPC_FTRACE_RET \ 271 " mtlr 0\n" \ 272 " bctr\n" 273 #define PPC_FTRACE_RECOVER_IP "" 274 #endif 275 276 asm ( 277 " .pushsection .text, \"ax\", @progbits\n" 278 " .type my_tramp1, @function\n" 279 " .globl my_tramp1\n" 280 " my_tramp1:\n" 281 PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" 282 PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" 283 " mflr 0\n" 284 PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" 285 PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" 286 PPC64_TOC_SAVE_AND_UPDATE 287 PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" 288 " mr 3, 0\n" 289 PPC_FTRACE_RECOVER_IP 290 " bl my_direct_func1\n" 291 PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" 292 PPC64_TOC_RESTORE 293 " addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" 294 PPC_FTRACE_RESTORE_LR 295 " addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" 296 PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" 297 PPC_FTRACE_RET 298 " .size my_tramp1, .-my_tramp1\n" 299 300 " .type my_tramp2, @function\n" 301 " .globl my_tramp2\n" 302 " my_tramp2:\n" 303 PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" 304 PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" 305 " mflr 0\n" 306 PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" 307 PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" 308 PPC64_TOC_SAVE_AND_UPDATE 309 PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" 310 " mr 3, 0\n" 311 PPC_FTRACE_RECOVER_IP 312 " bl my_direct_func2\n" 313 PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" 314 PPC64_TOC_RESTORE 315 " addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" 316 PPC_FTRACE_RESTORE_LR 317 " addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" 318 PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" 319 PPC_FTRACE_RET 320 PPC64_TOC 321 " .size my_tramp2, .-my_tramp2\n" 322 " .popsection\n" 323 ); 324 325 #endif /* CONFIG_PPC */ 326 327 static unsigned long my_tramp = (unsigned long)my_tramp1; 328 static unsigned long tramps[2] = { 329 (unsigned long)my_tramp1, 330 (unsigned long)my_tramp2, 331 }; 332 333 static struct ftrace_ops direct; 334 335 static int simple_thread(void *arg) 336 { 337 static int t; 338 int ret = 0; 339 340 while (!kthread_should_stop()) { 341 set_current_state(TASK_INTERRUPTIBLE); 342 schedule_timeout(2 * HZ); 343 344 if (ret) 345 continue; 346 t ^= 1; 347 ret = modify_ftrace_direct(&direct, tramps[t]); 348 if (!ret) 349 my_tramp = tramps[t]; 350 WARN_ON_ONCE(ret); 351 } 352 353 return 0; 354 } 355 356 static struct task_struct *simple_tsk; 357 358 static int __init ftrace_direct_multi_init(void) 359 { 360 int ret; 361 362 ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0); 363 ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0); 364 365 ret = register_ftrace_direct(&direct, my_tramp); 366 367 if (!ret) 368 simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn"); 369 return ret; 370 } 371 372 static void __exit ftrace_direct_multi_exit(void) 373 { 374 kthread_stop(simple_tsk); 375 unregister_ftrace_direct(&direct, my_tramp, true); 376 } 377 378 module_init(ftrace_direct_multi_init); 379 module_exit(ftrace_direct_multi_exit); 380 381 MODULE_AUTHOR("Jiri Olsa"); 382 MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct()"); 383 MODULE_LICENSE("GPL"); 384