summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyril Bur <cyrilbur@gmail.com>2018-02-14 15:27:42 +1100
committerAlistair Popple <alistair@popple.id.au>2018-02-16 16:22:23 +1100
commit2f0db42bf79bb0e91cc424dcb71ba78ff4766526 (patch)
tree880fb714f171083f6e1da4a66b7fcdc3af73bc6b
parent01b39f4737a7e3a5bb9d1e01d6e1f18d20a5b739 (diff)
downloadpdbg-2f0db42bf79bb0e91cc424dcb71ba78ff4766526.tar.gz
pdbg-2f0db42bf79bb0e91cc424dcb71ba78ff4766526.zip
main: Add HTM functions to deal with Core HTM
This commit also updates the README to only reference the new commands Signed-off-by: Cyril Bur <cyrilbur@gmail.com>
-rw-r--r--README.md16
-rw-r--r--src/htm.c222
-rw-r--r--src/htm.h2
-rw-r--r--src/main.c15
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 },
};
OpenPOWER on IntegriCloud