[Pdbg] [PATCH v2 6/7] main: Add HTM functions to deal with Core HTM

Cyril Bur cyrilbur at gmail.com
Wed Feb 14 15:27:42 AEDT 2018


This commit also updates the README to only reference the new commands

Signed-off-by: Cyril Bur <cyrilbur at gmail.com>
---
 README.md  |  16 +++--
 src/htm.c  | 222 ++++++++++++++++++++++++++++++++++++++++---------------------
 src/htm.h  |   2 +
 src/main.c |  15 +++--
 4 files changed, 167 insertions(+), 88 deletions(-)

diff --git a/README.md b/README.md
index 51b5f09..419af7f 100644
--- a/README.md
+++ b/README.md
@@ -272,24 +272,26 @@ c22: A A A A
 
 ### Hardware Trace Macro
 Expoitation of HTM is limited to POWER9 NestHTM from the powerpc host.
+POWER8 (core and nest( is currently experimental. The dump files
+should be correct but have not been confirmed to be.
 
 Using HTM requires a kernel built with both `CONFIG_PPC_MEMTRACE=y`
 (v4.14) and `CONFIG_SCOM_DEBUGFS=y`. debugfs should be mounted at
 `/sys/kernel/debug`.
 
-pdbg provides `htm_trace` which will configure the hardware and
-start tracing as well as `htm_analyse` which still stop the trace and
-dump the result to a file.
+pdbg provides a `htm` command with a variety of subcommands:
+ - `trace` will configure the hardware and start tracing
+ - `analyse` which still stop the trace and dump the result to a file
 
 ```
-./pdbg -b host -d p9 -a htm_trace
+./pdbg -b host -d p9 -a htm trace
 [allow test to run]
-./pdbg -b host -d p9 -a htm_analyse
+./pdbg -b host -d p9 -a htm analyse
 ```
-If you are running into a checkstop issue, `htm_trace` will print the
+If you are running into a checkstop issue, `htm trace` will print the
 physical address of the buffer it is tracing into and the BMC can be
 used to recover this memory after checkstop see `getmem`.
 
 pdbg also provides some of the basic functionality to use HTM, such as
-`htm_reset`, `htm_start` and `htm_stop` to perform each step manually
+`htm reset`, `htm start` and `htm stop` to perform each step manually
 if required.
diff --git a/src/htm.c b/src/htm.c
index d6638ea..56fcf26 100644
--- a/src/htm.c
+++ b/src/htm.c
@@ -13,6 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+
+
+ /*
+ * This file does the Hardware Trace Macro command parsing for pdbg
+ * the program.
+ * It will call into libpdbg backend with a target to either a 'nhtm'
+ * or a 'chtm' which will ultimately do the work.
+ *
+ */
 #define _GNU_SOURCE
 #include <inttypes.h>
 #include <stdio.h>
@@ -20,6 +30,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <ccan/array_size/array_size.h>
+
 #include <target.h>
 #include <operations.h>
 
@@ -27,6 +39,13 @@
 
 #define HTM_DUMP_BASENAME "htm.dump"
 
+#define HTM_ENUM_TO_STRING(e) ((e == HTM_NEST) ? "nhtm" : "chtm")
+
+enum htm_type {
+	HTM_CORE,
+	HTM_NEST,
+};
+
 static char *get_htm_dump_filename(void)
 {
 	char *filename;
@@ -47,12 +66,12 @@ static char *get_htm_dump_filename(void)
 	return filename;
 }
 
-int run_htm_start(int optind, int argc, char *argv[])
+static int run_start(enum htm_type type, int optind, int argc, char *argv[])
 {
 	struct pdbg_target *target;
 	int rc = 0;
 
-	pdbg_for_each_class_target("nhtm", target) {
+	pdbg_for_each_class_target(HTM_ENUM_TO_STRING(type), target) {
 		uint64_t chip_id;
 		uint32_t index;
 
@@ -70,12 +89,12 @@ int run_htm_start(int optind, int argc, char *argv[])
 	return rc;
 }
 
-int run_htm_stop(int optind, int argc, char *argv[])
+static int run_stop(enum htm_type type, int optind, int argc, char *argv[])
 {
 	struct pdbg_target *target;
 	int rc = 0;
 
-	pdbg_for_each_class_target("nhtm", target) {
+	pdbg_for_each_class_target(HTM_ENUM_TO_STRING(type), target) {
 		uint64_t chip_id;
 		uint32_t index;
 
@@ -93,12 +112,12 @@ int run_htm_stop(int optind, int argc, char *argv[])
 	return rc;
 }
 
-int run_htm_status(int optind, int argc, char *argv[])
+static int run_status(enum htm_type type, int optind, int argc, char *argv[])
 {
 	struct pdbg_target *target;
 	int rc = 0;
 
-	pdbg_for_each_class_target("nhtm", target) {
+	pdbg_for_each_class_target(HTM_ENUM_TO_STRING(type), target) {
 		uint64_t chip_id;
 		uint32_t index;
 
@@ -117,13 +136,13 @@ int run_htm_status(int optind, int argc, char *argv[])
 	return rc;
 }
 
-int run_htm_reset(int optind, int argc, char *argv[])
+static int run_reset(enum htm_type type, int optind, int argc, char *argv[])
 {
 	uint64_t old_base = 0, base, size;
 	struct pdbg_target *target;
 	int rc = 0;
 
-	pdbg_for_each_class_target("nhtm", target) {
+	pdbg_for_each_class_target(HTM_ENUM_TO_STRING(type), target) {
 		uint64_t chip_id;
 		uint32_t index;
 
@@ -149,7 +168,7 @@ int run_htm_reset(int optind, int argc, char *argv[])
 	return rc;
 }
 
-int run_htm_dump(int optind, int argc, char *argv[])
+static int run_dump(enum htm_type type, int optind, int argc, char *argv[])
 {
 	struct pdbg_target *target;
 	char *filename;
@@ -161,7 +180,7 @@ int run_htm_dump(int optind, int argc, char *argv[])
 
 	/* size = 0 will dump everything */
 	printf("Dumping HTM trace to file [chip].[#]%s\n", filename);
-	pdbg_for_each_class_target("nhtm", target) {
+	pdbg_for_each_class_target(HTM_ENUM_TO_STRING(type), target) {
 		uint64_t chip_id;
 		uint32_t index;
 
@@ -180,91 +199,146 @@ int run_htm_dump(int optind, int argc, char *argv[])
 	return rc;
 }
 
-int run_htm_trace(int optind, int argc, char *argv[])
+static int run_trace(enum htm_type type, int optind, int argc, char *argv[])
 {
-	uint64_t old_base = 0, base, size;
-	struct pdbg_target *target;
-	int rc = 0;
+	int rc;
 
-	pdbg_for_each_class_target("nhtm", target) {
-		uint64_t chip_id;
-		uint32_t index;
-
-		if (target_is_disabled(target))
-			continue;
-
-		index = pdbg_target_index(target);
-		assert(!pdbg_get_u64_property(target, "chip-id", &chip_id));
-
-		/*
-		 * Don't mind if stop fails, it will fail if it wasn't
-		 * running, if anything bad is happening reset will fail
-		 */
-		htm_stop(target);
-		printf("Resetting HTM@%" PRIu64 "#%d\n", chip_id, index);
-		if (htm_reset(target, &base, &size) != 1)
-			printf("Couldn't reset HTM@%" PRIu64 "#%d\n", chip_id, index);
-		if (old_base != base) {
-			printf("The kernel has initialised HTM memory at:\n");
-			printf("base: 0x%016" PRIx64 " for 0x%016" PRIx64 " size\n",
-					base, size);
-			printf("./pdbg getmem 0x%016" PRIx64 " 0x%016" PRIx64 " > htm.dump\n\n",
-					base, size);
-		}
-		old_base = base;
+	rc = run_reset(type, optind, argc, argv);
+	if (rc == 0) {
+		printf("No HTM units were reset.\n");
+		printf("It is unlikely anything will start... trying anyway\n");
 	}
 
-	pdbg_for_each_class_target("nhtm", target) {
-		uint64_t chip_id;
-		uint32_t index;
+	rc = run_start(type, optind, argc, argv);
+	if (rc == 0)
+		printf("No HTM units were started\n");
 
-		if (target_is_disabled(target))
-			continue;
+	return rc;
+}
 
-		index = pdbg_target_index(target);
-		assert(!pdbg_get_u64_property(target, "chip-id", &chip_id));
-		printf("Starting HTM@%" PRIu64 "#%d\n", chip_id, index);
-		if (htm_start(target) != 1)
-			printf("Couldn't start HTM@%" PRIu64 "#%d\n", chip_id, index);
-		rc++;
+static int run_analyse(enum htm_type type, int optind, int argc, char *argv[])
+{
+	int rc;
+
+	rc = run_stop(type, optind, argc, argv);
+	if (rc == 0) {
+		printf("No HTM units were stopped.\n");
+		printf("It is unlikely anything will dump... trying anyway\n");
 	}
 
+	rc = run_dump(type, optind, argc, argv);
+	if (rc == 0)
+		printf("No HTM buffers were dumped to file\n");
+
 	return rc;
 }
 
-int run_htm_analyse(int optind, int argc, char *argv[])
+static struct {
+	const char *name;
+	const char *args;
+	const char *desc;
+	int (*fn)(enum htm_type, int, int, char **);
+} actions[] = {
+	{ "start",  "", "Start %s HTM",               &run_start  },
+	{ "stop",   "", "Stop %s HTM",                &run_stop   },
+	{ "status", "", "Get %s HTM status",          &run_status },
+	{ "reset",  "", "Reset %s HTM",               &run_reset  },
+	{ "dump",   "", "Dump %s HTM buffer to file", &run_dump   },
+	{ "trace",  "", "Configure and start %s HTM", &run_trace  },
+	{ "analyse","", "Stop and dump %s HTM",       &run_analyse},
+};
+
+static void print_usage(enum htm_type type)
 {
-	struct pdbg_target *target;
-	char *filename;
-	int rc = 0;
+	int i;
 
-	pdbg_for_each_class_target("nhtm", target) {
-		if (target_is_disabled(target))
-			continue;
+	for (i = 0; i < ARRAY_SIZE(actions); i++) {
+		printf("%s %s", actions[i].name, actions[i].args);
+		printf(actions[i].desc, HTM_ENUM_TO_STRING(type));
+		printf("\n");
+	}
+}
+
+int run_htm(int optind, int argc, char *argv[])
+{
+	enum htm_type type;
+	int i, rc = 0;
 
-		htm_stop(target);
+	if (argc - optind < 2) {
+		fprintf(stderr, "Expecting one of 'core' or 'nest' with a command\n");
+		return 0;
 	}
 
-	filename = get_htm_dump_filename();
-	if (!filename)
+	optind++;
+	if (strcmp(argv[optind], "core") == 0) {
+		type = HTM_CORE;
+	} else if (strcmp(argv[optind], "nest") == 0) {
+		type = HTM_NEST;
+	} else {
+		fprintf(stderr, "Expecting one of 'core' or 'nest' not %s\n",
+			argv[optind]);
 		return 0;
+	}
 
-	printf("Dumping HTM trace to file [chip].[#]%s\n", filename);
-	pdbg_for_each_class_target("nhtm", target) {
-		uint64_t chip_id;
-		uint32_t index;
+	if (type == HTM_CORE)
+		fprintf(stderr, "Warning: Core HTM is currently experimental\n");
 
-		if (target_is_disabled(target))
-			continue;
+	optind++;
+	for (i = 0; i < ARRAY_SIZE(actions); i++) {
+		if (strcmp(argv[optind], actions[i].name) == 0) {
+			rc = actions[i].fn(type, optind, argc, argv);
+			break;
+		}
+	}
 
-		index = pdbg_target_index(target);
-		assert(!pdbg_get_u64_property(target, "chip-id", &chip_id));
-		printf("Dumping HTM@%" PRIu64 "#%d\n", chip_id, index);
-		if (htm_dump(target, 0, filename) != 1)
-			printf("Couldn't dump HTM@%" PRIu64 "#%d\n", chip_id, index);
-		rc++;
+	if (i == ARRAY_SIZE(actions)) {
+		PR_ERROR("Unsupported command: %s\n", argv[optind]);
+		print_usage(type);
+		return 0;
+	} else if (rc == 0) {
+		fprintf(stderr, "Couldn't run the HTM command.\n");
+		fprintf(stderr, "Double check that your kernel has debugfs mounted and the memtrace patches\n");
 	}
-	free(filename);
 
 	return rc;
 }
+
+/*
+ * These are all the old handlers that only worked with nest HTM.
+ * I don't want to break the commands but we've gone with a more
+ * flexible HTM command structure to better incorporate core HTM.
+ */
+int run_htm_start(int optind, int argc, char *argv[])
+{
+	return run_start(HTM_NEST, optind, argc, argv);
+}
+
+int run_htm_stop(int optind, int argc, char *argv[])
+{
+	return run_stop(HTM_NEST, optind, argc, argv);
+}
+
+int run_htm_status(int optind, int argc, char *argv[])
+{
+	return run_status(HTM_NEST, optind, argc, argv);
+}
+
+int run_htm_reset(int optind, int argc, char *argv[])
+{
+	return run_reset(HTM_NEST, optind, argc, argv);
+}
+
+int run_htm_dump(int optind, int argc, char *argv[])
+{
+	return run_dump(HTM_NEST, optind, argc, argv);;
+}
+
+int run_htm_trace(int optind, int argc, char *argv[])
+{
+	return run_trace(HTM_NEST, optind, argc, argv);
+}
+
+int run_htm_analyse(int optind, int argc, char *argv[])
+{
+	return run_analyse(HTM_NEST, optind, argc, argv);
+}
diff --git a/src/htm.h b/src/htm.h
index b454acc..fef569e 100644
--- a/src/htm.h
+++ b/src/htm.h
@@ -25,3 +25,5 @@ int run_htm_reset(int optind, int argc, char *argv[]);
 int run_htm_dump(int optind, int argc, char *argv[]);
 int run_htm_trace(int optind, int argc, char *argv[]);
 int run_htm_analyse(int optind, int argc, char *argv[]);
+
+int run_htm(int optind, int argc, char *argv[]);
diff --git a/src/main.c b/src/main.c
index 24a184b..11b578e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -88,13 +88,14 @@ static struct {
 	{ "stop",    "", "Stop thread", &thread_stop },
 	{ "threadstatus", "", "Print the status of a thread", &thread_status_print },
 	{ "sreset",  "", "Reset", &thread_sreset },
-	{ "htm_start", "", "Start Nest HTM", &run_htm_start },
-	{ "htm_stop", "", "Stop Nest HTM", &run_htm_stop },
-	{ "htm_status", "", "Print the status of HTM", &run_htm_status },
-	{ "htm_reset", "", "Reset the HTM facility", &run_htm_reset },
-	{ "htm_dump", "", "Dump HTM buffer to file", &run_htm_dump },
-	{ "htm_trace", "" , "Configure and start tracing with HTM", &run_htm_trace },
-	{ "htm_analyse", "", "Stop and dump buffer to file", &run_htm_analyse },
+	{ "htm_start", "", "[deprecated use 'htm nest start'] Start Nest HTM", &run_htm_start },
+	{ "htm_stop", "", "[deprecated use 'htm nest stop'] Stop Nest HTM", &run_htm_stop },
+	{ "htm_status", "", "[deprecated use 'htm nest status'] Print the status of HTM", &run_htm_status },
+	{ "htm_reset", "", "[deprecated use 'htm nest reset'] Reset the HTM facility", &run_htm_reset },
+	{ "htm_dump", "", "[deprecated use 'htm nest dump'] Dump HTM buffer to file", &run_htm_dump },
+	{ "htm_trace", "" , "[deprecated use 'htm nest trace'] Configure and start tracing with HTM", &run_htm_trace },
+	{ "htm_analyse", "", "[derepcated use 'htm nest analyse'] Stop and dump buffer to file", &run_htm_analyse },
+	{ "htm", "(core | nest) (start | stop | status | reset | dump | trace | analyse", "Hardware Trace Macro", &run_htm },
 	{ "probe", "", "", &handle_probe },
 };
 
-- 
2.16.1



More information about the Pdbg mailing list