diff options
author | Cyril Bur <cyrilbur@gmail.com> | 2018-02-14 15:27:42 +1100 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2018-02-16 16:22:23 +1100 |
commit | 2f0db42bf79bb0e91cc424dcb71ba78ff4766526 (patch) | |
tree | 880fb714f171083f6e1da4a66b7fcdc3af73bc6b | |
parent | 01b39f4737a7e3a5bb9d1e01d6e1f18d20a5b739 (diff) | |
download | pdbg-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.md | 16 | ||||
-rw-r--r-- | src/htm.c | 222 | ||||
-rw-r--r-- | src/htm.h | 2 | ||||
-rw-r--r-- | src/main.c | 15 |
4 files changed, 167 insertions, 88 deletions
@@ -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. @@ -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); +} @@ -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[]); @@ -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 }, }; |