1313#include <asm/patch.h>
1414#include "bpf_jit.h"
1515
16+ #define RV_FENTRY_NINSNS 2
17+
1618#define RV_REG_TCC RV_REG_A6
1719#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */
1820
@@ -241,7 +243,7 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
241243 if (!is_tail_call )
242244 emit_mv (RV_REG_A0 , RV_REG_A5 , ctx );
243245 emit_jalr (RV_REG_ZERO , is_tail_call ? RV_REG_T3 : RV_REG_RA ,
244- is_tail_call ? 20 : 0 , /* skip reserved nops and TCC init */
246+ is_tail_call ? ( RV_FENTRY_NINSNS + 1 ) * 4 : 0 , /* skip reserved nops and TCC init */
245247 ctx );
246248}
247249
@@ -618,32 +620,7 @@ static int add_exception_handler(const struct bpf_insn *insn,
618620 return 0 ;
619621}
620622
621- static int gen_call_or_nops (void * target , void * ip , u32 * insns )
622- {
623- s64 rvoff ;
624- int i , ret ;
625- struct rv_jit_context ctx ;
626-
627- ctx .ninsns = 0 ;
628- ctx .insns = (u16 * )insns ;
629-
630- if (!target ) {
631- for (i = 0 ; i < 4 ; i ++ )
632- emit (rv_nop (), & ctx );
633- return 0 ;
634- }
635-
636- rvoff = (s64 )(target - (ip + 4 ));
637- emit (rv_sd (RV_REG_SP , -8 , RV_REG_RA ), & ctx );
638- ret = emit_jump_and_link (RV_REG_RA , rvoff , false, & ctx );
639- if (ret )
640- return ret ;
641- emit (rv_ld (RV_REG_RA , -8 , RV_REG_SP ), & ctx );
642-
643- return 0 ;
644- }
645-
646- static int gen_jump_or_nops (void * target , void * ip , u32 * insns )
623+ static int gen_jump_or_nops (void * target , void * ip , u32 * insns , bool is_call )
647624{
648625 s64 rvoff ;
649626 struct rv_jit_context ctx ;
@@ -658,38 +635,35 @@ static int gen_jump_or_nops(void *target, void *ip, u32 *insns)
658635 }
659636
660637 rvoff = (s64 )(target - ip );
661- return emit_jump_and_link (RV_REG_ZERO , rvoff , false, & ctx );
638+ return emit_jump_and_link (is_call ? RV_REG_T0 : RV_REG_ZERO , rvoff , false, & ctx );
662639}
663640
664641int bpf_arch_text_poke (void * ip , enum bpf_text_poke_type poke_type ,
665642 void * old_addr , void * new_addr )
666643{
667- u32 old_insns [4 ], new_insns [4 ];
644+ u32 old_insns [RV_FENTRY_NINSNS ], new_insns [RV_FENTRY_NINSNS ];
668645 bool is_call = poke_type == BPF_MOD_CALL ;
669- int (* gen_insns )(void * target , void * ip , u32 * insns );
670- int ninsns = is_call ? 4 : 2 ;
671646 int ret ;
672647
673- if (!is_bpf_text_address ((unsigned long )ip ))
648+ if (!is_kernel_text ((unsigned long )ip ) &&
649+ !is_bpf_text_address ((unsigned long )ip ))
674650 return - ENOTSUPP ;
675651
676- gen_insns = is_call ? gen_call_or_nops : gen_jump_or_nops ;
677-
678- ret = gen_insns (old_addr , ip , old_insns );
652+ ret = gen_jump_or_nops (old_addr , ip , old_insns , is_call );
679653 if (ret )
680654 return ret ;
681655
682- if (memcmp (ip , old_insns , ninsns * 4 ))
656+ if (memcmp (ip , old_insns , RV_FENTRY_NINSNS * 4 ))
683657 return - EFAULT ;
684658
685- ret = gen_insns (new_addr , ip , new_insns );
659+ ret = gen_jump_or_nops (new_addr , ip , new_insns , is_call );
686660 if (ret )
687661 return ret ;
688662
689663 cpus_read_lock ();
690664 mutex_lock (& text_mutex );
691- if (memcmp (ip , new_insns , ninsns * 4 ))
692- ret = patch_text (ip , new_insns , ninsns );
665+ if (memcmp (ip , new_insns , RV_FENTRY_NINSNS * 4 ))
666+ ret = patch_text (ip , new_insns , RV_FENTRY_NINSNS );
693667 mutex_unlock (& text_mutex );
694668 cpus_read_unlock ();
695669
@@ -787,22 +761,35 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
787761 int i , ret , offset ;
788762 int * branches_off = NULL ;
789763 int stack_size = 0 , nregs = m -> nr_args ;
790- int retaddr_off , fp_off , retval_off , args_off ;
791- int nregs_off , ip_off , run_ctx_off , sreg_off ;
764+ int retval_off , args_off , nregs_off , ip_off , run_ctx_off , sreg_off ;
792765 struct bpf_tramp_links * fentry = & tlinks [BPF_TRAMP_FENTRY ];
793766 struct bpf_tramp_links * fexit = & tlinks [BPF_TRAMP_FEXIT ];
794767 struct bpf_tramp_links * fmod_ret = & tlinks [BPF_TRAMP_MODIFY_RETURN ];
795768 void * orig_call = func_addr ;
796769 bool save_ret ;
797770 u32 insn ;
798771
799- /* Generated trampoline stack layout:
772+ /* Two types of generated trampoline stack layout:
773+ *
774+ * 1. trampoline called from function entry
775+ * --------------------------------------
776+ * FP + 8 [ RA to parent func ] return address to parent
777+ * function
778+ * FP + 0 [ FP of parent func ] frame pointer of parent
779+ * function
780+ * FP - 8 [ T0 to traced func ] return address of traced
781+ * function
782+ * FP - 16 [ FP of traced func ] frame pointer of traced
783+ * function
784+ * --------------------------------------
800785 *
801- * FP - 8 [ RA of parent func ] return address of parent
786+ * 2. trampoline called directly
787+ * --------------------------------------
788+ * FP - 8 [ RA to caller func ] return address to caller
802789 * function
803- * FP - retaddr_off [ RA of traced func ] return address of traced
790+ * FP - 16 [ FP of caller func ] frame pointer of caller
804791 * function
805- * FP - fp_off [ FP of parent func ]
792+ * --------------------------------------
806793 *
807794 * FP - retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
808795 * BPF_TRAMP_F_RET_FENTRY_RET
@@ -833,14 +820,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
833820 if (nregs > 8 )
834821 return - ENOTSUPP ;
835822
836- /* room for parent function return address */
837- stack_size += 8 ;
838-
839- stack_size += 8 ;
840- retaddr_off = stack_size ;
841-
842- stack_size += 8 ;
843- fp_off = stack_size ;
823+ /* room of trampoline frame to store return address and frame pointer */
824+ stack_size += 16 ;
844825
845826 save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET );
846827 if (save_ret ) {
@@ -867,12 +848,29 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
867848
868849 stack_size = round_up (stack_size , 16 );
869850
870- emit_addi (RV_REG_SP , RV_REG_SP , - stack_size , ctx );
871-
872- emit_sd (RV_REG_SP , stack_size - retaddr_off , RV_REG_RA , ctx );
873- emit_sd (RV_REG_SP , stack_size - fp_off , RV_REG_FP , ctx );
874-
875- emit_addi (RV_REG_FP , RV_REG_SP , stack_size , ctx );
851+ if (func_addr ) {
852+ /* For the trampoline called from function entry,
853+ * the frame of traced function and the frame of
854+ * trampoline need to be considered.
855+ */
856+ emit_addi (RV_REG_SP , RV_REG_SP , -16 , ctx );
857+ emit_sd (RV_REG_SP , 8 , RV_REG_RA , ctx );
858+ emit_sd (RV_REG_SP , 0 , RV_REG_FP , ctx );
859+ emit_addi (RV_REG_FP , RV_REG_SP , 16 , ctx );
860+
861+ emit_addi (RV_REG_SP , RV_REG_SP , - stack_size , ctx );
862+ emit_sd (RV_REG_SP , stack_size - 8 , RV_REG_T0 , ctx );
863+ emit_sd (RV_REG_SP , stack_size - 16 , RV_REG_FP , ctx );
864+ emit_addi (RV_REG_FP , RV_REG_SP , stack_size , ctx );
865+ } else {
866+ /* For the trampoline called directly, just handle
867+ * the frame of trampoline.
868+ */
869+ emit_addi (RV_REG_SP , RV_REG_SP , - stack_size , ctx );
870+ emit_sd (RV_REG_SP , stack_size - 8 , RV_REG_RA , ctx );
871+ emit_sd (RV_REG_SP , stack_size - 16 , RV_REG_FP , ctx );
872+ emit_addi (RV_REG_FP , RV_REG_SP , stack_size , ctx );
873+ }
876874
877875 /* callee saved register S1 to pass start time */
878876 emit_sd (RV_REG_FP , - sreg_off , RV_REG_S1 , ctx );
@@ -890,7 +888,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
890888
891889 /* skip to actual body of traced function */
892890 if (flags & BPF_TRAMP_F_SKIP_FRAME )
893- orig_call += 16 ;
891+ orig_call += RV_FENTRY_NINSNS * 4 ;
894892
895893 if (flags & BPF_TRAMP_F_CALL_ORIG ) {
896894 emit_imm (RV_REG_A0 , (const s64 )im , ctx );
@@ -967,17 +965,30 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
967965
968966 emit_ld (RV_REG_S1 , - sreg_off , RV_REG_FP , ctx );
969967
970- if (flags & BPF_TRAMP_F_SKIP_FRAME )
971- /* return address of parent function */
972- emit_ld (RV_REG_RA , stack_size - 8 , RV_REG_SP , ctx );
973- else
974- /* return address of traced function */
975- emit_ld (RV_REG_RA , stack_size - retaddr_off , RV_REG_SP , ctx );
968+ if (func_addr ) {
969+ /* trampoline called from function entry */
970+ emit_ld (RV_REG_T0 , stack_size - 8 , RV_REG_SP , ctx );
971+ emit_ld (RV_REG_FP , stack_size - 16 , RV_REG_SP , ctx );
972+ emit_addi (RV_REG_SP , RV_REG_SP , stack_size , ctx );
976973
977- emit_ld (RV_REG_FP , stack_size - fp_off , RV_REG_SP , ctx );
978- emit_addi (RV_REG_SP , RV_REG_SP , stack_size , ctx );
974+ emit_ld (RV_REG_RA , 8 , RV_REG_SP , ctx );
975+ emit_ld (RV_REG_FP , 0 , RV_REG_SP , ctx );
976+ emit_addi (RV_REG_SP , RV_REG_SP , 16 , ctx );
979977
980- emit_jalr (RV_REG_ZERO , RV_REG_RA , 0 , ctx );
978+ if (flags & BPF_TRAMP_F_SKIP_FRAME )
979+ /* return to parent function */
980+ emit_jalr (RV_REG_ZERO , RV_REG_RA , 0 , ctx );
981+ else
982+ /* return to traced function */
983+ emit_jalr (RV_REG_ZERO , RV_REG_T0 , 0 , ctx );
984+ } else {
985+ /* trampoline called directly */
986+ emit_ld (RV_REG_RA , stack_size - 8 , RV_REG_SP , ctx );
987+ emit_ld (RV_REG_FP , stack_size - 16 , RV_REG_SP , ctx );
988+ emit_addi (RV_REG_SP , RV_REG_SP , stack_size , ctx );
989+
990+ emit_jalr (RV_REG_ZERO , RV_REG_RA , 0 , ctx );
991+ }
981992
982993 ret = ctx -> ninsns ;
983994out :
@@ -1691,8 +1702,8 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx)
16911702
16921703 store_offset = stack_adjust - 8 ;
16931704
1694- /* reserve 4 nop insns */
1695- for (i = 0 ; i < 4 ; i ++ )
1705+ /* nops reserved for auipc+jalr pair */
1706+ for (i = 0 ; i < RV_FENTRY_NINSNS ; i ++ )
16961707 emit (rv_nop (), ctx );
16971708
16981709 /* First instruction is always setting the tail-call-counter
0 commit comments