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 #include <xenguest.h>
12 
13 #include <xen-tools/common-macros.h>
14 #include <xen/lib/x86/cpuid-autogen.h>
15 
16 static uint32_t nr_features;
17 
18 static const struct {
19     const char *name;
20     const char *abbr;
21 } leaf_info[] = {
22     { "CPUID 0x00000001.edx",        "1d" },
23     { "CPUID 0x00000001.ecx",        "1c" },
24     { "CPUID 0x80000001.edx",       "e1d" },
25     { "CPUID 0x80000001.ecx",       "e1c" },
26     { "CPUID 0x0000000d:1.eax",     "Da1" },
27     { "CPUID 0x00000007:0.ebx",     "7b0" },
28     { "CPUID 0x00000007:0.ecx",     "7c0" },
29     { "CPUID 0x80000007.edx",       "e7d" },
30     { "CPUID 0x80000008.ebx",       "e8b" },
31     { "CPUID 0x00000007:0.edx",     "7d0" },
32     { "CPUID 0x00000007:1.eax",     "7a1" },
33     { "CPUID 0x80000021.eax",      "e21a" },
34     { "CPUID 0x00000007:1.ebx",     "7b1" },
35     { "CPUID 0x00000007:2.edx",     "7d2" },
36     { "CPUID 0x00000007:1.ecx",     "7c1" },
37     { "CPUID 0x00000007:1.edx",     "7d1" },
38     { "MSR_ARCH_CAPS.lo",         "m10Al" },
39     { "MSR_ARCH_CAPS.hi",         "m10Ah" },
40 };
41 
42 #define COL_ALIGN "24"
43 
44 static const char *const feature_names[] = INIT_FEATURE_VAL_TO_NAME;
45 
46 static const char *const fs_names[] = {
47     [XEN_SYSCTL_cpu_featureset_raw]     = "Raw",
48     [XEN_SYSCTL_cpu_featureset_host]    = "Host",
49     [XEN_SYSCTL_cpu_featureset_pv]      = "PV Default",
50     [XEN_SYSCTL_cpu_featureset_hvm]     = "HVM Default",
51     [XEN_SYSCTL_cpu_featureset_pv_max]  = "PV Max",
52     [XEN_SYSCTL_cpu_featureset_hvm_max] = "HVM Max",
53 };
54 
dump_leaf(uint32_t leaf,const char * const * strs)55 static void dump_leaf(uint32_t leaf, const char *const *strs)
56 {
57     unsigned i;
58 
59     for ( i = 0; i < 32; ++i )
60         if ( leaf & (1u << i) )
61         {
62             if ( strs[i] )
63                 printf(" %s", strs[i]);
64             else
65                 printf(" <%u>", i);
66         }
67 }
68 
decode_featureset(const uint32_t * features,const uint32_t length,const char * name,bool detail)69 static void decode_featureset(const uint32_t *features,
70                               const uint32_t length,
71                               const char *name,
72                               bool detail)
73 {
74     unsigned int i;
75 
76     /* If this trips, you probably need to extend leaf_info[] above. */
77     BUILD_BUG_ON(ARRAY_SIZE(leaf_info) != FEATURESET_NR_ENTRIES);
78     BUILD_BUG_ON(ARRAY_SIZE(feature_names) != FEATURESET_NR_ENTRIES * 32);
79 
80     printf("%-"COL_ALIGN"s        ", name);
81     for ( i = 0; i < length; ++i )
82         printf("%08x%c", features[i],
83                i < length - 1 ? ':' : '\n');
84 
85     if ( !detail )
86         return;
87 
88     for ( i = 0; i < length && i < ARRAY_SIZE(leaf_info); ++i )
89     {
90         printf("  [%02u] %-"COL_ALIGN"s", i, leaf_info[i].name ?: "<UNKNOWN>");
91         dump_leaf(features[i], &feature_names[i * 32]);
92         printf("\n");
93     }
94 }
95 
dump_info(xc_interface * xch,bool detail)96 static void dump_info(xc_interface *xch, bool detail)
97 {
98     unsigned int i;
99     uint32_t *fs;
100 
101     printf("nr_features: %u\n", nr_features);
102 
103     if ( !detail )
104     {
105         printf("       %"COL_ALIGN"s ", "KEY");
106         for ( i = 0; i < ARRAY_SIZE(leaf_info); ++i )
107             printf("%-8s ", leaf_info[i].abbr ?: "???");
108         printf("\n");
109     }
110 
111     printf("\nStatic sets:\n");
112     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_KNOWN),
113                       nr_features, "Known", detail);
114     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_SPECIAL),
115                       nr_features, "Special", detail);
116     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_PV_MAX),
117                       nr_features, "PV Max", detail);
118     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_PV_DEF),
119                       nr_features, "PV Default", detail);
120     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_SHADOW_MAX),
121                       nr_features, "HVM Shadow Max", detail);
122     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_SHADOW_DEF),
123                       nr_features, "HVM Shadow Default", detail);
124     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_HAP_MAX),
125                       nr_features, "HVM Hap Max", detail);
126     decode_featureset(xc_get_static_cpu_featuremask(XC_FEATUREMASK_HVM_HAP_DEF),
127                       nr_features, "HVM Hap Default", detail);
128 
129     printf("\nDynamic sets:\n");
130 
131     fs = malloc(sizeof(*fs) * nr_features);
132     if ( !fs )
133         err(1, "malloc(featureset)");
134 
135     for ( i = 0; i < ARRAY_SIZE(fs_names); ++i )
136     {
137         uint32_t len = nr_features;
138         int ret;
139 
140         memset(fs, 0, sizeof(*fs) * nr_features);
141 
142         ret = xc_get_cpu_featureset(xch, i, &len, fs);
143         if ( ret )
144         {
145             if ( errno == EOPNOTSUPP )
146             {
147                 printf("%s featureset not supported by Xen\n", fs_names[i]);
148                 continue;
149             }
150 
151             err(1, "xc_get_featureset()");
152         }
153 
154         decode_featureset(fs, len, fs_names[i], detail);
155     }
156 
157     free(fs);
158 }
159 
print_policy(const char * name,xen_cpuid_leaf_t * leaves,uint32_t nr_leaves,xen_msr_entry_t * msrs,uint32_t nr_msrs)160 static void print_policy(const char *name,
161                          xen_cpuid_leaf_t *leaves, uint32_t nr_leaves,
162                          xen_msr_entry_t *msrs, uint32_t nr_msrs)
163 {
164     unsigned int l;
165 
166     printf("%s policy: %u leaves, %u MSRs\n", name, nr_leaves, nr_msrs);
167     printf(" CPUID:\n");
168     printf("  %-8s %-8s -> %-8s %-8s %-8s %-8s\n",
169            "leaf", "subleaf", "eax", "ebx", "ecx", "edx");
170     for ( l = 0; l < nr_leaves; ++l )
171     {
172         /* Skip empty leaves. */
173         if ( !leaves[l].a && !leaves[l].b && !leaves[l].c && !leaves[l].d )
174             continue;
175 
176         printf("  %08x:%08x -> %08x:%08x:%08x:%08x\n",
177                leaves[l].leaf, leaves[l].subleaf,
178                leaves[l].a, leaves[l].b, leaves[l].c, leaves[l].d);
179     }
180 
181     printf(" MSRs:\n");
182     printf("  %-8s -> %-16s\n", "index", "value");
183     for ( l = 0; l < nr_msrs; ++l )
184         printf("  %08x -> %016"PRIx64"\n",
185                msrs[l].idx, msrs[l].val);
186 }
187 
main(int argc,char ** argv)188 int main(int argc, char **argv)
189 {
190     enum { MODE_UNKNOWN, MODE_INFO, MODE_DETAIL, MODE_INTERPRET, MODE_POLICY }
191     mode = MODE_UNKNOWN;
192     int domid = -1;
193 
194     nr_features = xc_get_cpu_featureset_size();
195 
196     for ( ;; )
197     {
198         const char *tmp_optarg;
199         int option_index = 0, c;
200         static const struct option long_options[] =
201         {
202             { "help", no_argument, NULL, 'h' },
203             { "info", no_argument, NULL, 'i' },
204             { "detail", no_argument, NULL, 'd' },
205             { "verbose", no_argument, NULL, 'v' },
206             { "policy", optional_argument, NULL, 'p' },
207             { NULL, 0, NULL, 0 },
208         };
209 
210         c = getopt_long(argc, argv, "hidvp::", long_options, &option_index);
211 
212         if ( c == -1 )
213             break;
214 
215         switch ( c )
216         {
217         default:
218             printf("Bad option '%c'\n", c);
219             /* Fallthough */
220         case 'h':
221             printf("Usage: %s [ info | detail | <featureset>* ]\n", argv[0]);
222             return 0;
223 
224         case 'i':
225             mode = MODE_INFO;
226             break;
227 
228         case 'p':
229             mode = MODE_POLICY;
230 
231             tmp_optarg = optarg;
232 
233             /* Make "--policy $DOMID" and "-p $DOMID" work. */
234             if ( !optarg && optind < argc &&
235                  argv[optind] != NULL && argv[optind][0] != '\0' &&
236                  argv[optind][0] != '-' )
237                 tmp_optarg = argv[optind++];
238 
239             if ( tmp_optarg )
240             {
241                 char *endptr;
242 
243                 errno = 0;
244                 domid = strtol(tmp_optarg, &endptr, 0);
245                 if ( errno || endptr == tmp_optarg )
246                     err(1, "strtol(%s,,)", tmp_optarg);
247             }
248             break;
249 
250         case 'd':
251         case 'v':
252             mode = MODE_DETAIL;
253             break;
254         }
255     }
256 
257     if ( mode == MODE_UNKNOWN )
258     {
259         if ( optind == argc )
260             mode = MODE_INFO;
261         else if ( optind < argc )
262         {
263             if ( !strcmp(argv[optind], "info") )
264             {
265                 mode = MODE_INFO;
266                 optind++;
267             }
268             else if ( !strcmp(argv[optind], "detail") )
269             {
270                 mode = MODE_DETAIL;
271                 optind++;
272             }
273             else
274                 mode = MODE_INTERPRET;
275         }
276         else
277             mode = MODE_INTERPRET;
278     }
279 
280     if ( mode == MODE_POLICY )
281     {
282         static const char *const sys_policies[] = {
283             [ XEN_SYSCTL_cpu_policy_raw ]          = "Raw",
284             [ XEN_SYSCTL_cpu_policy_host ]         = "Host",
285             [ XEN_SYSCTL_cpu_policy_pv_max ]       = "PV Max",
286             [ XEN_SYSCTL_cpu_policy_hvm_max ]      = "HVM Max",
287             [ XEN_SYSCTL_cpu_policy_pv_default ]   = "PV Default",
288             [ XEN_SYSCTL_cpu_policy_hvm_default ]  = "HVM Default",
289         };
290         xen_cpuid_leaf_t *leaves;
291         xen_msr_entry_t *msrs;
292         uint32_t i, max_leaves, max_msrs;
293 
294         xc_interface *xch = xc_interface_open(0, 0, 0);
295         xc_cpu_policy_t *policy = xc_cpu_policy_init();
296 
297         if ( !xch )
298             err(1, "xc_interface_open");
299         if ( !policy )
300             err(1, "xc_cpu_policy_init");
301 
302         if ( xc_cpu_policy_get_size(xch, &max_leaves, &max_msrs) )
303             err(1, "xc_get_cpu_policy_size(...)");
304         if ( domid == -1 )
305             printf("Xen reports there are maximum %u leaves and %u MSRs\n",
306                    max_leaves, max_msrs);
307 
308         leaves = calloc(max_leaves, sizeof(xen_cpuid_leaf_t));
309         if ( !leaves )
310             err(1, "calloc(max_leaves)");
311         msrs = calloc(max_msrs, sizeof(xen_msr_entry_t));
312         if ( !msrs )
313             err(1, "calloc(max_msrs)");
314 
315         if ( domid != -1 )
316         {
317             char name[20];
318             uint32_t nr_leaves = max_leaves;
319             uint32_t nr_msrs = max_msrs;
320 
321             if ( xc_cpu_policy_get_domain(xch, domid, policy) )
322                 err(1, "xc_cpu_policy_get_domain(, %d, )", domid);
323             if ( xc_cpu_policy_serialise(xch, policy, leaves, &nr_leaves,
324                                          msrs, &nr_msrs) )
325                 err(1, "xc_cpu_policy_serialise");
326 
327             snprintf(name, sizeof(name), "Domain %d", domid);
328             print_policy(name, leaves, nr_leaves, msrs, nr_msrs);
329         }
330         else
331         {
332             /* Get system policies */
333             for ( i = 0; i < ARRAY_SIZE(sys_policies); ++i )
334             {
335                 uint32_t nr_leaves = max_leaves;
336                 uint32_t nr_msrs = max_msrs;
337 
338                 if ( xc_cpu_policy_get_system(xch, i, policy) )
339                 {
340                     if ( errno == EOPNOTSUPP )
341                     {
342                         printf("%s policy not supported by Xen\n",
343                                sys_policies[i]);
344                         continue;
345                     }
346 
347                     err(1, "xc_cpu_policy_get_system(, %s, )", sys_policies[i]);
348                 }
349                 if ( xc_cpu_policy_serialise(xch, policy, leaves, &nr_leaves,
350                                              msrs, &nr_msrs) )
351                     err(1, "xc_cpu_policy_serialise");
352 
353                 print_policy(sys_policies[i], leaves, nr_leaves,
354                              msrs, nr_msrs);
355             }
356         }
357 
358         xc_cpu_policy_destroy(policy);
359         free(leaves);
360         free(msrs);
361         xc_interface_close(xch);
362     }
363     else if ( mode == MODE_INFO || mode == MODE_DETAIL )
364     {
365         xc_interface *xch = xc_interface_open(0, 0, 0);
366 
367         if ( !xch )
368             err(1, "xc_interface_open");
369 
370         if ( xc_get_cpu_featureset(xch, 0, &nr_features, NULL) )
371             err(1, "xc_get_featureset(, NULL)");
372 
373         dump_info(xch, mode == MODE_DETAIL);
374 
375         xc_interface_close(xch);
376     }
377     else
378     {
379         uint32_t fs[nr_features + 1];
380 
381         while ( optind < argc )
382         {
383             char *ptr = argv[optind++];
384             unsigned int i = 0;
385             int offset;
386 
387             memset(fs, 0, sizeof(fs));
388 
389             while ( sscanf(ptr, "%x%n", &fs[i], &offset) == 1 )
390             {
391                 i++;
392                 ptr += offset;
393 
394                 if ( i == nr_features )
395                     break;
396 
397                 if ( *ptr == ':' || *ptr == '-' )
398                 {
399                     ptr++;
400                     continue;
401                 }
402                 break;
403             }
404 
405             if ( !i )
406             {
407                 fprintf(stderr, "'%s' unrecognized - skipping\n", ptr);
408                 continue;
409             }
410 
411             if ( *ptr )
412                 fprintf(stderr, "'%s' unrecognized - ignoring\n", ptr);
413 
414             decode_featureset(fs, i, "Raw", true);
415         }
416     }
417 
418     return 0;
419 }
420 
421 /*
422  * Local variables:
423  * mode: C
424  * c-file-style: "BSD"
425  * c-basic-offset: 4
426  * tab-width: 4
427  * indent-tabs-mode: nil
428  * End:
429  */
430