OSDN Git Service

selftests: Test the new RISC-V hwprobe interface
authorEvan Green <evan@rivosinc.com>
Fri, 7 Apr 2023 23:11:02 +0000 (16:11 -0700)
committerPalmer Dabbelt <palmer@rivosinc.com>
Tue, 18 Apr 2023 22:48:17 +0000 (15:48 -0700)
This adds a test for the recently added RISC-V interface for probing
hardware capabilities.  It happens to be the first selftest we have for
RISC-V, so I've added some infrastructure for those as well.

Co-developed-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Evan Green <evan@rivosinc.com>
Link: https://lore.kernel.org/r/20230407231103.2622178-6-evan@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
tools/testing/selftests/Makefile
tools/testing/selftests/riscv/Makefile [new file with mode: 0644]
tools/testing/selftests/riscv/hwprobe/Makefile [new file with mode: 0644]
tools/testing/selftests/riscv/hwprobe/hwprobe.c [new file with mode: 0644]
tools/testing/selftests/riscv/hwprobe/sys_hwprobe.S [new file with mode: 0644]

index 13a6837..4bea261 100644 (file)
@@ -63,6 +63,7 @@ TARGETS += pstore
 TARGETS += ptrace
 TARGETS += openat2
 TARGETS += resctrl
+TARGETS += riscv
 TARGETS += rlimits
 TARGETS += rseq
 TARGETS += rtc
diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile
new file mode 100644 (file)
index 0000000..32a7290
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+# Originally tools/testing/arm64/Makefile
+
+# When ARCH not overridden for crosscompiling, lookup machine
+ARCH ?= $(shell uname -m 2>/dev/null || echo not)
+
+ifneq (,$(filter $(ARCH),riscv))
+RISCV_SUBTARGETS ?= hwprobe
+else
+RISCV_SUBTARGETS :=
+endif
+
+CFLAGS := -Wall -O2 -g
+
+# A proper top_srcdir is needed by KSFT(lib.mk)
+top_srcdir = $(realpath ../../../../)
+
+# Additional include paths needed by kselftest.h and local headers
+CFLAGS += -I$(top_srcdir)/tools/testing/selftests/
+
+CFLAGS += $(KHDR_INCLUDES)
+
+export CFLAGS
+export top_srcdir
+
+all:
+       @for DIR in $(RISCV_SUBTARGETS); do                             \
+               BUILD_TARGET=$(OUTPUT)/$$DIR;                   \
+               mkdir -p $$BUILD_TARGET;                        \
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;              \
+       done
+
+install: all
+       @for DIR in $(RISCV_SUBTARGETS); do                             \
+               BUILD_TARGET=$(OUTPUT)/$$DIR;                   \
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;              \
+       done
+
+run_tests: all
+       @for DIR in $(RISCV_SUBTARGETS); do                             \
+               BUILD_TARGET=$(OUTPUT)/$$DIR;                   \
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;              \
+       done
+
+# Avoid any output on non riscv on emit_tests
+emit_tests: all
+       @for DIR in $(RISCV_SUBTARGETS); do                             \
+               BUILD_TARGET=$(OUTPUT)/$$DIR;                   \
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;              \
+       done
+
+clean:
+       @for DIR in $(RISCV_SUBTARGETS); do                             \
+               BUILD_TARGET=$(OUTPUT)/$$DIR;                   \
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;              \
+       done
+
+.PHONY: all clean install run_tests emit_tests
diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile b/tools/testing/selftests/riscv/hwprobe/Makefile
new file mode 100644 (file)
index 0000000..ebdbb3c
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 ARM Limited
+# Originally tools/testing/arm64/abi/Makefile
+
+TEST_GEN_PROGS := hwprobe
+
+include ../../lib.mk
+
+$(OUTPUT)/hwprobe: hwprobe.c sys_hwprobe.S
+       $(CC) -o$@ $(CFLAGS) $(LDFLAGS) $^
diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c
new file mode 100644 (file)
index 0000000..09f290a
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <stddef.h>
+#include <asm/hwprobe.h>
+
+/*
+ * Rather than relying on having a new enough libc to define this, just do it
+ * ourselves.  This way we don't need to be coupled to a new-enough libc to
+ * contain the call.
+ */
+long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
+                  size_t cpu_count, unsigned long *cpus, unsigned int flags);
+
+int main(int argc, char **argv)
+{
+       struct riscv_hwprobe pairs[8];
+       unsigned long cpus;
+       long out;
+
+       /* Fake the CPU_SET ops. */
+       cpus = -1;
+
+       /*
+        * Just run a basic test: pass enough pairs to get up to the base
+        * behavior, and then check to make sure it's sane.
+        */
+       for (long i = 0; i < 8; i++)
+               pairs[i].key = i;
+       out = riscv_hwprobe(pairs, 8, 1, &cpus, 0);
+       if (out != 0)
+               return -1;
+       for (long i = 0; i < 4; ++i) {
+               /* Fail if the kernel claims not to recognize a base key. */
+               if ((i < 4) && (pairs[i].key != i))
+                       return -2;
+
+               if (pairs[i].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR)
+                       continue;
+
+               if (pairs[i].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA)
+                       continue;
+
+               return -3;
+       }
+
+       /*
+        * This should also work with a NULL CPU set, but should not work
+        * with an improperly supplied CPU set.
+        */
+       out = riscv_hwprobe(pairs, 8, 0, 0, 0);
+       if (out != 0)
+               return -4;
+
+       out = riscv_hwprobe(pairs, 8, 0, &cpus, 0);
+       if (out == 0)
+               return -5;
+
+       out = riscv_hwprobe(pairs, 8, 1, 0, 0);
+       if (out == 0)
+               return -6;
+
+       /*
+        * Check that keys work by providing one that we know exists, and
+        * checking to make sure the resultig pair is what we asked for.
+        */
+       pairs[0].key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR;
+       out = riscv_hwprobe(pairs, 1, 1, &cpus, 0);
+       if (out != 0)
+               return -7;
+       if (pairs[0].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR)
+               return -8;
+
+       /*
+        * Check that an unknown key gets overwritten with -1,
+        * but doesn't block elements after it.
+        */
+       pairs[0].key = 0x5555;
+       pairs[1].key = 1;
+       pairs[1].value = 0xAAAA;
+       out = riscv_hwprobe(pairs, 2, 0, 0, 0);
+       if (out != 0)
+               return -9;
+
+       if (pairs[0].key != -1)
+               return -10;
+
+       if ((pairs[1].key != 1) || (pairs[1].value == 0xAAAA))
+               return -11;
+
+       return 0;
+}
diff --git a/tools/testing/selftests/riscv/hwprobe/sys_hwprobe.S b/tools/testing/selftests/riscv/hwprobe/sys_hwprobe.S
new file mode 100644 (file)
index 0000000..a4773c8
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2023 Rivos, Inc */
+
+.text
+.global riscv_hwprobe
+riscv_hwprobe:
+       # Put __NR_riscv_hwprobe in the syscall number register, then just shim
+       # back the kernel's return.  This doesn't do any sort of errno
+       # handling, the caller can deal with it.
+       li a7, 258
+       ecall
+       ret