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 struct dexcr_aspect { 16 const char *name; 17 const char *desc; 18 unsigned int index; 19 unsigned long prctl; 20 const char *sysctl; 21 }; 22 23 static const struct dexcr_aspect aspects[] = { 24 { 25 .name = "SBHE", 26 .desc = "Speculative branch hint enable", 27 .index = 0, 28 .prctl = PR_PPC_DEXCR_SBHE, 29 .sysctl = "speculative_branch_hint_enable", 30 }, 31 { 32 .name = "IBRTPD", 33 .desc = "Indirect branch recurrent target prediction disable", 34 .index = 3, 35 .prctl = PR_PPC_DEXCR_IBRTPD, 36 .sysctl = "indirect_branch_recurrent_target_prediction_disable", 37 }, 38 { 39 .name = "SRAPD", 40 .desc = "Subroutine return address prediction disable", 41 .index = 4, 42 .prctl = PR_PPC_DEXCR_SRAPD, 43 .sysctl = "subroutine_return_address_prediction_disable", 44 }, 45 { 46 .name = "NPHIE", 47 .desc = "Non-privileged hash instruction enable", 48 .index = 5, 49 .prctl = PR_PPC_DEXCR_NPHIE, 50 .sysctl = "nonprivileged_hash_instruction_enable", 51 }, 52 { 53 .name = "PHIE", 54 .desc = "Privileged hash instruction enable", 55 .index = 6, 56 .prctl = -1, 57 .sysctl = NULL, 58 }, 59 }; 60 61 static void print_list(const char *list[], size_t len) 62 { 63 for (size_t i = 0; i < len; i++) { 64 printf("%s", list[i]); 65 if (i + 1 < len) 66 printf(", "); 67 } 68 } 69 70 static void print_dexcr(char *name, unsigned int bits) 71 { 72 const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL}; 73 size_t j = 0; 74 75 printf("%s: 0x%08x", name, bits); 76 77 if (bits == 0) { 78 printf("\n"); 79 return; 80 } 81 82 for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) { 83 unsigned int mask = DEXCR_PR_BIT(aspects[i].index); 84 85 if (bits & mask) { 86 enabled_aspects[j++] = aspects[i].name; 87 bits &= ~mask; 88 } 89 } 90 91 if (bits) 92 enabled_aspects[j++] = "unknown"; 93 94 printf(" ("); 95 print_list(enabled_aspects, j); 96 printf(")\n"); 97 } 98 99 static void print_aspect(const struct dexcr_aspect *aspect) 100 { 101 const char *attributes[8] = {NULL}; 102 size_t j = 0; 103 unsigned long mask; 104 105 mask = DEXCR_PR_BIT(aspect->index); 106 if (dexcr & mask) 107 attributes[j++] = "set"; 108 if (hdexcr & mask) 109 attributes[j++] = "set (hypervisor)"; 110 if (!(effective & mask)) 111 attributes[j++] = "clear"; 112 113 printf("%12s %c (%d): ", aspect->name, effective & mask ? '*' : ' ', aspect->index); 114 print_list(attributes, j); 115 printf(" \t(%s)\n", aspect->desc); 116 } 117 118 static void print_aspect_config(const struct dexcr_aspect *aspect) 119 { 120 char sysctl_path[128] = "/proc/sys/kernel/dexcr/"; 121 const char *reason = "unknown"; 122 const char *reason_hyp = NULL; 123 const char *reason_sysctl = "no sysctl"; 124 const char *reason_prctl = "no prctl"; 125 bool actual = effective & DEXCR_PR_BIT(aspect->index); 126 bool expected = false; 127 128 long sysctl_ctrl = 0; 129 int prctl_ctrl = 0; 130 int err; 131 132 if (aspect->prctl >= 0) { 133 prctl_ctrl = pr_get_dexcr(aspect->prctl); 134 if (prctl_ctrl < 0) 135 reason_prctl = "(failed to read prctl)"; 136 else { 137 if (prctl_ctrl & PR_PPC_DEXCR_CTRL_SET) { 138 reason_prctl = "set by prctl"; 139 expected = true; 140 } else if (prctl_ctrl & PR_PPC_DEXCR_CTRL_CLEAR) { 141 reason_prctl = "cleared by prctl"; 142 expected = false; 143 } else 144 reason_prctl = "unknown prctl"; 145 146 reason = reason_prctl; 147 } 148 } 149 150 if (aspect->sysctl) { 151 strcat(sysctl_path, aspect->sysctl); 152 err = read_long(sysctl_path, &sysctl_ctrl, 10); 153 if (err) 154 reason_sysctl = "(failed to read sysctl)"; 155 else { 156 switch (sysctl_ctrl) { 157 case 0: 158 reason_sysctl = "cleared by sysctl"; 159 reason = reason_sysctl; 160 expected = false; 161 break; 162 case 1: 163 reason_sysctl = "set by sysctl"; 164 reason = reason_sysctl; 165 expected = true; 166 break; 167 case 2: 168 reason_sysctl = "not modified by sysctl"; 169 break; 170 case 3: 171 reason_sysctl = "cleared by sysctl (permanent)"; 172 reason = reason_sysctl; 173 expected = false; 174 break; 175 case 4: 176 reason_sysctl = "set by sysctl (permanent)"; 177 reason = reason_sysctl; 178 expected = true; 179 break; 180 default: 181 reason_sysctl = "unknown sysctl"; 182 break; 183 } 184 } 185 } 186 187 188 if (hdexcr & DEXCR_PR_BIT(aspect->index)) { 189 reason_hyp = "set by hypervisor"; 190 reason = reason_hyp; 191 expected = true; 192 } else 193 reason_hyp = "not modified by hypervisor"; 194 195 printf("%12s (%d): %-28s (%s, %s, %s)\n", 196 aspect->name, 197 aspect->index, 198 reason, 199 reason_hyp, 200 reason_sysctl, 201 reason_prctl); 202 203 if (actual != expected) 204 printf(" : ! actual %s does not match config\n", aspect->name); 205 } 206 207 int main(int argc, char *argv[]) 208 { 209 if (!dexcr_exists()) { 210 printf("DEXCR not detected on this hardware\n"); 211 return 1; 212 } 213 214 dexcr = get_dexcr(DEXCR); 215 hdexcr = get_dexcr(HDEXCR); 216 effective = dexcr | hdexcr; 217 218 printf("current status:\n"); 219 220 print_dexcr(" DEXCR", dexcr); 221 print_dexcr(" HDEXCR", hdexcr); 222 print_dexcr("Effective", effective); 223 printf("\n"); 224 225 for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) 226 print_aspect(&aspects[i]); 227 printf("\n"); 228 229 if (effective & DEXCR_PR_NPHIE) { 230 printf("DEXCR[NPHIE] enabled: hashst/hashchk "); 231 if (hashchk_triggers()) 232 printf("working\n"); 233 else 234 printf("failed to trigger\n"); 235 } else { 236 printf("DEXCR[NPHIE] disabled: hashst/hashchk "); 237 if (hashchk_triggers()) 238 printf("unexpectedly triggered\n"); 239 else 240 printf("ignored\n"); 241 } 242 printf("\n"); 243 244 printf("configuration:\n"); 245 for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) 246 print_aspect_config(&aspects[i]); 247 printf("\n"); 248 249 return 0; 250 } 251