Skip to content

Commit 25ad106

Browse files
Pu LehuiAlexei Starovoitov
authored andcommitted
riscv, bpf: Adapt bpf trampoline to optimized riscv ftrace framework
Commit 6724a76 ("riscv: ftrace: Reduce the detour code size to half") optimizes the detour code size of kernel functions to half with T0 register and the upcoming DYNAMIC_FTRACE_WITH_DIRECT_CALLS of riscv is based on this optimization, we need to adapt riscv bpf trampoline based on this. One thing to do is to reduce detour code size of bpf programs, and the second is to deal with the return address after the execution of bpf trampoline. Meanwhile, we need to construct the frame of parent function, otherwise we will miss one layer when unwinding. The related tests have passed. Signed-off-by: Pu Lehui <pulehui@huawei.com> Tested-by: Björn Töpel <bjorn@rivosinc.com> Link: https://lore.kernel.org/r/20230721100627.2630326-1-pulehui@huaweicloud.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 94e38c9 commit 25ad106

File tree

1 file changed

+82
-71
lines changed

1 file changed

+82
-71
lines changed

arch/riscv/net/bpf_jit_comp64.c

Lines changed: 82 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
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

664641
int 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;
983994
out:
@@ -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

Comments
 (0)