// 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; 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: 0x%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); } static void print_aspect_config(const struct dexcr_aspect *aspect) { const char *reason = NULL; const char *reason_hyp = NULL; const char *reason_prctl = "no prctl"; bool actual = effective & DEXCR_PR_BIT(aspect->index); 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 (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) { reason_prctl = "cleared by prctl"; expected = false; } else { reason_prctl = "unknown prctl"; } reason = reason_prctl; } } if (hdexcr & DEXCR_PR_BIT(aspect->index)) { reason_hyp = "set by hypervisor"; reason = reason_hyp; expected = true; } else { reason_hyp = "not modified by hypervisor"; } printf("%12s (%d): %-28s (%s, %s)\n", aspect->name, aspect->index, reason, reason_hyp, 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); } 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; printf("current status:\n"); 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"); } printf("\n"); printf("configuration:\n"); for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) print_aspect_config(&aspects[i]); printf("\n"); return 0; }