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


Reply via email to