From a16e472c3546ba0b8a4be265c008d02ef6aed899 Mon Sep 17 00:00:00 2001 From: Benjamin Gray Date: Mon, 19 Jun 2023 17:36:28 +1000 Subject: [PATCH] selftests/powerpc/dexcr: Add DEXCR status utility lsdexcr Add a utility 'lsdexcr' to print the current DEXCR status. Useful for quickly checking the status such as when debugging test failures or verifying the new default DEXCR does what you want (for userspace at least). Example output: # ./lsdexcr uDEXCR: 04000000 (NPHIE) HDEXCR: 00000000 Effective: 04000000 (NPHIE) SBHE (0): clear (Speculative branch hint enable) IBRTPD (3): clear (Indirect branch recurrent target ...) SRAPD (4): clear (Subroutine return address ...) NPHIE * (5): set (Non-privileged hash instruction enable) PHIE (6): clear (Privileged hash instruction enable) DEXCR[NPHIE] enabled: hashst/hashchk working Signed-off-by: Benjamin Gray Signed-off-by: Michael Ellerman Link: https://msgid.link/20230616034846.311705-12-bgray@linux.ibm.com --- .../selftests/powerpc/dexcr/.gitignore | 1 + .../testing/selftests/powerpc/dexcr/Makefile | 2 + .../testing/selftests/powerpc/dexcr/lsdexcr.c | 141 ++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 tools/testing/selftests/powerpc/dexcr/lsdexcr.c diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore index d12e4560aca9..b82f45dd46b9 100644 --- a/tools/testing/selftests/powerpc/dexcr/.gitignore +++ b/tools/testing/selftests/powerpc/dexcr/.gitignore @@ -1 +1,2 @@ hashchk_test +lsdexcr diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile index 16c8b489948a..76210f2bcec3 100644 --- a/tools/testing/selftests/powerpc/dexcr/Makefile +++ b/tools/testing/selftests/powerpc/dexcr/Makefile @@ -1,7 +1,9 @@ TEST_GEN_PROGS := hashchk_test +TEST_GEN_FILES := lsdexcr include ../../lib.mk $(OUTPUT)/hashchk_test: CFLAGS += -fno-pie $(call cc-option,-mno-rop-protect) $(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c +$(TEST_GEN_FILES): ../utils.c ./dexcr.c diff --git a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c new file mode 100644 index 000000000000..94abbfcc389e --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include + +#include "dexcr.h" +#include "utils.h" + +static unsigned int dexcr; +static unsigned int hdexcr; +static unsigned int effective; + +struct dexcr_aspect { + const char *name; + const char *desc; + unsigned int index; +}; + +static const struct dexcr_aspect aspects[] = { + { + .name = "SBHE", + .desc = "Speculative branch hint enable", + .index = 0, + }, + { + .name = "IBRTPD", + .desc = "Indirect branch recurrent target prediction disable", + .index = 3, + }, + { + .name = "SRAPD", + .desc = "Subroutine return address prediction disable", + .index = 4, + }, + { + .name = "NPHIE", + .desc = "Non-privileged hash instruction enable", + .index = 5, + }, + { + .name = "PHIE", + .desc = "Privileged hash instruction enable", + .index = 6, + }, +}; + +static void print_list(const char *list[], size_t len) +{ + for (size_t i = 0; i < len; i++) { + printf("%s", list[i]); + if (i + 1 < len) + printf(", "); + } +} + +static void print_dexcr(char *name, unsigned int bits) +{ + const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL}; + size_t j = 0; + + printf("%s: %08x", name, bits); + + if (bits == 0) { + printf("\n"); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) { + unsigned int mask = DEXCR_PR_BIT(aspects[i].index); + + if (bits & mask) { + enabled_aspects[j++] = aspects[i].name; + bits &= ~mask; + } + } + + if (bits) + enabled_aspects[j++] = "unknown"; + + printf(" ("); + print_list(enabled_aspects, j); + printf(")\n"); +} + +static void print_aspect(const struct dexcr_aspect *aspect) +{ + const char *attributes[8] = {NULL}; + size_t j = 0; + unsigned long mask; + + mask = DEXCR_PR_BIT(aspect->index); + if (dexcr & mask) + attributes[j++] = "set"; + if (hdexcr & mask) + attributes[j++] = "set (hypervisor)"; + if (!(effective & mask)) + attributes[j++] = "clear"; + + printf("%12s %c (%d): ", aspect->name, effective & mask ? '*' : ' ', aspect->index); + print_list(attributes, j); + printf(" \t(%s)\n", aspect->desc); +} + +int main(int argc, char *argv[]) +{ + if (!dexcr_exists()) { + printf("DEXCR not detected on this hardware\n"); + return 1; + } + + dexcr = get_dexcr(DEXCR); + hdexcr = get_dexcr(HDEXCR); + effective = dexcr | hdexcr; + + print_dexcr(" DEXCR", dexcr); + print_dexcr(" HDEXCR", hdexcr); + print_dexcr("Effective", effective); + printf("\n"); + + for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) + print_aspect(&aspects[i]); + printf("\n"); + + if (effective & DEXCR_PR_NPHIE) { + printf("DEXCR[NPHIE] enabled: hashst/hashchk "); + if (hashchk_triggers()) + printf("working\n"); + else + printf("failed to trigger\n"); + } else { + printf("DEXCR[NPHIE] disabled: hashst/hashchk "); + if (hashchk_triggers()) + printf("unexpectedly triggered\n"); + else + printf("ignored\n"); + } + + return 0; +}