13
13
#include <asm/patch.h>
14
14
#include "bpf_jit.h"
15
15
16
+ #define RV_FENTRY_NINSNS 2
17
+
16
18
#define RV_REG_TCC RV_REG_A6
17
19
#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */
18
20
@@ -241,7 +243,7 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
241
243
if (!is_tail_call )
242
244
emit_mv (RV_REG_A0 , RV_REG_A5 , ctx );
243
245
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 */
245
247
ctx );
246
248
}
247
249
@@ -618,32 +620,7 @@ static int add_exception_handler(const struct bpf_insn *insn,
618
620
return 0 ;
619
621
}
620
622
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 )
647
624
{
648
625
s64 rvoff ;
649
626
struct rv_jit_context ctx ;
@@ -658,38 +635,35 @@ static int gen_jump_or_nops(void *target, void *ip, u32 *insns)
658
635
}
659
636
660
637
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 );
662
639
}
663
640
664
641
int bpf_arch_text_poke (void * ip , enum bpf_text_poke_type poke_type ,
665
642
void * old_addr , void * new_addr )
666
643
{
667
- u32 old_insns [4 ], new_insns [4 ];
644
+ u32 old_insns [RV_FENTRY_NINSNS ], new_insns [RV_FENTRY_NINSNS ];
668
645
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 ;
671
646
int ret ;
672
647
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 ))
674
650
return - ENOTSUPP ;
675
651
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 );
679
653
if (ret )
680
654
return ret ;
681
655
682
- if (memcmp (ip , old_insns , ninsns * 4 ))
656
+ if (memcmp (ip , old_insns , RV_FENTRY_NINSNS * 4 ))
683
657
return - EFAULT ;
684
658
685
- ret = gen_insns (new_addr , ip , new_insns );
659
+ ret = gen_jump_or_nops (new_addr , ip , new_insns , is_call );
686
660
if (ret )
687
661
return ret ;
688
662
689
663
cpus_read_lock ();
690
664
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 );
693
667
mutex_unlock (& text_mutex );
694
668
cpus_read_unlock ();
695
669
@@ -787,22 +761,35 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
787
761
int i , ret , offset ;
788
762
int * branches_off = NULL ;
789
763
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 ;
792
765
struct bpf_tramp_links * fentry = & tlinks [BPF_TRAMP_FENTRY ];
793
766
struct bpf_tramp_links * fexit = & tlinks [BPF_TRAMP_FEXIT ];
794
767
struct bpf_tramp_links * fmod_ret = & tlinks [BPF_TRAMP_MODIFY_RETURN ];
795
768
void * orig_call = func_addr ;
796
769
bool save_ret ;
797
770
u32 insn ;
798
771
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
+ * --------------------------------------
800
785
*
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
802
789
* function
803
- * FP - retaddr_off [ RA of traced func ] return address of traced
790
+ * FP - 16 [ FP of caller func ] frame pointer of caller
804
791
* function
805
- * FP - fp_off [ FP of parent func ]
792
+ * --------------------------------------
806
793
*
807
794
* FP - retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
808
795
* BPF_TRAMP_F_RET_FENTRY_RET
@@ -833,14 +820,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
833
820
if (nregs > 8 )
834
821
return - ENOTSUPP ;
835
822
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 ;
844
825
845
826
save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET );
846
827
if (save_ret ) {
@@ -867,12 +848,29 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
867
848
868
849
stack_size = round_up (stack_size , 16 );
869
850
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
+ }
876
874
877
875
/* callee saved register S1 to pass start time */
878
876
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,
890
888
891
889
/* skip to actual body of traced function */
892
890
if (flags & BPF_TRAMP_F_SKIP_FRAME )
893
- orig_call += 16 ;
891
+ orig_call += RV_FENTRY_NINSNS * 4 ;
894
892
895
893
if (flags & BPF_TRAMP_F_CALL_ORIG ) {
896
894
emit_imm (RV_REG_A0 , (const s64 )im , ctx );
@@ -967,17 +965,30 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
967
965
968
966
emit_ld (RV_REG_S1 , - sreg_off , RV_REG_FP , ctx );
969
967
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 );
976
973
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 );
979
977
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
+ }
981
992
982
993
ret = ctx -> ninsns ;
983
994
out :
@@ -1691,8 +1702,8 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx)
1691
1702
1692
1703
store_offset = stack_adjust - 8 ;
1693
1704
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 ++ )
1696
1707
emit (rv_nop (), ctx );
1697
1708
1698
1709
/* First instruction is always setting the tail-call-counter
0 commit comments