All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Gray <bgray@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: Benjamin Gray <bgray@linux.ibm.com>
Subject: [PATCH v1 8/9] selftests/powerpc/dexcr: Add chdexcr utility
Date: Wed, 17 Apr 2024 21:23:24 +1000	[thread overview]
Message-ID: <20240417112325.728010-9-bgray@linux.ibm.com> (raw)
In-Reply-To: <20240417112325.728010-1-bgray@linux.ibm.com>

Adds a utility to exercise the prctl DEXCR inheritance in the shell.
Supports setting and clearing each aspect.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 .../selftests/powerpc/dexcr/.gitignore        |   1 +
 .../testing/selftests/powerpc/dexcr/Makefile  |   2 +-
 .../testing/selftests/powerpc/dexcr/chdexcr.c | 110 +++++++++++++++
 tools/testing/selftests/powerpc/dexcr/dexcr.h |  47 +++++++
 .../testing/selftests/powerpc/dexcr/lsdexcr.c | 130 ++++--------------
 5 files changed, 185 insertions(+), 105 deletions(-)
 create mode 100644 tools/testing/selftests/powerpc/dexcr/chdexcr.c

diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore
index 5d526613cd26..11eefb4b9fa4 100644
--- a/tools/testing/selftests/powerpc/dexcr/.gitignore
+++ b/tools/testing/selftests/powerpc/dexcr/.gitignore
@@ -1,3 +1,4 @@
 dexcr_test
 hashchk_test
+chdexcr
 lsdexcr
diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile
index 076943193c07..6a89e88ef7b2 100644
--- a/tools/testing/selftests/powerpc/dexcr/Makefile
+++ b/tools/testing/selftests/powerpc/dexcr/Makefile
@@ -1,5 +1,5 @@
 TEST_GEN_PROGS := dexcr_test hashchk_test
-TEST_GEN_FILES := lsdexcr
+TEST_GEN_FILES := lsdexcr chdexcr
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/powerpc/dexcr/chdexcr.c b/tools/testing/selftests/powerpc/dexcr/chdexcr.c
new file mode 100644
index 000000000000..217187a83224
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/chdexcr.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+
+#include "dexcr.h"
+#include "utils.h"
+
+static void die(const char *msg)
+{
+	printf("%s\n", msg);
+	exit(1);
+}
+
+static void help(void)
+{
+	printf("Invoke a provided program with a custom DEXCR on-exec reset value\n"
+	       "\n"
+	       "usage: chdexcr [CHDEXCR OPTIONS] -- PROGRAM [ARGS...]\n"
+	       "\n"
+	       "Each configurable DEXCR aspect is exposed as an option.\n"
+	       "\n"
+	       "The normal option sets the aspect in the DEXCR. The --no- variant\n"
+	       "clears that aspect. For example, --ibrtpd sets the IBRTPD aspect bit,\n"
+	       "so indirect branch predicition will be disabled in the provided program.\n"
+	       "Conversely, --no-ibrtpd clears the aspect bit, so indirect branch\n"
+	       "prediction may occur.\n"
+	       "\n"
+	       "CHDEXCR OPTIONS:\n");
+
+	for (int i = 0; i < ARRAY_SIZE(aspects); i++) {
+		const struct dexcr_aspect *aspect = &aspects[i];
+
+		if (aspect->prctl == -1)
+			continue;
+
+		printf("  --%-6s / --no-%-6s : %s\n", aspect->opt, aspect->opt, aspect->desc);
+	}
+}
+
+static const struct dexcr_aspect *opt_to_aspect(const char *opt)
+{
+	for (int i = 0; i < ARRAY_SIZE(aspects); i++)
+		if (aspects[i].prctl != -1 && !strcmp(aspects[i].opt, opt))
+			return &aspects[i];
+
+	return NULL;
+}
+
+static int apply_option(const char *option)
+{
+	const struct dexcr_aspect *aspect;
+	const char *opt = NULL;
+	const char *set_prefix = "--";
+	const char *clear_prefix = "--no-";
+	unsigned long ctrl = 0;
+	int err;
+
+	if (!strcmp(option, "-h") || !strcmp(option, "--help")) {
+		help();
+		exit(0);
+	}
+
+	/* Strip out --(no-) prefix and determine ctrl value */
+	if (!strncmp(option, clear_prefix, strlen(clear_prefix))) {
+		opt = &option[strlen(clear_prefix)];
+		ctrl |= PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC;
+	} else if (!strncmp(option, set_prefix, strlen(set_prefix))) {
+		opt = &option[strlen(set_prefix)];
+		ctrl |= PR_PPC_DEXCR_CTRL_SET_ONEXEC;
+	}
+
+	if (!opt || !*opt)
+		return 1;
+
+	aspect = opt_to_aspect(opt);
+	if (!aspect)
+		die("unknown aspect");
+
+	err = pr_set_dexcr(aspect->prctl, ctrl);
+	if (err)
+		die("failed to apply option");
+
+	return 0;
+}
+
+int main(int argc, char *const argv[], char *const envp[])
+{
+	int i;
+
+	if (!dexcr_exists())
+		die("DEXCR not detected on this hardware");
+
+	for (i = 1; i < argc; i++)
+		if (apply_option(argv[i]))
+			break;
+
+	if (i < argc && !strcmp(argv[i], "--"))
+		i++;
+
+	if (i >= argc)
+		die("missing command");
+
+	execve(argv[i], &argv[i], envp);
+	return errno;
+}
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.h b/tools/testing/selftests/powerpc/dexcr/dexcr.h
index a6aa7eac11da..51e9ba3b0997 100644
--- a/tools/testing/selftests/powerpc/dexcr/dexcr.h
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr.h
@@ -9,6 +9,7 @@
 #define _SELFTESTS_POWERPC_DEXCR_DEXCR_H
 
 #include <stdbool.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 
 #include "reg.h"
@@ -26,6 +27,52 @@
 #define PPC_RAW_HASHCHK(b, i, a) \
 	str(.long (0x7C0005E4 | PPC_RAW_HASH_ARGS(b, i, a));)
 
+struct dexcr_aspect {
+	const char *name;	/* Short display name */
+	const char *opt;	/* Option name for chdexcr */
+	const char *desc;	/* Expanded aspect meaning */
+	unsigned int index;	/* Aspect bit index in DEXCR */
+	unsigned long prctl;	/* 'which' value for get/set prctl */
+};
+
+static const struct dexcr_aspect aspects[] = {
+	{
+		.name = "SBHE",
+		.opt = "sbhe",
+		.desc = "Speculative branch hint enable",
+		.index = 0,
+		.prctl = PR_PPC_DEXCR_SBHE,
+	},
+	{
+		.name = "IBRTPD",
+		.opt = "ibrtpd",
+		.desc = "Indirect branch recurrent target prediction disable",
+		.index = 3,
+		.prctl = PR_PPC_DEXCR_IBRTPD,
+	},
+	{
+		.name = "SRAPD",
+		.opt = "srapd",
+		.desc = "Subroutine return address prediction disable",
+		.index = 4,
+		.prctl = PR_PPC_DEXCR_SRAPD,
+	},
+	{
+		.name = "NPHIE",
+		.opt = "nphie",
+		.desc = "Non-privileged hash instruction enable",
+		.index = 5,
+		.prctl = PR_PPC_DEXCR_NPHIE,
+	},
+	{
+		.name = "PHIE",
+		.opt = "phie",
+		.desc = "Privileged hash instruction enable",
+		.index = 6,
+		.prctl = -1,
+	},
+};
+
 bool dexcr_exists(void);
 
 bool pr_dexcr_aspect_supported(unsigned long which);
diff --git a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
index a63db47b6610..7588929180ab 100644
--- a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
+++ b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
@@ -12,52 +12,6 @@ static unsigned int dexcr;
 static unsigned int hdexcr;
 static unsigned int effective;
 
-struct dexcr_aspect {
-	const char *name;
-	const char *desc;
-	unsigned int index;
-	unsigned long prctl;
-	const char *sysctl;
-};
-
-static const struct dexcr_aspect aspects[] = {
-	{
-		.name = "SBHE",
-		.desc = "Speculative branch hint enable",
-		.index = 0,
-		.prctl = PR_PPC_DEXCR_SBHE,
-		.sysctl = "speculative_branch_hint_enable",
-	},
-	{
-		.name = "IBRTPD",
-		.desc = "Indirect branch recurrent target prediction disable",
-		.index = 3,
-		.prctl = PR_PPC_DEXCR_IBRTPD,
-		.sysctl = "indirect_branch_recurrent_target_prediction_disable",
-	},
-	{
-		.name = "SRAPD",
-		.desc = "Subroutine return address prediction disable",
-		.index = 4,
-		.prctl = PR_PPC_DEXCR_SRAPD,
-		.sysctl = "subroutine_return_address_prediction_disable",
-	},
-	{
-		.name = "NPHIE",
-		.desc = "Non-privileged hash instruction enable",
-		.index = 5,
-		.prctl = PR_PPC_DEXCR_NPHIE,
-		.sysctl = "nonprivileged_hash_instruction_enable",
-	},
-	{
-		.name = "PHIE",
-		.desc = "Privileged hash instruction enable",
-		.index = 6,
-		.prctl = -1,
-		.sysctl = NULL,
-	},
-};
-
 static void print_list(const char *list[], size_t len)
 {
 	for (size_t i = 0; i < len; i++) {
@@ -117,89 +71,57 @@ static void print_aspect(const struct dexcr_aspect *aspect)
 
 static void print_aspect_config(const struct dexcr_aspect *aspect)
 {
-	char sysctl_path[128] = "/proc/sys/kernel/dexcr/";
-	const char *reason = "unknown";
+	const char *reason = NULL;
 	const char *reason_hyp = NULL;
-	const char *reason_sysctl = "no sysctl";
 	const char *reason_prctl = "no prctl";
 	bool actual = effective & DEXCR_PR_BIT(aspect->index);
-	bool expected = false;
-
-	long sysctl_ctrl = 0;
-	int prctl_ctrl = 0;
-	int err;
-
-	if (aspect->prctl >= 0) {
-		prctl_ctrl = pr_get_dexcr(aspect->prctl);
-		if (prctl_ctrl < 0)
-			reason_prctl = "(failed to read prctl)";
-		else {
-			if (prctl_ctrl & PR_PPC_DEXCR_CTRL_SET) {
+	bool expected = actual;  /* Assume it's fine if we don't expect a specific set/clear value */
+
+	if (actual)
+		reason = "set by unknown";
+	else
+		reason = "cleared by unknown";
+
+	if (aspect->prctl != -1) {
+		int ctrl = pr_get_dexcr(aspect->prctl);
+
+		if (ctrl < 0) {
+			reason_prctl = "failed to read prctl";
+		} else {
+			if (ctrl & PR_PPC_DEXCR_CTRL_SET) {
 				reason_prctl = "set by prctl";
 				expected = true;
-			} else if (prctl_ctrl & PR_PPC_DEXCR_CTRL_CLEAR) {
+			} else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) {
 				reason_prctl = "cleared by prctl";
 				expected = false;
-			} else
+			} else {
 				reason_prctl = "unknown prctl";
+			}
 
 			reason = reason_prctl;
 		}
 	}
 
-	if (aspect->sysctl) {
-		strcat(sysctl_path, aspect->sysctl);
-		err = read_long(sysctl_path, &sysctl_ctrl, 10);
-		if (err)
-			reason_sysctl = "(failed to read sysctl)";
-		else {
-			switch (sysctl_ctrl) {
-			case 0:
-				reason_sysctl = "cleared by sysctl";
-				reason = reason_sysctl;
-				expected = false;
-				break;
-			case 1:
-				reason_sysctl = "set by sysctl";
-				reason = reason_sysctl;
-				expected = true;
-				break;
-			case 2:
-				reason_sysctl = "not modified by sysctl";
-				break;
-			case 3:
-				reason_sysctl = "cleared by sysctl (permanent)";
-				reason = reason_sysctl;
-				expected = false;
-				break;
-			case 4:
-				reason_sysctl = "set by sysctl (permanent)";
-				reason = reason_sysctl;
-				expected = true;
-				break;
-			default:
-				reason_sysctl = "unknown sysctl";
-				break;
-			}
-		}
-	}
-
-
 	if (hdexcr & DEXCR_PR_BIT(aspect->index)) {
 		reason_hyp = "set by hypervisor";
 		reason = reason_hyp;
 		expected = true;
-	} else
+	} else {
 		reason_hyp = "not modified by hypervisor";
+	}
 
-	printf("%12s (%d): %-28s (%s, %s, %s)\n",
+	printf("%12s (%d): %-28s (%s, %s)\n",
 	       aspect->name,
 	       aspect->index,
 	       reason,
 	       reason_hyp,
-	       reason_sysctl,
 	       reason_prctl);
 
+	/*
+	 * The checks are not atomic, so this can technically trigger if the
+	 * hypervisor makes a change while we are checking each source. It's
+	 * far more likely to be a bug if we see this though.
+	 */
 	if (actual != expected)
 		printf("                : ! actual %s does not match config\n", aspect->name);
 }
-- 
2.44.0


  parent reply	other threads:[~2024-04-17 11:30 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests Benjamin Gray
2024-05-07  7:44   ` Andrew Donnellan
2024-04-17 11:23 ` [PATCH v1 2/9] powerpc/dexcr: Track the DEXCR per-process Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 3/9] powerpc/dexcr: Reset DEXCR value across exec Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 4/9] powerpc/dexcr: Add DEXCR prctl interface Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 5/9] selftests/powerpc/dexcr: Add DEXCR prctl interface test Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 6/9] selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 7/9] selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr Benjamin Gray
2024-04-17 11:23 ` Benjamin Gray [this message]
2024-04-17 11:23 ` [PATCH v1 9/9] Documentation: Document PowerPC kernel dynamic DEXCR interface Benjamin Gray
2024-05-08 13:39 ` [PATCH v1 0/9] Add dynamic DEXCR support Michael Ellerman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240417112325.728010-9-bgray@linux.ibm.com \
    --to=bgray@linux.ibm.com \
    --cc=linuxppc-dev@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.