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