1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <err.h>
4 #include <getopt.h>
5 #include <string.h>
6
7 #include <xenctrl.h>
8
9 #define ARRAY_SIZE(a) (sizeof a / sizeof *a)
10 static uint32_t nr_features;
11
12 static const char *str_1d[32] =
13 {
14 [ 0] = "fpu", [ 1] = "vme",
15 [ 2] = "de", [ 3] = "pse",
16 [ 4] = "tsc", [ 5] = "msr",
17 [ 6] = "pae", [ 7] = "mce",
18 [ 8] = "cx8", [ 9] = "apic",
19 [10] = "REZ", [11] = "sysenter",
20 [12] = "mtrr", [13] = "pge",
21 [14] = "mca", [15] = "cmov",
22 [16] = "pat", [17] = "pse36",
23 [18] = "psn", [19] = "clflush",
24 [20] = "REZ", [21] = "ds",
25 [22] = "acpi", [23] = "mmx",
26 [24] = "fxsr", [25] = "sse",
27 [26] = "sse2", [27] = "ss",
28 [28] = "htt", [29] = "tm",
29 [30] = "ia64", [31] = "pbe",
30 };
31
32 static const char *str_1c[32] =
33 {
34 [ 0] = "sse3", [ 1] = "pclmulqdq",
35 [ 2] = "dtes64", [ 3] = "monitor",
36 [ 4] = "ds-cpl", [ 5] = "vmx",
37 [ 6] = "smx", [ 7] = "est",
38 [ 8] = "tm2", [ 9] = "ssse3",
39 [10] = "cntx-id", [11] = "sdgb",
40 [12] = "fma", [13] = "cx16",
41 [14] = "xtpr", [15] = "pdcm",
42 [16] = "REZ", [17] = "pcid",
43 [18] = "dca", [19] = "sse41",
44 [20] = "sse42", [21] = "x2apic",
45 [22] = "movebe", [23] = "popcnt",
46 [24] = "tsc-dl", [25] = "aesni",
47 [26] = "xsave", [27] = "osxsave",
48 [28] = "avx", [29] = "f16c",
49 [30] = "rdrnd", [31] = "hyper",
50 };
51
52 static const char *str_e1d[32] =
53 {
54 [ 0] = "fpu", [ 1] = "vme",
55 [ 2] = "de", [ 3] = "pse",
56 [ 4] = "tsc", [ 5] = "msr",
57 [ 6] = "pae", [ 7] = "mce",
58 [ 8] = "cx8", [ 9] = "apic",
59 [10] = "REZ", [11] = "syscall",
60 [12] = "mtrr", [13] = "pge",
61 [14] = "mca", [15] = "cmov",
62 [16] = "fcmov", [17] = "pse36",
63 [18] = "REZ", [19] = "mp",
64 [20] = "nx", [21] = "REZ",
65 [22] = "mmx+", [23] = "mmx",
66 [24] = "fxsr", [25] = "fxsr+",
67 [26] = "pg1g", [27] = "rdtscp",
68 [28] = "REZ", [29] = "lm",
69 [30] = "3dnow+", [31] = "3dnow",
70 };
71
72 static const char *str_e1c[32] =
73 {
74 [ 0] = "lahf_lm", [ 1] = "cmp",
75 [ 2] = "svm", [ 3] = "extapic",
76 [ 4] = "cr8d", [ 5] = "lzcnt",
77 [ 6] = "sse4a", [ 7] = "msse",
78 [ 8] = "3dnowpf", [ 9] = "osvw",
79 [10] = "ibs", [11] = "xop",
80 [12] = "skinit", [13] = "wdt",
81 [14] = "REZ", [15] = "lwp",
82 [16] = "fma4", [17] = "tce",
83 [18] = "REZ", [19] = "nodeid",
84 [20] = "REZ", [21] = "tbm",
85 [22] = "topoext", [23] = "perfctr_core",
86 [24] = "perfctr_nb", [25] = "REZ",
87 [26] = "dbx", [27] = "perftsc",
88 [28] = "pcx_l2i", [29] = "monitorx",
89
90 [30 ... 31] = "REZ",
91 };
92
93 static const char *str_7b0[32] =
94 {
95 [ 0] = "fsgsbase", [ 1] = "tsc-adj",
96 [ 2] = "sgx", [ 3] = "bmi1",
97 [ 4] = "hle", [ 5] = "avx2",
98 [ 6] = "fdp_exn", [ 7] = "smep",
99 [ 8] = "bmi2", [ 9] = "erms",
100 [10] = "invpcid", [11] = "rtm",
101 [12] = "pqm", [13] = "depfpp",
102 [14] = "mpx", [15] = "pqe",
103 [16] = "avx512f", [17] = "avx512dq",
104 [18] = "rdseed", [19] = "adx",
105 [20] = "smap", [21] = "avx512ifma",
106 [22] = "pcomit", [23] = "clflushopt",
107 [24] = "clwb", [25] = "pt",
108 [26] = "avx512pf", [27] = "avx512er",
109 [28] = "avx512cd", [29] = "sha",
110 [30] = "avx512bw", [31] = "avx512vl",
111 };
112
113 static const char *str_Da1[32] =
114 {
115 [ 0] = "xsaveopt", [ 1] = "xsavec",
116 [ 2] = "xgetbv1", [ 3] = "xsaves",
117
118 [4 ... 31] = "REZ",
119 };
120
121 static const char *str_7c0[32] =
122 {
123 [ 0] = "prechwt1", [ 1] = "avx512vbmi",
124 [ 2] = "umip", [ 3] = "pku",
125 [ 4] = "ospke",
126
127 [5 ... 13] = "REZ",
128
129 [14] = "avx512_vpopcntdq",
130
131 [15 ... 21] = "REZ",
132
133 [22] = "rdpid",
134
135 [23 ... 31] = "REZ",
136 };
137
138 static const char *str_e7d[32] =
139 {
140 [0 ... 7] = "REZ",
141
142 [ 8] = "itsc", [ 9] = "REZ",
143 [10] = "efro",
144
145 [11 ... 31] = "REZ",
146 };
147
148 static const char *str_e8b[32] =
149 {
150 [ 0] = "clzero",
151
152 [1 ... 31] = "REZ",
153 };
154
155 static const char *str_7d0[32] =
156 {
157 [0 ... 1] = "REZ",
158
159 [ 2] = "avx512_4vnniw", [ 3] = "avx512_4fmaps",
160
161 [4 ... 31] = "REZ",
162 };
163
164 static struct {
165 const char *name;
166 const char *abbr;
167 const char **strs;
168 } decodes[] =
169 {
170 { "0x00000001.edx", "1d", str_1d },
171 { "0x00000001.ecx", "1c", str_1c },
172 { "0x80000001.edx", "e1d", str_e1d },
173 { "0x80000001.ecx", "e1c", str_e1c },
174 { "0x0000000d:1.eax", "Da1", str_Da1 },
175 { "0x00000007:0.ebx", "7b0", str_7b0 },
176 { "0x00000007:0.ecx", "7c0", str_7c0 },
177 { "0x80000007.edx", "e7d", str_e7d },
178 { "0x80000008.ebx", "e8b", str_e8b },
179 { "0x00000007:0.edx", "7d0", str_7d0 },
180 };
181
182 #define COL_ALIGN "18"
183
184 static struct fsinfo {
185 const char *name;
186 uint32_t len;
187 uint32_t *fs;
188 } featuresets[] =
189 {
190 [XEN_SYSCTL_cpu_featureset_host] = { "Host", 0, NULL },
191 [XEN_SYSCTL_cpu_featureset_raw] = { "Raw", 0, NULL },
192 [XEN_SYSCTL_cpu_featureset_pv] = { "PV", 0, NULL },
193 [XEN_SYSCTL_cpu_featureset_hvm] = { "HVM", 0, NULL },
194 };
195
dump_leaf(uint32_t leaf,const char ** strs)196 static void dump_leaf(uint32_t leaf, const char **strs)
197 {
198 unsigned i;
199
200 if ( !strs )
201 {
202 printf(" ???");
203 return;
204 }
205
206 for ( i = 0; i < 32; ++i )
207 if ( leaf & (1u << i) )
208 printf(" %s", strs[i] ?: "???" );
209 }
210
decode_featureset(const uint32_t * features,const uint32_t length,const char * name,bool detail)211 static void decode_featureset(const uint32_t *features,
212 const uint32_t length,
213 const char *name,
214 bool detail)
215 {
216 unsigned int i;
217
218 printf("%-"COL_ALIGN"s ", name);
219 for ( i = 0; i < length; ++i )
220 printf("%08x%c", features[i],
221 i < length - 1 ? ':' : '\n');
222
223 if ( !detail )
224 return;
225
226 for ( i = 0; i < length && i < ARRAY_SIZE(decodes); ++i )
227 {
228 printf(" [%02u] %-"COL_ALIGN"s", i, decodes[i].name ?: "<UNKNOWN>");
229 if ( decodes[i].name )
230 dump_leaf(features[i], decodes[i].strs);
231 printf("\n");
232 }
233 }
234
get_featureset(xc_interface * xch,unsigned int idx)235 static void get_featureset(xc_interface *xch, unsigned int idx)
236 {
237 struct fsinfo *f = &featuresets[idx];
238
239 f->len = xc_get_cpu_featureset_size();
240 f->fs = calloc(nr_features, sizeof(*f->fs));
241
242 if ( !f->fs )
243 err(1, "calloc(, featureset)");
244
245 if ( xc_get_cpu_featureset(xch, idx, &f->len, f->fs) )
246 err(1, "xc_get_featureset()");
247 }
248
dump_info(xc_interface * xch,bool detail)249 static void dump_info(xc_interface *xch, bool detail)
250 {
251 unsigned int i;
252
253 printf("nr_features: %u\n", nr_features);
254
255 if ( !detail )
256 {
257 printf(" %"COL_ALIGN"s ", "KEY");
258 for ( i = 0; i < ARRAY_SIZE(decodes); ++i )
259 printf("%-8s ", decodes[i].abbr ?: "???");
260 printf("\n");
261 }
262
263 printf("\nStatic sets:\n");
264 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_KNOWN),
265 nr_features, "Known", detail);
266 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_SPECIAL),
267 nr_features, "Special", detail);
268 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_PV),
269 nr_features, "PV Mask", detail);
270 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_SHADOW),
271 nr_features, "HVM Shadow Mask", detail);
272 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_HAP),
273 nr_features, "HVM Hap Mask", detail);
274
275 printf("\nDynamic sets:\n");
276 for ( i = 0; i < ARRAY_SIZE(featuresets); ++i )
277 {
278 get_featureset(xch, i);
279
280 decode_featureset(featuresets[i].fs, featuresets[i].len,
281 featuresets[i].name, detail);
282 }
283
284 for ( i = 0; i < ARRAY_SIZE(featuresets); ++i )
285 free(featuresets[i].fs);
286 }
287
main(int argc,char ** argv)288 int main(int argc, char **argv)
289 {
290 enum { MODE_UNKNOWN, MODE_INFO, MODE_DETAIL, MODE_INTERPRET }
291 mode = MODE_UNKNOWN;
292
293 nr_features = xc_get_cpu_featureset_size();
294
295 for ( ;; )
296 {
297 int option_index = 0, c;
298 static struct option long_options[] =
299 {
300 { "help", no_argument, NULL, 'h' },
301 { "info", no_argument, NULL, 'i' },
302 { "detail", no_argument, NULL, 'd' },
303 { "verbose", no_argument, NULL, 'v' },
304 { NULL, 0, NULL, 0 },
305 };
306
307 c = getopt_long(argc, argv, "hidv", long_options, &option_index);
308
309 if ( c == -1 )
310 break;
311
312 switch ( c )
313 {
314 default:
315 printf("Bad option '%c'\n", c);
316 /* Fallthough */
317 case 'h':
318 printf("Usage: %s [ info | detail | <featureset>* ]\n", argv[0]);
319 return 0;
320
321 case 'i':
322 mode = MODE_INFO;
323 break;
324
325 case 'd':
326 case 'v':
327 mode = MODE_DETAIL;
328 break;
329 }
330 }
331
332 if ( mode == MODE_UNKNOWN )
333 {
334 if ( optind == argc )
335 mode = MODE_INFO;
336 else if ( optind < argc )
337 {
338 if ( !strcmp(argv[optind], "info") )
339 {
340 mode = MODE_INFO;
341 optind++;
342 }
343 else if ( !strcmp(argv[optind], "detail") )
344 {
345 mode = MODE_DETAIL;
346 optind++;
347 }
348 else
349 mode = MODE_INTERPRET;
350 }
351 else
352 mode = MODE_INTERPRET;
353 }
354
355 if ( mode == MODE_INFO || mode == MODE_DETAIL )
356 {
357 xc_interface *xch = xc_interface_open(0, 0, 0);
358
359 if ( !xch )
360 err(1, "xc_interface_open");
361
362 if ( xc_get_cpu_featureset(xch, 0, &nr_features, NULL) )
363 err(1, "xc_get_featureset(, NULL)");
364
365 dump_info(xch, mode == MODE_DETAIL);
366
367 xc_interface_close(xch);
368 }
369 else
370 {
371 uint32_t fs[nr_features + 1];
372
373 while ( optind < argc )
374 {
375 char *ptr = argv[optind++];
376 unsigned int i = 0;
377 int offset;
378
379 memset(fs, 0, sizeof(fs));
380
381 while ( sscanf(ptr, "%x%n", &fs[i], &offset) == 1 )
382 {
383 i++;
384 ptr += offset;
385
386 if ( i == nr_features )
387 break;
388
389 if ( *ptr == ':' )
390 {
391 ptr++; continue;
392 }
393 break;
394 }
395
396 decode_featureset(fs, i, "Raw", true);
397 }
398 }
399
400 return 0;
401 }
402
403 /*
404 * Local variables:
405 * mode: C
406 * c-file-style: "BSD"
407 * c-basic-offset: 4
408 * tab-width: 4
409 * indent-tabs-mode: nil
410 * End:
411 */
412