1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <err.h>
4 #include <getopt.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <limits.h>
8 #include <inttypes.h>
9
10 #include <xenctrl.h>
11
12 #include <xen-tools/libs.h>
13
14 static uint32_t nr_features;
15
16 static const char *const str_1d[32] =
17 {
18 [ 0] = "fpu", [ 1] = "vme",
19 [ 2] = "de", [ 3] = "pse",
20 [ 4] = "tsc", [ 5] = "msr",
21 [ 6] = "pae", [ 7] = "mce",
22 [ 8] = "cx8", [ 9] = "apic",
23 /* [10] */ [11] = "sysenter",
24 [12] = "mtrr", [13] = "pge",
25 [14] = "mca", [15] = "cmov",
26 [16] = "pat", [17] = "pse36",
27 [18] = "psn", [19] = "clflush",
28 /* [20] */ [21] = "ds",
29 [22] = "acpi", [23] = "mmx",
30 [24] = "fxsr", [25] = "sse",
31 [26] = "sse2", [27] = "ss",
32 [28] = "htt", [29] = "tm",
33 [30] = "ia64", [31] = "pbe",
34 };
35
36 static const char *const str_1c[32] =
37 {
38 [ 0] = "sse3", [ 1] = "pclmulqdq",
39 [ 2] = "dtes64", [ 3] = "monitor",
40 [ 4] = "ds-cpl", [ 5] = "vmx",
41 [ 6] = "smx", [ 7] = "est",
42 [ 8] = "tm2", [ 9] = "ssse3",
43 [10] = "cntx-id", [11] = "sdgb",
44 [12] = "fma", [13] = "cx16",
45 [14] = "xtpr", [15] = "pdcm",
46 /* [16] */ [17] = "pcid",
47 [18] = "dca", [19] = "sse41",
48 [20] = "sse42", [21] = "x2apic",
49 [22] = "movebe", [23] = "popcnt",
50 [24] = "tsc-dl", [25] = "aesni",
51 [26] = "xsave", [27] = "osxsave",
52 [28] = "avx", [29] = "f16c",
53 [30] = "rdrnd", [31] = "hyper",
54 };
55
56 static const char *const str_e1d[32] =
57 {
58 [ 0] = "fpu", [ 1] = "vme",
59 [ 2] = "de", [ 3] = "pse",
60 [ 4] = "tsc", [ 5] = "msr",
61 [ 6] = "pae", [ 7] = "mce",
62 [ 8] = "cx8", [ 9] = "apic",
63 /* [10] */ [11] = "syscall",
64 [12] = "mtrr", [13] = "pge",
65 [14] = "mca", [15] = "cmov",
66 [16] = "fcmov", [17] = "pse36",
67 /* [18] */ [19] = "mp",
68 [20] = "nx", /* [21] */
69 [22] = "mmx+", [23] = "mmx",
70 [24] = "fxsr", [25] = "fxsr+",
71 [26] = "pg1g", [27] = "rdtscp",
72 /* [28] */ [29] = "lm",
73 [30] = "3dnow+", [31] = "3dnow",
74 };
75
76 static const char *const str_e1c[32] =
77 {
78 [ 0] = "lahf_lm", [ 1] = "cmp",
79 [ 2] = "svm", [ 3] = "extapic",
80 [ 4] = "cr8d", [ 5] = "lzcnt",
81 [ 6] = "sse4a", [ 7] = "msse",
82 [ 8] = "3dnowpf", [ 9] = "osvw",
83 [10] = "ibs", [11] = "xop",
84 [12] = "skinit", [13] = "wdt",
85 /* [14] */ [15] = "lwp",
86 [16] = "fma4", [17] = "tce",
87 /* [18] */ [19] = "nodeid",
88 /* [20] */ [21] = "tbm",
89 [22] = "topoext", [23] = "perfctr_core",
90 [24] = "perfctr_nb", /* [25] */
91 [26] = "dbx", [27] = "perftsc",
92 [28] = "pcx_l2i", [29] = "monitorx",
93 };
94
95 static const char *const str_7b0[32] =
96 {
97 [ 0] = "fsgsbase", [ 1] = "tsc-adj",
98 [ 2] = "sgx", [ 3] = "bmi1",
99 [ 4] = "hle", [ 5] = "avx2",
100 [ 6] = "fdp_exn", [ 7] = "smep",
101 [ 8] = "bmi2", [ 9] = "erms",
102 [10] = "invpcid", [11] = "rtm",
103 [12] = "pqm", [13] = "depfpp",
104 [14] = "mpx", [15] = "pqe",
105 [16] = "avx512f", [17] = "avx512dq",
106 [18] = "rdseed", [19] = "adx",
107 [20] = "smap", [21] = "avx512-ifma",
108 [22] = "pcommit", [23] = "clflushopt",
109 [24] = "clwb", [25] = "pt",
110 [26] = "avx512pf", [27] = "avx512er",
111 [28] = "avx512cd", [29] = "sha",
112 [30] = "avx512bw", [31] = "avx512vl",
113 };
114
115 static const char *const str_Da1[32] =
116 {
117 [ 0] = "xsaveopt", [ 1] = "xsavec",
118 [ 2] = "xgetbv1", [ 3] = "xsaves",
119 };
120
121 static const char *const str_7c0[32] =
122 {
123 [ 0] = "prefetchwt1", [ 1] = "avx512_vbmi",
124 [ 2] = "umip", [ 3] = "pku",
125 [ 4] = "ospke", [ 5] = "waitpkg",
126 [ 6] = "avx512_vbmi2", [ 7] = "cet-ss",
127 [ 8] = "gfni", [ 9] = "vaes",
128 [10] = "vpclmulqdq", [11] = "avx512_vnni",
129 [12] = "avx512_bitalg",
130 [14] = "avx512_vpopcntdq",
131 [16] = "tsxldtrk",
132
133 [22] = "rdpid",
134 /* 24 */ [25] = "cldemote",
135 /* 26 */ [27] = "movdiri",
136 [28] = "movdir64b",
137 [30] = "sgx_lc",
138 };
139
140 static const char *const str_e7d[32] =
141 {
142 [ 8] = "itsc",
143 [10] = "efro",
144 };
145
146 static const char *const str_e8b[32] =
147 {
148 [ 0] = "clzero",
149 [ 2] = "rstr-fp-err-ptrs",
150
151 /* [ 8] */ [ 9] = "wbnoinvd",
152
153 [12] = "ibpb",
154
155 /* [22] */ [23] = "ppin",
156 };
157
158 static const char *const str_7d0[32] =
159 {
160 [ 2] = "avx512_4vnniw", [ 3] = "avx512_4fmaps",
161 [ 4] = "fsrm",
162
163 /* 8 */ [ 9] = "srbds-ctrl",
164 [10] = "md-clear",
165 /* 12 */ [13] = "tsx-force-abort",
166 [14] = "serialize",
167
168 [18] = "pconfig",
169 [20] = "cet-ibt",
170
171 [26] = "ibrsb", [27] = "stibp",
172 [28] = "l1d_flush", [29] = "arch_caps",
173 [30] = "core_caps", [31] = "ssbd",
174 };
175
176 static const char *const str_7a1[32] =
177 {
178 /* 4 */ [ 5] = "avx512_bf16",
179 };
180
181 static const struct {
182 const char *name;
183 const char *abbr;
184 const char *const *strs;
185 } decodes[] =
186 {
187 { "0x00000001.edx", "1d", str_1d },
188 { "0x00000001.ecx", "1c", str_1c },
189 { "0x80000001.edx", "e1d", str_e1d },
190 { "0x80000001.ecx", "e1c", str_e1c },
191 { "0x0000000d:1.eax", "Da1", str_Da1 },
192 { "0x00000007:0.ebx", "7b0", str_7b0 },
193 { "0x00000007:0.ecx", "7c0", str_7c0 },
194 { "0x80000007.edx", "e7d", str_e7d },
195 { "0x80000008.ebx", "e8b", str_e8b },
196 { "0x00000007:0.edx", "7d0", str_7d0 },
197 { "0x00000007:1.eax", "7a1", str_7a1 },
198 };
199
200 #define COL_ALIGN "18"
201
202 static struct fsinfo {
203 const char *name;
204 uint32_t len;
205 uint32_t *fs;
206 } featuresets[] =
207 {
208 [XEN_SYSCTL_cpu_featureset_host] = { "Host", 0, NULL },
209 [XEN_SYSCTL_cpu_featureset_raw] = { "Raw", 0, NULL },
210 [XEN_SYSCTL_cpu_featureset_pv] = { "PV", 0, NULL },
211 [XEN_SYSCTL_cpu_featureset_hvm] = { "HVM", 0, NULL },
212 };
213
dump_leaf(uint32_t leaf,const char * const * strs)214 static void dump_leaf(uint32_t leaf, const char *const *strs)
215 {
216 unsigned i;
217
218 if ( !strs )
219 {
220 printf(" ???");
221 return;
222 }
223
224 for ( i = 0; i < 32; ++i )
225 if ( leaf & (1u << i) )
226 {
227 if ( strs[i] )
228 printf(" %s", strs[i]);
229 else
230 printf(" <%u>", i);
231 }
232 }
233
decode_featureset(const uint32_t * features,const uint32_t length,const char * name,bool detail)234 static void decode_featureset(const uint32_t *features,
235 const uint32_t length,
236 const char *name,
237 bool detail)
238 {
239 unsigned int i;
240
241 printf("%-"COL_ALIGN"s ", name);
242 for ( i = 0; i < length; ++i )
243 printf("%08x%c", features[i],
244 i < length - 1 ? ':' : '\n');
245
246 if ( !detail )
247 return;
248
249 for ( i = 0; i < length && i < ARRAY_SIZE(decodes); ++i )
250 {
251 printf(" [%02u] %-"COL_ALIGN"s", i, decodes[i].name ?: "<UNKNOWN>");
252 if ( decodes[i].name )
253 dump_leaf(features[i], decodes[i].strs);
254 printf("\n");
255 }
256 }
257
get_featureset(xc_interface * xch,unsigned int idx)258 static int get_featureset(xc_interface *xch, unsigned int idx)
259 {
260 struct fsinfo *f = &featuresets[idx];
261
262 f->len = nr_features;
263 f->fs = calloc(nr_features, sizeof(*f->fs));
264
265 if ( !f->fs )
266 err(1, "calloc(, featureset)");
267
268 return xc_get_cpu_featureset(xch, idx, &f->len, f->fs);
269 }
270
dump_info(xc_interface * xch,bool detail)271 static void dump_info(xc_interface *xch, bool detail)
272 {
273 unsigned int i;
274
275 printf("nr_features: %u\n", nr_features);
276
277 if ( !detail )
278 {
279 printf(" %"COL_ALIGN"s ", "KEY");
280 for ( i = 0; i < ARRAY_SIZE(decodes); ++i )
281 printf("%-8s ", decodes[i].abbr ?: "???");
282 printf("\n");
283 }
284
285 printf("\nStatic sets:\n");
286 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_KNOWN),
287 nr_features, "Known", detail);
288 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_SPECIAL),
289 nr_features, "Special", detail);
290 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_PV_MAX),
291 nr_features, "PV Max", detail);
292 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_PV_DEF),
293 nr_features, "PV Default", detail);
294 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_SHADOW_MAX),
295 nr_features, "HVM Shadow Max", detail);
296 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_SHADOW_DEF),
297 nr_features, "HVM Shadow Default", detail);
298 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_HAP_MAX),
299 nr_features, "HVM Hap Max", detail);
300 decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_HAP_DEF),
301 nr_features, "HVM Hap Default", detail);
302
303 printf("\nDynamic sets:\n");
304 for ( i = 0; i < ARRAY_SIZE(featuresets); ++i )
305 {
306 if ( get_featureset(xch, i) )
307 {
308 if ( errno == EOPNOTSUPP )
309 {
310 printf("%s featureset not supported by Xen\n",
311 featuresets[i].name);
312 continue;
313 }
314
315 err(1, "xc_get_featureset()");
316 }
317
318 decode_featureset(featuresets[i].fs, featuresets[i].len,
319 featuresets[i].name, detail);
320 }
321
322 for ( i = 0; i < ARRAY_SIZE(featuresets); ++i )
323 free(featuresets[i].fs);
324 }
325
print_policy(const char * name,xen_cpuid_leaf_t * leaves,uint32_t nr_leaves,xen_msr_entry_t * msrs,uint32_t nr_msrs)326 static void print_policy(const char *name,
327 xen_cpuid_leaf_t *leaves, uint32_t nr_leaves,
328 xen_msr_entry_t *msrs, uint32_t nr_msrs)
329 {
330 unsigned int l;
331
332 printf("%s policy: %u leaves, %u MSRs\n", name, nr_leaves, nr_msrs);
333 printf(" CPUID:\n");
334 printf(" %-8s %-8s -> %-8s %-8s %-8s %-8s\n",
335 "leaf", "subleaf", "eax", "ebx", "ecx", "edx");
336 for ( l = 0; l < nr_leaves; ++l )
337 {
338 /* Skip empty leaves. */
339 if ( !leaves[l].a && !leaves[l].b && !leaves[l].c && !leaves[l].d )
340 continue;
341
342 printf(" %08x:%08x -> %08x:%08x:%08x:%08x\n",
343 leaves[l].leaf, leaves[l].subleaf,
344 leaves[l].a, leaves[l].b, leaves[l].c, leaves[l].d);
345 }
346
347 printf(" MSRs:\n");
348 printf(" %-8s -> %-16s\n", "index", "value");
349 for ( l = 0; l < nr_msrs; ++l )
350 printf(" %08x -> %016"PRIx64"\n",
351 msrs[l].idx, msrs[l].val);
352 }
353
main(int argc,char ** argv)354 int main(int argc, char **argv)
355 {
356 enum { MODE_UNKNOWN, MODE_INFO, MODE_DETAIL, MODE_INTERPRET, MODE_POLICY }
357 mode = MODE_UNKNOWN;
358 int domid = -1;
359
360 nr_features = xc_get_cpu_featureset_size();
361
362 for ( ;; )
363 {
364 const char *tmp_optarg;
365 int option_index = 0, c;
366 static const struct option long_options[] =
367 {
368 { "help", no_argument, NULL, 'h' },
369 { "info", no_argument, NULL, 'i' },
370 { "detail", no_argument, NULL, 'd' },
371 { "verbose", no_argument, NULL, 'v' },
372 { "policy", optional_argument, NULL, 'p' },
373 { NULL, 0, NULL, 0 },
374 };
375
376 c = getopt_long(argc, argv, "hidvp::", long_options, &option_index);
377
378 if ( c == -1 )
379 break;
380
381 switch ( c )
382 {
383 default:
384 printf("Bad option '%c'\n", c);
385 /* Fallthough */
386 case 'h':
387 printf("Usage: %s [ info | detail | <featureset>* ]\n", argv[0]);
388 return 0;
389
390 case 'i':
391 mode = MODE_INFO;
392 break;
393
394 case 'p':
395 mode = MODE_POLICY;
396
397 tmp_optarg = optarg;
398
399 /* Make "--policy $DOMID" and "-p $DOMID" work. */
400 if ( !optarg && optind < argc &&
401 argv[optind] != NULL && argv[optind][0] != '\0' &&
402 argv[optind][0] != '-' )
403 tmp_optarg = argv[optind++];
404
405 if ( tmp_optarg )
406 {
407 char *endptr;
408
409 errno = 0;
410 domid = strtol(tmp_optarg, &endptr, 0);
411 if ( errno || endptr == tmp_optarg )
412 err(1, "strtol(%s,,)", tmp_optarg);
413 }
414 break;
415
416 case 'd':
417 case 'v':
418 mode = MODE_DETAIL;
419 break;
420 }
421 }
422
423 if ( mode == MODE_UNKNOWN )
424 {
425 if ( optind == argc )
426 mode = MODE_INFO;
427 else if ( optind < argc )
428 {
429 if ( !strcmp(argv[optind], "info") )
430 {
431 mode = MODE_INFO;
432 optind++;
433 }
434 else if ( !strcmp(argv[optind], "detail") )
435 {
436 mode = MODE_DETAIL;
437 optind++;
438 }
439 else
440 mode = MODE_INTERPRET;
441 }
442 else
443 mode = MODE_INTERPRET;
444 }
445
446 if ( mode == MODE_POLICY )
447 {
448 static const char *const sys_policies[] = {
449 [ XEN_SYSCTL_cpu_policy_raw ] = "Raw",
450 [ XEN_SYSCTL_cpu_policy_host ] = "Host",
451 [ XEN_SYSCTL_cpu_policy_pv_max ] = "PV Max",
452 [ XEN_SYSCTL_cpu_policy_hvm_max ] = "HVM Max",
453 [ XEN_SYSCTL_cpu_policy_pv_default ] = "PV Default",
454 [ XEN_SYSCTL_cpu_policy_hvm_default ] = "HVM Default",
455 };
456 xen_cpuid_leaf_t *leaves;
457 xen_msr_entry_t *msrs;
458 uint32_t i, max_leaves, max_msrs;
459
460 xc_interface *xch = xc_interface_open(0, 0, 0);
461
462 if ( !xch )
463 err(1, "xc_interface_open");
464
465 if ( xc_get_cpu_policy_size(xch, &max_leaves, &max_msrs) )
466 err(1, "xc_get_cpu_policy_size(...)");
467 if ( domid == -1 )
468 printf("Xen reports there are maximum %u leaves and %u MSRs\n",
469 max_leaves, max_msrs);
470
471 leaves = calloc(max_leaves, sizeof(xen_cpuid_leaf_t));
472 if ( !leaves )
473 err(1, "calloc(max_leaves)");
474 msrs = calloc(max_msrs, sizeof(xen_msr_entry_t));
475 if ( !msrs )
476 err(1, "calloc(max_msrs)");
477
478 if ( domid != -1 )
479 {
480 char name[20];
481 uint32_t nr_leaves = max_leaves;
482 uint32_t nr_msrs = max_msrs;
483
484 if ( xc_get_domain_cpu_policy(xch, domid, &nr_leaves, leaves,
485 &nr_msrs, msrs) )
486 err(1, "xc_get_domain_cpu_policy(, %d, %d,, %d,)",
487 domid, nr_leaves, nr_msrs);
488
489 snprintf(name, sizeof(name), "Domain %d", domid);
490 print_policy(name, leaves, nr_leaves, msrs, nr_msrs);
491 }
492 else
493 {
494 /* Get system policies */
495 for ( i = 0; i < ARRAY_SIZE(sys_policies); ++i )
496 {
497 uint32_t nr_leaves = max_leaves;
498 uint32_t nr_msrs = max_msrs;
499
500 if ( xc_get_system_cpu_policy(xch, i, &nr_leaves, leaves,
501 &nr_msrs, msrs) )
502 {
503 if ( errno == EOPNOTSUPP )
504 {
505 printf("%s policy not supported by Xen\n",
506 sys_policies[i]);
507 continue;
508 }
509
510 err(1, "xc_get_system_cpu_policy(, %s,,)", sys_policies[i]);
511 }
512
513 print_policy(sys_policies[i], leaves, nr_leaves,
514 msrs, nr_msrs);
515 }
516 }
517
518 free(leaves);
519 free(msrs);
520 xc_interface_close(xch);
521 }
522 else if ( mode == MODE_INFO || mode == MODE_DETAIL )
523 {
524 xc_interface *xch = xc_interface_open(0, 0, 0);
525
526 if ( !xch )
527 err(1, "xc_interface_open");
528
529 if ( xc_get_cpu_featureset(xch, 0, &nr_features, NULL) )
530 err(1, "xc_get_featureset(, NULL)");
531
532 dump_info(xch, mode == MODE_DETAIL);
533
534 xc_interface_close(xch);
535 }
536 else
537 {
538 uint32_t fs[nr_features + 1];
539
540 while ( optind < argc )
541 {
542 char *ptr = argv[optind++];
543 unsigned int i = 0;
544 int offset;
545
546 memset(fs, 0, sizeof(fs));
547
548 while ( sscanf(ptr, "%x%n", &fs[i], &offset) == 1 )
549 {
550 i++;
551 ptr += offset;
552
553 if ( i == nr_features )
554 break;
555
556 if ( *ptr == ':' )
557 {
558 ptr++; continue;
559 }
560 break;
561 }
562
563 if ( !i )
564 {
565 fprintf(stderr, "'%s' unrecognized - skipping\n", ptr);
566 continue;
567 }
568
569 if ( *ptr )
570 fprintf(stderr, "'%s' unrecognized - ignoring\n", ptr);
571
572 decode_featureset(fs, i, "Raw", true);
573 }
574 }
575
576 return 0;
577 }
578
579 /*
580 * Local variables:
581 * mode: C
582 * c-file-style: "BSD"
583 * c-basic-offset: 4
584 * tab-width: 4
585 * indent-tabs-mode: nil
586 * End:
587 */
588