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