]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
powerpc/selftests: Add test for papr-sysparm
authorNathan Lynch <nathanl@linux.ibm.com>
Tue, 12 Dec 2023 17:02:00 +0000 (11:02 -0600)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 13 Dec 2023 10:38:21 +0000 (21:38 +1100)
Consistently testing system parameter access is a bit difficult by
nature -- the set of parameters available depends on the model and
system configuration, and updating a parameter should be considered a
destructive operation reserved for the admin.

So we validate some of the error paths and retrieve the SPLPAR
characteristics string, but not much else.

Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20231212-papr-sys_rtas-vs-lockdown-v6-13-e9eafd0c8c6c@linux.ibm.com
tools/testing/selftests/powerpc/Makefile
tools/testing/selftests/powerpc/papr_sysparm/.gitignore [new file with mode: 0644]
tools/testing/selftests/powerpc/papr_sysparm/Makefile [new file with mode: 0644]
tools/testing/selftests/powerpc/papr_sysparm/papr_sysparm.c [new file with mode: 0644]

index 05fc68d446c283aff9f3e97bdaece214db82bdb4..c376151982c4df2d2d40c89c04b29be5d273da87 100644 (file)
@@ -33,6 +33,7 @@ SUB_DIRS = alignment          \
           math         \
           papr_attributes      \
           papr_vpd             \
+          papr_sysparm         \
           ptrace       \
           security     \
           mce
diff --git a/tools/testing/selftests/powerpc/papr_sysparm/.gitignore b/tools/testing/selftests/powerpc/papr_sysparm/.gitignore
new file mode 100644 (file)
index 0000000..f2a69bf
--- /dev/null
@@ -0,0 +1 @@
+/papr_sysparm
diff --git a/tools/testing/selftests/powerpc/papr_sysparm/Makefile b/tools/testing/selftests/powerpc/papr_sysparm/Makefile
new file mode 100644 (file)
index 0000000..7f79e43
--- /dev/null
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+noarg:
+       $(MAKE) -C ../
+
+TEST_GEN_PROGS := papr_sysparm
+
+top_srcdir = ../../../../..
+include ../../lib.mk
+
+$(TEST_GEN_PROGS): ../harness.c ../utils.c
+
+$(OUTPUT)/papr_sysparm: CFLAGS += $(KHDR_INCLUDES)
diff --git a/tools/testing/selftests/powerpc/papr_sysparm/papr_sysparm.c b/tools/testing/selftests/powerpc/papr_sysparm/papr_sysparm.c
new file mode 100644 (file)
index 0000000..d5436de
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <asm/papr-sysparm.h>
+
+#include "utils.h"
+
+#define DEVPATH "/dev/papr-sysparm"
+
+static int open_close(void)
+{
+       const int devfd = open(DEVPATH, O_RDONLY);
+
+       SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
+                   DEVPATH " not present");
+
+       FAIL_IF(devfd < 0);
+       FAIL_IF(close(devfd) != 0);
+
+       return 0;
+}
+
+static int get_splpar(void)
+{
+       struct papr_sysparm_io_block sp = {
+               .parameter = 20, // SPLPAR characteristics
+       };
+       const int devfd = open(DEVPATH, O_RDONLY);
+
+       SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
+                   DEVPATH " not present");
+
+       FAIL_IF(devfd < 0);
+       FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_GET, &sp) != 0);
+       FAIL_IF(sp.length == 0);
+       FAIL_IF(sp.length > sizeof(sp.data));
+       FAIL_IF(close(devfd) != 0);
+
+       return 0;
+}
+
+static int get_bad_parameter(void)
+{
+       struct papr_sysparm_io_block sp = {
+               .parameter = UINT32_MAX, // there are only ~60 specified parameters
+       };
+       const int devfd = open(DEVPATH, O_RDONLY);
+
+       SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
+                   DEVPATH " not present");
+
+       FAIL_IF(devfd < 0);
+
+       // Ensure expected error
+       FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_GET, &sp) != -1);
+       FAIL_IF(errno != EOPNOTSUPP);
+
+       // Ensure the buffer is unchanged
+       FAIL_IF(sp.length != 0);
+       for (size_t i = 0; i < ARRAY_SIZE(sp.data); ++i)
+               FAIL_IF(sp.data[i] != 0);
+
+       FAIL_IF(close(devfd) != 0);
+
+       return 0;
+}
+
+static int check_efault_common(unsigned long cmd)
+{
+       const int devfd = open(DEVPATH, O_RDWR);
+
+       SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
+                   DEVPATH " not present");
+
+       FAIL_IF(devfd < 0);
+
+       // Ensure expected error
+       FAIL_IF(ioctl(devfd, cmd, NULL) != -1);
+       FAIL_IF(errno != EFAULT);
+
+       FAIL_IF(close(devfd) != 0);
+
+       return 0;
+}
+
+static int check_efault_get(void)
+{
+       return check_efault_common(PAPR_SYSPARM_IOC_GET);
+}
+
+static int check_efault_set(void)
+{
+       return check_efault_common(PAPR_SYSPARM_IOC_SET);
+}
+
+static int set_hmc0(void)
+{
+       struct papr_sysparm_io_block sp = {
+               .parameter = 0, // HMC0, not a settable parameter
+       };
+       const int devfd = open(DEVPATH, O_RDWR);
+
+       SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
+                   DEVPATH " not present");
+
+       FAIL_IF(devfd < 0);
+
+       // Ensure expected error
+       FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_SET, &sp) != -1);
+       SKIP_IF_MSG(errno == EOPNOTSUPP, "operation not supported");
+       FAIL_IF(errno != EPERM);
+
+       FAIL_IF(close(devfd) != 0);
+
+       return 0;
+}
+
+static int set_with_ro_fd(void)
+{
+       struct papr_sysparm_io_block sp = {
+               .parameter = 0, // HMC0, not a settable parameter.
+       };
+       const int devfd = open(DEVPATH, O_RDONLY);
+
+       SKIP_IF_MSG(devfd < 0 && errno == ENOENT,
+                   DEVPATH " not present");
+
+       FAIL_IF(devfd < 0);
+
+       // Ensure expected error
+       FAIL_IF(ioctl(devfd, PAPR_SYSPARM_IOC_SET, &sp) != -1);
+       SKIP_IF_MSG(errno == EOPNOTSUPP, "operation not supported");
+
+       // HMC0 isn't a settable parameter and we would normally
+       // expect to get EPERM on attempts to modify it. However, when
+       // the file is open read-only, we expect the driver to prevent
+       // the attempt with a distinct error.
+       FAIL_IF(errno != EBADF);
+
+       FAIL_IF(close(devfd) != 0);
+
+       return 0;
+}
+
+struct sysparm_test {
+       int (*function)(void);
+       const char *description;
+};
+
+static const struct sysparm_test sysparm_tests[] = {
+       {
+               .function = open_close,
+               .description = "open and close " DEVPATH " without issuing commands",
+       },
+       {
+               .function = get_splpar,
+               .description = "retrieve SPLPAR characteristics",
+       },
+       {
+               .function = get_bad_parameter,
+               .description = "verify EOPNOTSUPP for known-bad parameter",
+       },
+       {
+               .function = check_efault_get,
+               .description = "PAPR_SYSPARM_IOC_GET returns EFAULT on bad address",
+       },
+       {
+               .function = check_efault_set,
+               .description = "PAPR_SYSPARM_IOC_SET returns EFAULT on bad address",
+       },
+       {
+               .function = set_hmc0,
+               .description = "ensure EPERM on attempt to update HMC0",
+       },
+       {
+               .function = set_with_ro_fd,
+               .description = "PAPR_IOC_SYSPARM_SET returns EACCESS on read-only fd",
+       },
+};
+
+int main(void)
+{
+       size_t fails = 0;
+
+       for (size_t i = 0; i < ARRAY_SIZE(sysparm_tests); ++i) {
+               const struct sysparm_test *t = &sysparm_tests[i];
+
+               if (test_harness(t->function, t->description))
+                       ++fails;
+       }
+
+       return fails == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}