2019-11-14 22:41:47 +03:00
// SPDX-License-Identifier: GPL-2.0-only
# include <linux/module.h>
# include <linux/kthread.h>
# include <linux/ftrace.h>
2023-04-27 17:07:00 +03:00
# ifndef CONFIG_ARM64
2021-10-12 16:38:02 +03:00
# include <asm/asm-offsets.h>
2023-04-27 17:07:00 +03:00
# endif
2019-11-14 22:41:47 +03:00
2021-12-19 16:53:17 +03:00
extern void my_direct_func1 ( void ) ;
extern void my_direct_func2 ( void ) ;
2019-11-14 22:41:47 +03:00
void my_direct_func1 ( void )
{
trace_printk ( " my direct func1 \n " ) ;
}
void my_direct_func2 ( void )
{
trace_printk ( " my direct func2 \n " ) ;
}
extern void my_tramp1 ( void * ) ;
extern void my_tramp2 ( void * ) ;
static unsigned long my_ip = ( unsigned long ) schedule ;
2023-11-30 15:15:31 +03:00
# ifdef CONFIG_RISCV
# include <asm/asm.h>
asm (
" .pushsection .text, \" ax \" , @progbits \n "
" .type my_tramp1, @function \n "
" .globl my_tramp1 \n "
" my_tramp1: \n "
" addi sp,sp,-2* " SZREG " \n "
" " REG_S " t0,0* " SZREG " (sp) \n "
" " REG_S " ra,1* " SZREG " (sp) \n "
" call my_direct_func1 \n "
" " REG_L " t0,0* " SZREG " (sp) \n "
" " REG_L " ra,1* " SZREG " (sp) \n "
" addi sp,sp,2* " SZREG " \n "
" jr t0 \n "
" .size my_tramp1, .-my_tramp1 \n "
" .type my_tramp2, @function \n "
" .globl my_tramp2 \n "
" my_tramp2: \n "
" addi sp,sp,-2* " SZREG " \n "
" " REG_S " t0,0* " SZREG " (sp) \n "
" " REG_S " ra,1* " SZREG " (sp) \n "
" call my_direct_func2 \n "
" " REG_L " t0,0* " SZREG " (sp) \n "
" " REG_L " ra,1* " SZREG " (sp) \n "
" addi sp,sp,2* " SZREG " \n "
" jr t0 \n "
" .size my_tramp2, .-my_tramp2 \n "
" .popsection \n "
) ;
# endif /* CONFIG_RISCV */
2021-10-12 16:38:02 +03:00
# ifdef CONFIG_X86_64
2022-03-08 18:30:34 +03:00
# include <asm/ibt.h>
2023-01-30 11:59:54 +03:00
# include <asm/nospec-branch.h>
2022-03-08 18:30:34 +03:00
2019-11-14 22:41:47 +03:00
asm (
" .pushsection .text, \" ax \" , @progbits \n "
2020-04-24 23:40:43 +03:00
" .type my_tramp1, @function \n "
2020-11-13 21:34:14 +03:00
" .globl my_tramp1 \n "
2019-11-14 22:41:47 +03:00
" my_tramp1: "
2022-03-08 18:30:34 +03:00
ASM_ENDBR
2019-11-14 22:41:47 +03:00
" pushq %rbp \n "
" movq %rsp, %rbp \n "
2022-09-15 14:11:37 +03:00
CALL_DEPTH_ACCOUNT
2019-11-14 22:41:47 +03:00
" call my_direct_func1 \n "
" leave \n "
2020-04-24 23:40:43 +03:00
" .size my_tramp1, .-my_tramp1 \n "
2021-12-04 16:43:41 +03:00
ASM_RET
2022-03-08 18:30:34 +03:00
2020-04-24 23:40:43 +03:00
" .type my_tramp2, @function \n "
2020-11-13 21:34:14 +03:00
" .globl my_tramp2 \n "
2019-11-14 22:41:47 +03:00
" my_tramp2: "
2022-03-08 18:30:34 +03:00
ASM_ENDBR
2019-11-14 22:41:47 +03:00
" pushq %rbp \n "
" movq %rsp, %rbp \n "
2022-09-15 14:11:37 +03:00
CALL_DEPTH_ACCOUNT
2019-11-14 22:41:47 +03:00
" call my_direct_func2 \n "
" leave \n "
2021-12-04 16:43:41 +03:00
ASM_RET
2020-04-24 23:40:43 +03:00
" .size my_tramp2, .-my_tramp2 \n "
2019-11-14 22:41:47 +03:00
" .popsection \n "
) ;
2021-10-12 16:38:02 +03:00
# endif /* CONFIG_X86_64 */
# ifdef CONFIG_S390
asm (
" .pushsection .text, \" ax \" , @progbits \n "
" .type my_tramp1, @function \n "
" .globl my_tramp1 \n "
" my_tramp1: "
" lgr %r1,%r15 \n "
" stmg %r0,%r5, " __stringify ( __SF_GPRS ) " (%r15) \n "
" stg %r14, " __stringify ( __SF_GPRS + 8 * 8 ) " (%r15) \n "
" aghi %r15, " __stringify ( - STACK_FRAME_OVERHEAD ) " \n "
" stg %r1, " __stringify ( __SF_BACKCHAIN ) " (%r15) \n "
" brasl %r14,my_direct_func1 \n "
" aghi %r15, " __stringify ( STACK_FRAME_OVERHEAD ) " \n "
" lmg %r0,%r5, " __stringify ( __SF_GPRS ) " (%r15) \n "
" lg %r14, " __stringify ( __SF_GPRS + 8 * 8 ) " (%r15) \n "
" lgr %r1,%r0 \n "
" br %r1 \n "
" .size my_tramp1, .-my_tramp1 \n "
" .type my_tramp2, @function \n "
" .globl my_tramp2 \n "
" my_tramp2: "
" lgr %r1,%r15 \n "
" stmg %r0,%r5, " __stringify ( __SF_GPRS ) " (%r15) \n "
" stg %r14, " __stringify ( __SF_GPRS + 8 * 8 ) " (%r15) \n "
" aghi %r15, " __stringify ( - STACK_FRAME_OVERHEAD ) " \n "
" stg %r1, " __stringify ( __SF_BACKCHAIN ) " (%r15) \n "
" brasl %r14,my_direct_func2 \n "
" aghi %r15, " __stringify ( STACK_FRAME_OVERHEAD ) " \n "
" lmg %r0,%r5, " __stringify ( __SF_GPRS ) " (%r15) \n "
" lg %r14, " __stringify ( __SF_GPRS + 8 * 8 ) " (%r15) \n "
" lgr %r1,%r0 \n "
" br %r1 \n "
" .size my_tramp2, .-my_tramp2 \n "
" .popsection \n "
) ;
# endif /* CONFIG_S390 */
2023-04-27 17:07:00 +03:00
# ifdef CONFIG_ARM64
asm (
" .pushsection .text, \" ax \" , @progbits \n "
" .type my_tramp1, @function \n "
" .globl my_tramp1 \n "
" my_tramp1: "
2023-08-20 14:15:09 +03:00
" hint 34 \n " // bti c
2023-04-27 17:07:00 +03:00
" sub sp, sp, #16 \n "
" stp x9, x30, [sp] \n "
" bl my_direct_func1 \n "
" ldp x30, x9, [sp] \n "
" add sp, sp, #16 \n "
" ret x9 \n "
" .size my_tramp1, .-my_tramp1 \n "
" .type my_tramp2, @function \n "
" .globl my_tramp2 \n "
" my_tramp2: "
2023-08-20 14:15:09 +03:00
" hint 34 \n " // bti c
2023-04-27 17:07:00 +03:00
" sub sp, sp, #16 \n "
" stp x9, x30, [sp] \n "
" bl my_direct_func2 \n "
" ldp x30, x9, [sp] \n "
" add sp, sp, #16 \n "
" ret x9 \n "
" .size my_tramp2, .-my_tramp2 \n "
" .popsection \n "
) ;
# endif /* CONFIG_ARM64 */
2023-05-01 12:19:53 +03:00
# ifdef CONFIG_LOONGARCH
asm (
" .pushsection .text, \" ax \" , @progbits \n "
" .type my_tramp1, @function \n "
" .globl my_tramp1 \n "
" my_tramp1: \n "
" addi.d $sp, $sp, -16 \n "
" st.d $t0, $sp, 0 \n "
" st.d $ra, $sp, 8 \n "
" bl my_direct_func1 \n "
" ld.d $t0, $sp, 0 \n "
" ld.d $ra, $sp, 8 \n "
" addi.d $sp, $sp, 16 \n "
" jr $t0 \n "
" .size my_tramp1, .-my_tramp1 \n "
" .type my_tramp2, @function \n "
" .globl my_tramp2 \n "
" my_tramp2: \n "
" addi.d $sp, $sp, -16 \n "
" st.d $t0, $sp, 0 \n "
" st.d $ra, $sp, 8 \n "
" bl my_direct_func2 \n "
" ld.d $t0, $sp, 0 \n "
" ld.d $ra, $sp, 8 \n "
" addi.d $sp, $sp, 16 \n "
" jr $t0 \n "
" .size my_tramp2, .-my_tramp2 \n "
" .popsection \n "
) ;
# endif /* CONFIG_LOONGARCH */
2023-03-21 17:04:19 +03:00
static struct ftrace_ops direct ;
2019-11-14 22:41:47 +03:00
static unsigned long my_tramp = ( unsigned long ) my_tramp1 ;
static unsigned long tramps [ 2 ] = {
( unsigned long ) my_tramp1 ,
( unsigned long ) my_tramp2 ,
} ;
static int simple_thread ( void * arg )
{
static int t ;
int ret = 0 ;
while ( ! kthread_should_stop ( ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_timeout ( 2 * HZ ) ;
if ( ret )
continue ;
t ^ = 1 ;
2023-03-21 17:04:21 +03:00
ret = modify_ftrace_direct ( & direct , tramps [ t ] ) ;
2019-11-14 22:41:47 +03:00
if ( ! ret )
my_tramp = tramps [ t ] ;
WARN_ON_ONCE ( ret ) ;
}
return 0 ;
}
static struct task_struct * simple_tsk ;
static int __init ftrace_direct_init ( void )
{
int ret ;
2023-03-21 17:04:19 +03:00
ftrace_set_filter_ip ( & direct , ( unsigned long ) my_ip , 0 , 0 ) ;
2023-03-21 17:04:21 +03:00
ret = register_ftrace_direct ( & direct , my_tramp ) ;
2023-03-21 17:04:19 +03:00
2019-11-14 22:41:47 +03:00
if ( ! ret )
simple_tsk = kthread_run ( simple_thread , NULL , " event-sample-fn " ) ;
return ret ;
}
static void __exit ftrace_direct_exit ( void )
{
kthread_stop ( simple_tsk ) ;
2023-03-21 17:04:21 +03:00
unregister_ftrace_direct ( & direct , my_tramp , true ) ;
2019-11-14 22:41:47 +03:00
}
module_init ( ftrace_direct_init ) ;
module_exit ( ftrace_direct_exit ) ;
MODULE_AUTHOR ( " Steven Rostedt " ) ;
2023-03-21 17:04:21 +03:00
MODULE_DESCRIPTION ( " Example use case of using modify_ftrace_direct() " ) ;
2019-11-14 22:41:47 +03:00
MODULE_LICENSE ( " GPL " ) ;