[PATCH bpf-next 2/2] selftests/bpf: Cover IA32 narrow kfunc returns

Yiyang Chen <[email protected]>
Newsgroups org.kernel.vger.linux-kselftest,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <20260813-bpf-next-039-ia32-kfunc-return-v1-v1-2-37495ec632b5@mails.tsinghua.edu.cn>
Teach test_loader to select IA32-specific cases and add unsigned bool and
signed int kfunc-return tests. Each case consumes the high half of R0 after
the call and checks the required zero or sign extension.

Signed-off-by: Yiyang Chen <[email protected]>
---
 tools/testing/selftests/bpf/prog_tests/verifier.c  |  2 +
 tools/testing/selftests/bpf/progs/bpf_misc.h       |  1 +
 .../selftests/bpf/progs/verifier_kfunc_return.c    | 84 ++++++++++++++++++++++
 tools/testing/selftests/bpf/test_loader.c          | 13 ++--
 4 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index 8113fea7ba86c..4638e0a45db6e 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -127,6 +127,7 @@
 #include "verifier_set_retval.skel.h"
 #include "verifier_lsm.skel.h"
 #include "verifier_jit_inline.skel.h"
+#include "verifier_kfunc_return.skel.h"
 #include "irq.skel.h"
 #include "verifier_ctx_ptr_param.skel.h"
 #include "verifier_zext.skel.h"
@@ -289,6 +290,7 @@ void test_verifier_lsm(void)                  { RUN(verifier_lsm); }
 void test_irq(void)			      { RUN(irq); }
 void test_verifier_mtu(void)		      { RUN(verifier_mtu); }
 void test_verifier_jit_inline(void)               { RUN(verifier_jit_inline); }
+void test_verifier_kfunc_return(void)             { RUN(verifier_kfunc_return); }
 void test_verifier_ctx_ptr_param(void)       { RUN(verifier_ctx_ptr_param); }
 void test_verifier_zext(void)                 { RUN_TESTS(verifier_zext); }
 
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 5eacf1b432521..1498da04597af 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -155,6 +155,7 @@
 #define __btf_func_path(path)	__test_tag("test_btf_func_path=" path)
 #define __arch(arch)		__test_tag("test_arch=" arch)
 #define __arch_x86_64		__arch("X86_64")
+#define __arch_x86_32		__arch("X86_32")
 #define __arch_arm64		__arch("ARM64")
 #define __arch_riscv64		__arch("RISCV64")
 #define __arch_s390x		__arch("s390x")
diff --git a/tools/testing/selftests/bpf/progs/verifier_kfunc_return.c b/tools/testing/selftests/bpf/progs/verifier_kfunc_return.c
new file mode 100644
index 0000000000000..52a94daf03922
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_kfunc_return.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define BPF_NO_KFUNC_PROTOTYPES
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+extern int bpf_strcmp(const char *s1__ign, const char *s2__ign) __ksym;
+extern bool bpf_dynptr_is_null(const struct bpf_dynptr *p) __ksym;
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__uint(max_entries, 1);
+	__type(key, __u32);
+	__type(value, __u64);
+} kfunc_return_map SEC(".maps");
+
+static const char string_a[] = "a";
+static const char string_b[] = "b";
+
+void __kfunc_btf_root(void)
+{
+	struct bpf_dynptr ptr = {};
+
+	bpf_strcmp(string_a, string_b);
+	bpf_dynptr_is_null(&ptr);
+}
+
+SEC("syscall")
+__flag(BPF_F_SLEEPABLE)
+__success __retval(0)
+__arch_x86_32
+__naked void kfunc_bool_return_zero_extended(void)
+{
+	asm volatile ("					\
+	r0 = 0;						\
+	*(u32 *)(r10 - 4) = r0;				\
+	r2 = r10;					\
+	r2 += -4;					\
+	r1 = %[kfunc_return_map] ll;			\
+	call %[bpf_map_lookup_elem];			\
+	if r0 == 0 goto 1f;				\
+	r1 = r0;					\
+	r2 = 8;						\
+	r3 = 0;						\
+	r4 = r10;					\
+	r4 += -24;					\
+	call %[bpf_dynptr_from_mem];			\
+	if r0 != 0 goto 1f;				\
+	r0 = 0x100000000 ll;				\
+	r1 = r10;					\
+	r1 += -24;					\
+	call bpf_dynptr_is_null;				\
+	r0 >>= 32;					\
+	exit;						\
+1:	r0 = 2;						\
+	exit;						\
+"	:
+	: __imm_addr(kfunc_return_map),
+	  __imm(bpf_map_lookup_elem),
+	  __imm(bpf_dynptr_from_mem)
+	: __clobber_all);
+}
+
+SEC("syscall")
+__flag(BPF_F_SLEEPABLE)
+__success __retval(-1)
+__arch_x86_32
+__naked void kfunc_int_return_sign_extended(void)
+{
+	asm volatile ("					\
+	r0 = 0;						\
+	r1 = %[string_a] ll;				\
+	r2 = %[string_b] ll;				\
+	call bpf_strcmp;				\
+	r0 >>= 32;					\
+	exit;						\
+"	:
+	: __imm_addr(string_a),
+	  __imm_addr(string_b)
+	: __clobber_all);
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index 07807757b518d..8a9f4a31a1bb1 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -374,16 +374,19 @@ static const char **collect_decl_tags(struct btf *btf, int id, int *cnt)
 enum arch {
 	ARCH_UNKNOWN	= 0x1,
 	ARCH_X86_64	= 0x2,
-	ARCH_ARM64	= 0x4,
-	ARCH_RISCV64	= 0x8,
-	ARCH_S390X	= 0x10,
-	ARCH_LOONGARCH	= 0x20,
+	ARCH_X86_32	= 0x4,
+	ARCH_ARM64	= 0x8,
+	ARCH_RISCV64	= 0x10,
+	ARCH_S390X	= 0x20,
+	ARCH_LOONGARCH	= 0x40,
 };
 
 static int get_current_arch(void)
 {
 #if defined(__x86_64__)
 	return ARCH_X86_64;
+#elif defined(__i386__)
+	return ARCH_X86_32;
 #elif defined(__aarch64__)
 	return ARCH_ARM64;
 #elif defined(__riscv) && __riscv_xlen == 64
@@ -577,6 +580,8 @@ static int parse_test_spec(struct test_loader *tester,
 		} else if ((val = str_has_pfx(s, "test_arch="))) {
 			if (strcmp(val, "X86_64") == 0) {
 				arch = ARCH_X86_64;
+			} else if (strcmp(val, "X86_32") == 0) {
+				arch = ARCH_X86_32;
 			} else if (strcmp(val, "ARM64") == 0) {
 				arch = ARCH_ARM64;
 			} else if (strcmp(val, "RISCV64") == 0) {

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.