1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <stddef.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <sys/prctl.h> 7 8 #include "dexcr.h" 9 #include "utils.h" 10 11 static unsigned int dexcr; 12 static unsigned int hdexcr; 13 static unsigned int effective; 14 15 static void print_list(const char *list[], size_t len) 16 { 17 for (size_t i = 0; i < len; i++) { 18 printf("%s", list[i]); 19 if (i + 1 < len) 20 printf(", "); 21 } 22 } 23 24 static void print_dexcr(char *name, unsigned int bits) 25 { 26 const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL}; 27 size_t j = 0; 28 29 printf("%s: 0x%08x", name, bits); 30 31 if (bits == 0) { 32 printf("\n"); 33 return; 34 } 35 36 for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) { 37 unsigned int mask = DEXCR_PR_BIT(aspects[i].index); 38 39 if (bits & mask) { 40 enabled_aspects[j++] = aspects[i].name; 41 bits &= ~mask; 42 } 43 } 44 45 if (bits) 46 enabled_aspects[j++] = "unknown"; 47 48 printf(" ("); 49 print_list(enabled_aspects, j); 50 printf(")\n"); 51 } 52 53 static void print_aspect(const struct dexcr_aspect *aspect) 54 { 55 const char *attributes[8] = {NULL}; 56 size_t j = 0; 57 unsigned long mask; 58 59 mask = DEXCR_PR_BIT(aspect->index); 60 if (dexcr & mask) 61 attributes[j++] = "set"; 62 if (hdexcr & mask) 63 attributes[j++] = "set (hypervisor)"; 64 if (!(effective & mask)) 65 attributes[j++] = "clear"; 66 67 printf("%12s %c (%d): ", aspect->name, effective & mask ? '*' : ' ', aspect->index); 68 print_list(attributes, j); 69 printf(" \t(%s)\n", aspect->desc); 70 } 71 72 static void print_aspect_config(const struct dexcr_aspect *aspect) 73 { 74 const char *reason = NULL; 75 const char *reason_hyp = NULL; 76 const char *reason_prctl = "no prctl"; 77 bool actual = effective & DEXCR_PR_BIT(aspect->index); 78 bool expected = actual; /* Assume it's fine if we don't expect a specific set/clear value */ 79 80 if (actual) 81 reason = "set by unknown"; 82 else 83 reason = "cleared by unknown"; 84 85 if (aspect->prctl != -1) { 86 int ctrl = pr_get_dexcr(aspect->prctl); 87 88 if (ctrl < 0) { 89 reason_prctl = "failed to read prctl"; 90 } else { 91 if (ctrl & PR_PPC_DEXCR_CTRL_SET) { 92 reason_prctl = "set by prctl"; 93 expected = true; 94 } else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) { 95 reason_prctl = "cleared by prctl"; 96 expected = false; 97 } else { 98 reason_prctl = "unknown prctl"; 99 } 100 101 reason = reason_prctl; 102 } 103 } 104 105 if (hdexcr & DEXCR_PR_BIT(aspect->index)) { 106 reason_hyp = "set by hypervisor"; 107 reason = reason_hyp; 108 expected = true; 109 } else { 110 reason_hyp = "not modified by hypervisor"; 111 } 112 113 printf("%12s (%d): %-28s (%s, %s)\n", 114 aspect->name, 115 aspect->index, 116 reason, 117 reason_hyp, 118 reason_prctl); 119 120 /* 121 * The checks are not atomic, so this can technically trigger if the 122 * hypervisor makes a change while we are checking each source. It's 123 * far more likely to be a bug if we see this though. 124 */ 125 if (actual != expected) 126 printf(" : ! actual %s does not match config\n", aspect->name); 127 } 128 129 int main(int argc, char *argv[]) 130 { 131 if (!dexcr_exists()) { 132 printf("DEXCR not detected on this hardware\n"); 133 return 1; 134 } 135 136 dexcr = get_dexcr(DEXCR); 137 hdexcr = get_dexcr(HDEXCR); 138 effective = dexcr | hdexcr; 139 140 printf("current status:\n"); 141 142 print_dexcr(" DEXCR", dexcr); 143 print_dexcr(" HDEXCR", hdexcr); 144 print_dexcr("Effective", effective); 145 printf("\n"); 146 147 for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) 148 print_aspect(&aspects[i]); 149 printf("\n"); 150 151 if (effective & DEXCR_PR_NPHIE) { 152 printf("DEXCR[NPHIE] enabled: hashst/hashchk "); 153 if (hashchk_triggers()) 154 printf("working\n"); 155 else 156 printf("failed to trigger\n"); 157 } else { 158 printf("DEXCR[NPHIE] disabled: hashst/hashchk "); 159 if (hashchk_triggers()) 160 printf("unexpectedly triggered\n"); 161 else 162 printf("ignored\n"); 163 } 164 printf("\n"); 165 166 printf("configuration:\n"); 167 for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) 168 print_aspect_config(&aspects[i]); 169 printf("\n"); 170 171 return 0; 172 } 173