| // SPDX-License-Identifier: GPL-2.0+ | |
| #include <stddef.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <sys/prctl.h> | |
| #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; | |
| } |