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
print_list(const char * list[],size_t len)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
print_dexcr(char * name,unsigned int bits)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
print_aspect(const struct dexcr_aspect * aspect)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
print_aspect_config(const struct dexcr_aspect * aspect)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
main(int argc,char * argv[])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