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