xref: /linux/tools/testing/selftests/powerpc/dexcr/lsdexcr.c (revision ff2632d7d08edc11e8bd0629e9fcfebab25c78b4)
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