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