1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as published
4 * by the Free Software Foundation; version 2.1 only. with the special
5 * exception on linking described in file LICENSE.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Lesser General Public License for more details.
11 */
12
13 #include "libxl_osdeps.h" /* must come before any other headers */
14
15 #include "libxl_internal.h"
16
17 #include <xen/lib/x86/cpu-policy.h>
18
libxl__cpuid_policy_is_empty(libxl_cpuid_policy_list * pl)19 int libxl__cpuid_policy_is_empty(libxl_cpuid_policy_list *pl)
20 {
21 return !*pl || (!libxl_cpuid_policy_list_length(pl) && !(*pl)->msr);
22 }
23
libxl_cpuid_dispose(libxl_cpuid_policy_list * pl)24 void libxl_cpuid_dispose(libxl_cpuid_policy_list *pl)
25 {
26 libxl_cpuid_policy_list policy = *pl;
27
28 if (policy == NULL)
29 return;
30
31 if (policy->cpuid) {
32 unsigned int i, j;
33 struct xc_xend_cpuid *cpuid_list = policy->cpuid;
34
35 for (i = 0; cpuid_list[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
36 for (j = 0; j < 4; j++) {
37 if (cpuid_list[i].policy[j] != NULL) {
38 free(cpuid_list[i].policy[j]);
39 }
40 }
41 }
42 free(policy->cpuid);
43 }
44
45 free(policy->msr);
46
47 free(policy);
48 *pl = NULL;
49 return;
50 }
51
52 #define CPUID_REG_INV 0
53 #define CPUID_REG_EAX 1
54 #define CPUID_REG_EBX 2
55 #define CPUID_REG_ECX 3
56 #define CPUID_REG_EDX 4
57
58 /* mapping CPUID features to names
59 * holds a "name" for each feature, specified by the "leaf" number (and an
60 * optional "subleaf" in ECX), the "reg"ister (EAX-EDX) used and a number of
61 * bits starting with "bit" and being "length" bits long.
62 * Used for the static structure describing all features.
63 */
64 struct cpuid_flags {
65 const char *name;
66 uint32_t leaf;
67 uint32_t subleaf;
68 int reg;
69 int bit;
70 int length;
71 };
72
73 /* go through the dynamic array finding the entry for a specified leaf.
74 * if no entry exists, allocate one and return that.
75 */
cpuid_find_match(libxl_cpuid_policy_list * pl,uint32_t leaf,uint32_t subleaf)76 static struct xc_xend_cpuid *cpuid_find_match(libxl_cpuid_policy_list *pl,
77 uint32_t leaf, uint32_t subleaf)
78 {
79 libxl_cpuid_policy_list policy = *pl;
80 struct xc_xend_cpuid **list;
81 int i = 0;
82
83 if (policy == NULL)
84 policy = *pl = calloc(1, sizeof(*policy));
85
86 list = &policy->cpuid;
87 if (*list != NULL) {
88 for (i = 0; (*list)[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
89 if ((*list)[i].input[0] == leaf && (*list)[i].input[1] == subleaf)
90 return *list + i;
91 }
92 }
93 *list = realloc(*list, sizeof((*list)[0]) * (i + 2));
94 (*list)[i].input[0] = leaf;
95 (*list)[i].input[1] = subleaf;
96 memset((*list)[i].policy, 0, 4 * sizeof(char*));
97 (*list)[i + 1].input[0] = XEN_CPUID_INPUT_UNUSED;
98 return *list + i;
99 }
100
cpuid_add(libxl_cpuid_policy_list * policy,const struct cpuid_flags * flag,const char * val)101 static int cpuid_add(libxl_cpuid_policy_list *policy,
102 const struct cpuid_flags *flag, const char *val)
103 {
104 struct xc_xend_cpuid *entry = cpuid_find_match(policy, flag->leaf,
105 flag->subleaf);
106 unsigned long num;
107 char flags[33], *resstr, *endptr;
108 unsigned int i;
109
110 resstr = entry->policy[flag->reg - 1];
111 num = strtoul(val, &endptr, 0);
112 flags[flag->length] = 0;
113 if (endptr != val) {
114 /* if this was a valid number, write the binary form into the string */
115 for (i = 0; i < flag->length; i++) {
116 flags[flag->length - 1 - i] = "01"[(num >> i) & 1];
117 }
118 } else {
119 switch(val[0]) {
120 case 'x': case 'k': case 's':
121 memset(flags, val[0], flag->length);
122 break;
123 default:
124 return 3;
125 }
126 }
127
128 if (resstr == NULL) {
129 resstr = strdup("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
130 }
131
132 /* the family and model entry is potentially split up across
133 * two fields in Fn0000_0001_EAX, so handle them here separately.
134 */
135 if (!strcmp(flag->name, "family")) {
136 if (num < 16) {
137 memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
138 memcpy(resstr + (32 - 8) - 20, "00000000", 8);
139 } else {
140 num -= 15;
141 memcpy(resstr + (32 - 4) - flag->bit, "1111", 4);
142 for (i = 0; i < 7; i++) {
143 flags[7 - i] = "01"[num & 1];
144 num >>= 1;
145 }
146 memcpy(resstr + (32 - 8) - 20, flags, 8);
147 }
148 } else if (!strcmp(flag->name, "model")) {
149 memcpy(resstr + (32 - 4) - 16, flags, 4);
150 memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
151 } else {
152 memcpy(resstr + (32 - flag->length) - flag->bit, flags,
153 flag->length);
154 }
155 entry->policy[flag->reg - 1] = resstr;
156
157 return 0;
158 }
159
msr_find_match(libxl_cpuid_policy_list * pl,uint32_t idx)160 static struct xc_msr *msr_find_match(libxl_cpuid_policy_list *pl, uint32_t idx)
161 {
162 unsigned int i = 0;
163 libxl_cpuid_policy_list policy = *pl;
164
165 if (policy == NULL)
166 policy = *pl = calloc(1, sizeof(*policy));
167
168 if (policy->msr != NULL) {
169 for (i = 0; policy->msr[i].index != XC_MSR_INPUT_UNUSED; i++) {
170 if (policy->msr[i].index == idx) {
171 return &policy->msr[i];
172 }
173 }
174 }
175
176 policy->msr = realloc(policy->msr, sizeof(struct xc_msr) * (i + 2));
177 policy->msr[i].index = idx;
178 memset(policy->msr[i].policy, 'x', ARRAY_SIZE(policy->msr[0].policy) - 1);
179 policy->msr[i].policy[ARRAY_SIZE(policy->msr[0].policy) - 1] = '\0';
180 policy->msr[i + 1].index = XC_MSR_INPUT_UNUSED;
181
182 return &policy->msr[i];
183 }
184
msr_add(libxl_cpuid_policy_list * policy,uint32_t idx,unsigned int bit,const char * val)185 static int msr_add(libxl_cpuid_policy_list *policy, uint32_t idx,
186 unsigned int bit, const char *val)
187 {
188 struct xc_msr *entry = msr_find_match(policy, idx);
189
190 /* Only allow options taking a character for MSRs, no values allowed. */
191 if (strlen(val) != 1)
192 return 3;
193
194 switch (val[0]) {
195 case '0':
196 case '1':
197 case 'x':
198 case 'k':
199 entry->policy[63 - bit] = val[0];
200 break;
201
202 case 's':
203 /* Translate s -> k as xc_msr doesn't support the deprecated 's'. */
204 entry->policy[63 - bit] = 'k';
205 break;
206
207 default:
208 return 3;
209 }
210
211 return 0;
212 }
213
214 struct feature_name {
215 const char *name;
216 unsigned int bit;
217 };
218
search_feature(const void * a,const void * b)219 static int search_feature(const void *a, const void *b)
220 {
221 const char *key = a;
222 const char *feat = ((const struct feature_name *)b)->name;
223
224 return strcmp(key, feat);
225 }
226
227 /* parse a single key=value pair and translate it into the libxc
228 * used interface using 32-characters strings for each register.
229 * Will overwrite earlier entries and thus can be called multiple
230 * times.
231 */
libxl_cpuid_parse_config(libxl_cpuid_policy_list * policy,const char * str)232 int libxl_cpuid_parse_config(libxl_cpuid_policy_list *policy, const char* str)
233 {
234 #define NA XEN_CPUID_INPUT_UNUSED
235 static const struct cpuid_flags cpuid_flags[] = {
236 {"maxleaf", 0x00000000, NA, CPUID_REG_EAX, 0, 32},
237 /* the following two entries are subject to tweaking later in the code */
238 {"stepping", 0x00000001, NA, CPUID_REG_EAX, 0, 4},
239 {"model", 0x00000001, NA, CPUID_REG_EAX, 4, 8},
240 {"family", 0x00000001, NA, CPUID_REG_EAX, 8, 8},
241
242 {"brandid", 0x00000001, NA, CPUID_REG_EBX, 0, 8},
243 {"clflush", 0x00000001, NA, CPUID_REG_EBX, 8, 8},
244 {"proccount", 0x00000001, NA, CPUID_REG_EBX, 16, 8},
245 {"localapicid", 0x00000001, NA, CPUID_REG_EBX, 24, 8},
246
247 {"est", 0x00000001, NA, CPUID_REG_ECX, 7, 1},
248 {"cntxid", 0x00000001, NA, CPUID_REG_ECX, 10, 1},
249 {"cmpxchg16", 0x00000001, NA, CPUID_REG_ECX, 13, 1},
250 /* Linux uses sse4_{1,2}. Keep sse4.{1,2} for compatibility */
251 {"sse4_1", 0x00000001, NA, CPUID_REG_ECX, 19, 1},
252 {"sse4.1", 0x00000001, NA, CPUID_REG_ECX, 19, 1},
253 {"sse4_2", 0x00000001, NA, CPUID_REG_ECX, 20, 1},
254 {"sse4.2", 0x00000001, NA, CPUID_REG_ECX, 20, 1},
255 {"aes", 0x00000001, NA, CPUID_REG_ECX, 25, 1},
256
257 {"cmpxchg8", 0x00000001, NA, CPUID_REG_EDX, 8, 1},
258 {"sysenter", 0x00000001, NA, CPUID_REG_EDX, 11, 1},
259 {"psn", 0x00000001, NA, CPUID_REG_EDX, 18, 1},
260 {"clfsh", 0x00000001, NA, CPUID_REG_EDX, 19, 1},
261 {"tm", 0x00000001, NA, CPUID_REG_EDX, 29, 1},
262 {"ia64", 0x00000001, NA, CPUID_REG_EDX, 30, 1},
263
264 {"arat", 0x00000006, NA, CPUID_REG_EAX, 2, 1},
265
266 {"tsc_adjust", 0x00000007, 0, CPUID_REG_EBX, 1, 1},
267 {"cmt", 0x00000007, 0, CPUID_REG_EBX, 12, 1},
268
269 {"lahfsahf", 0x80000001, NA, CPUID_REG_ECX, 0, 1},
270 {"cmplegacy", 0x80000001, NA, CPUID_REG_ECX, 1, 1},
271 {"altmovcr8", 0x80000001, NA, CPUID_REG_ECX, 4, 1},
272 {"nodeid", 0x80000001, NA, CPUID_REG_ECX, 19, 1},
273 {"perfctr_core", 0x80000001, NA, CPUID_REG_ECX, 23, 1},
274 {"perfctr_nb", 0x80000001, NA, CPUID_REG_ECX, 24, 1},
275
276 {"procpkg", 0x00000004, 0, CPUID_REG_EAX, 26, 6},
277
278 {"invtsc", 0x80000007, NA, CPUID_REG_EDX, 8, 1},
279
280 {"ppin", 0x80000008, NA, CPUID_REG_EBX, 23, 1},
281
282 {"nc", 0x80000008, NA, CPUID_REG_ECX, 0, 8},
283 {"apicidsize", 0x80000008, NA, CPUID_REG_ECX, 12, 4},
284
285 {"svm_npt", 0x8000000a, NA, CPUID_REG_EDX, 0, 1},
286 {"svm_lbrv", 0x8000000a, NA, CPUID_REG_EDX, 1, 1},
287 {"svm_nrips", 0x8000000a, NA, CPUID_REG_EDX, 3, 1},
288 {"svm_tscrate", 0x8000000a, NA, CPUID_REG_EDX, 4, 1},
289 {"svm_vmcbclean",0x8000000a, NA, CPUID_REG_EDX, 5, 1},
290 {"svm_decode", 0x8000000a, NA, CPUID_REG_EDX, 7, 1},
291 {"svm_pausefilt",0x8000000a, NA, CPUID_REG_EDX, 10, 1},
292
293 {"lfence+", 0x80000021, NA, CPUID_REG_EAX, 2, 1},
294
295 {"maxhvleaf", 0x40000000, NA, CPUID_REG_EAX, 0, 8},
296
297 {NULL, 0, NA, CPUID_REG_INV, 0, 0}
298 };
299 static const struct feature_name features[] = INIT_FEATURE_NAME_TO_VAL;
300 /*
301 * NB: if we switch to using a cpu_policy derived object instead of a
302 * libxl_cpuid_policy_list we could get rid of the featureset -> cpuid leaf
303 * conversion table and use a featureset directly as we have conversions
304 * to/from featureset and cpu_policy.
305 */
306 static const struct {
307 enum { FEAT_CPUID, FEAT_MSR } type;
308 union {
309 struct {
310 uint32_t leaf, subleaf;
311 unsigned int reg;
312 } cpuid;
313 struct {
314 uint32_t index;
315 unsigned int reg;
316 } msr;
317 } u;
318 } feature_to_policy[] = {
319 #define CPUID_ENTRY(l, s, r) \
320 { .type = FEAT_CPUID, \
321 .u = { .cpuid.leaf = l, .cpuid.subleaf = s, .cpuid.reg = r } \
322 }
323 #define MSR_ENTRY(i, r) \
324 { .type = FEAT_MSR, \
325 .u = { .msr.index = i, .msr.reg = r } \
326 }
327 CPUID_ENTRY(0x00000001, NA, CPUID_REG_EDX),
328 CPUID_ENTRY(0x00000001, NA, CPUID_REG_ECX),
329 CPUID_ENTRY(0x80000001, NA, CPUID_REG_EDX),
330 CPUID_ENTRY(0x80000001, NA, CPUID_REG_ECX),
331 CPUID_ENTRY(0x0000000D, 1, CPUID_REG_EAX),
332 CPUID_ENTRY(0x00000007, 0, CPUID_REG_EBX),
333 CPUID_ENTRY(0x00000007, 0, CPUID_REG_ECX),
334 CPUID_ENTRY(0x80000007, NA, CPUID_REG_EDX),
335 CPUID_ENTRY(0x80000008, NA, CPUID_REG_EBX),
336 CPUID_ENTRY(0x00000007, 0, CPUID_REG_EDX),
337 CPUID_ENTRY(0x00000007, 1, CPUID_REG_EAX),
338 CPUID_ENTRY(0x80000021, NA, CPUID_REG_EAX),
339 CPUID_ENTRY(0x00000007, 1, CPUID_REG_EBX),
340 CPUID_ENTRY(0x00000007, 2, CPUID_REG_EDX),
341 CPUID_ENTRY(0x00000007, 1, CPUID_REG_ECX),
342 CPUID_ENTRY(0x00000007, 1, CPUID_REG_EDX),
343 MSR_ENTRY(0x10a, CPUID_REG_EAX),
344 MSR_ENTRY(0x10a, CPUID_REG_EDX),
345 #undef MSR_ENTRY
346 #undef CPUID_ENTRY
347 };
348 #undef NA
349 const char *sep, *val;
350 char *name;
351 const struct cpuid_flags *flag;
352 const struct feature_name *feat;
353
354 BUILD_BUG_ON(ARRAY_SIZE(feature_to_policy) != FEATURESET_NR_ENTRIES);
355
356 sep = strchr(str, '=');
357 if (sep == NULL) {
358 return 1;
359 } else {
360 val = sep + 1;
361 }
362 for (flag = cpuid_flags; flag->name != NULL; flag++) {
363 if(!strncmp(str, flag->name, sep - str) && flag->name[sep - str] == 0)
364 return cpuid_add(policy, flag, val);
365 }
366
367 /* Provide a NUL terminated feature name to the search helper. */
368 name = strndup(str, sep - str);
369 if (name == NULL)
370 return ERROR_NOMEM;
371
372 feat = bsearch(name, features, ARRAY_SIZE(features), sizeof(features[0]),
373 search_feature);
374 free(name);
375
376 if (feat == NULL)
377 return 2;
378
379 switch (feature_to_policy[feat->bit / 32].type) {
380 case FEAT_CPUID:
381 {
382 struct cpuid_flags f;
383
384 f.name = feat->name;
385 f.leaf = feature_to_policy[feat->bit / 32].u.cpuid.leaf;
386 f.subleaf = feature_to_policy[feat->bit / 32].u.cpuid.subleaf;
387 f.reg = feature_to_policy[feat->bit / 32].u.cpuid.reg;
388 f.bit = feat->bit % 32;
389 f.length = 1;
390
391 return cpuid_add(policy, &f, val);
392 }
393
394 case FEAT_MSR:
395 {
396 unsigned int bit = feat->bit % 32;
397
398 if (feature_to_policy[feat->bit / 32].u.msr.reg == CPUID_REG_EDX)
399 bit += 32;
400
401 return msr_add(policy, feature_to_policy[feat->bit / 32].u.msr.index,
402 bit, val);
403 }
404 }
405
406 return 2;
407 }
408
409 /* parse a single list item from the legacy Python xend syntax, where
410 * the strings for each register were directly exposed to the user.
411 * Used for maintaining compatibility with older config files
412 */
libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list * policy,const char * str)413 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *policy,
414 const char* str)
415 {
416 char *endptr;
417 unsigned long value;
418 uint32_t leaf, subleaf = XEN_CPUID_INPUT_UNUSED;
419 struct xc_xend_cpuid *entry;
420
421 /* parse the leaf number */
422 value = strtoul(str, &endptr, 0);
423 if (str == endptr) {
424 return 1;
425 }
426 leaf = value;
427 /* check for an optional subleaf number */
428 if (*endptr == ',') {
429 str = endptr + 1;
430 value = strtoul(str, &endptr, 0);
431 if (str == endptr) {
432 return 2;
433 }
434 subleaf = value;
435 }
436 if (*endptr != ':') {
437 return 3;
438 }
439 str = endptr + 1;
440 entry = cpuid_find_match(policy, leaf, subleaf);
441 for (str = endptr + 1; *str != 0;) {
442 if (str[0] != 'e' || str[2] != 'x') {
443 return 4;
444 }
445 value = str[1] - 'a';
446 endptr = strchr(str, '=');
447 if (value > 3 || endptr == NULL) {
448 return 4;
449 }
450 str = endptr + 1;
451 endptr = strchr(str, ',');
452 if (endptr == NULL) {
453 endptr = strchr(str, 0);
454 }
455 if (endptr - str != 32) {
456 return 5;
457 }
458 entry->policy[value] = calloc(32 + 1, 1);
459 strncpy(entry->policy[value], str, 32);
460 entry->policy[value][32] = 0;
461 if (*endptr == 0) {
462 break;
463 }
464 for (str = endptr + 1; *str == ' ' || *str == '\n'; str++);
465 }
466 return 0;
467 }
468
libxl__cpuid_legacy(libxl_ctx * ctx,uint32_t domid,bool restore,libxl_domain_build_info * info)469 int libxl__cpuid_legacy(libxl_ctx *ctx, uint32_t domid, bool restore,
470 libxl_domain_build_info *info)
471 {
472 GC_INIT(ctx);
473 bool pae = true;
474 bool itsc;
475 int r;
476
477 /*
478 * Gross hack. Using libxl_defbool_val() here causes libvirt to crash in
479 * __vfscanf_internal(), which is probably collateral damage from a side
480 * effect of the assert().
481 *
482 * Unblock things for now by opencoding without the assert.
483 */
484 bool nested_virt = info->nested_hvm.val > 0;
485
486 /*
487 * For PV guests, PAE is Xen-controlled (it is the 'p' that differentiates
488 * the xen-3.0-x86_32 and xen-3.0-x86_32p ABIs). It is mandatory as Xen
489 * is 64bit only these days.
490 *
491 * For PVH guests, there is no top-level PAE control in the domain config,
492 * so is treated as always available.
493 *
494 * HVM guests get a top-level choice of whether PAE is available.
495 */
496 if (info->type == LIBXL_DOMAIN_TYPE_HVM)
497 pae = libxl_defbool_val(info->u.hvm.pae);
498
499 /*
500 * Advertising Invariant TSC to a guest means that the TSC frequency won't
501 * change at any point in the future.
502 *
503 * We do not have enough information about potential migration
504 * destinations to know whether advertising ITSC is safe, but if the guest
505 * isn't going to migrate, then the current hardware is all that matters.
506 *
507 * Alternatively, an internal property of vTSC is that the values read are
508 * invariant. Advertise ITSC when we know the domain will have emulated
509 * TSC everywhere it goes.
510 */
511 itsc = (libxl_defbool_val(info->disable_migrate) ||
512 info->tsc_mode == LIBXL_TSC_MODE_ALWAYS_EMULATE);
513
514 r = xc_cpuid_apply_policy(ctx->xch, domid, restore, NULL, 0,
515 pae, itsc, nested_virt,
516 info->cpuid ? info->cpuid->cpuid : NULL,
517 info->cpuid ? info->cpuid->msr : NULL);
518 if (r)
519 LOGEVD(ERROR, -r, domid, "Failed to apply CPUID policy");
520
521 GC_FREE;
522 return r ? ERROR_FAIL : 0;
523 }
524
525 static const char *input_names[2] = { "leaf", "subleaf" };
526 static const char *policy_names[4] = { "eax", "ebx", "ecx", "edx" };
527 /*
528 * Aiming for:
529 * { 'cpuid': [
530 * { 'leaf': 'val-eax',
531 * 'subleaf': 'val-ecx',
532 * 'eax': 'filter',
533 * 'ebx': 'filter',
534 * 'ecx': 'filter',
535 * 'edx': 'filter' },
536 * { 'leaf': 'val-eax', ..., 'eax': 'filter', ... },
537 * ... etc ...
538 * ],
539 * 'msr': [
540 * { 'index': 'val-index',
541 * 'policy': 'filter', },
542 * ... etc ...
543 * ],
544 * }
545 */
546
libxl_cpuid_policy_list_gen_json(yajl_gen hand,libxl_cpuid_policy_list * pl)547 yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand,
548 libxl_cpuid_policy_list *pl)
549 {
550 libxl_cpuid_policy_list policy = *pl;
551 struct xc_xend_cpuid *cpuid;
552 const struct xc_msr *msr;
553 yajl_gen_status s;
554 int i, j;
555
556 s = yajl_gen_map_open(hand);
557 if (s != yajl_gen_status_ok) goto out;
558
559 s = libxl__yajl_gen_asciiz(hand, "cpuid");
560 if (s != yajl_gen_status_ok) goto out;
561
562 s = yajl_gen_array_open(hand);
563 if (s != yajl_gen_status_ok) goto out;
564
565 if (policy == NULL || policy->cpuid == NULL) goto empty;
566 cpuid = policy->cpuid;
567
568 for (i = 0; cpuid[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
569 s = yajl_gen_map_open(hand);
570 if (s != yajl_gen_status_ok) goto out;
571
572 for (j = 0; j < 2; j++) {
573 if (cpuid[i].input[j] != XEN_CPUID_INPUT_UNUSED) {
574 s = libxl__yajl_gen_asciiz(hand, input_names[j]);
575 if (s != yajl_gen_status_ok) goto out;
576 s = yajl_gen_integer(hand, cpuid[i].input[j]);
577 if (s != yajl_gen_status_ok) goto out;
578 }
579 }
580
581 for (j = 0; j < 4; j++) {
582 if (cpuid[i].policy[j] != NULL) {
583 s = libxl__yajl_gen_asciiz(hand, policy_names[j]);
584 if (s != yajl_gen_status_ok) goto out;
585 s = yajl_gen_string(hand,
586 (const unsigned char *)cpuid[i].policy[j], 32);
587 if (s != yajl_gen_status_ok) goto out;
588 }
589 }
590 s = yajl_gen_map_close(hand);
591 if (s != yajl_gen_status_ok) goto out;
592 }
593
594 empty:
595 s = yajl_gen_array_close(hand);
596 if (s != yajl_gen_status_ok) goto out;
597
598 s = libxl__yajl_gen_asciiz(hand, "msr");
599 if (s != yajl_gen_status_ok) goto out;
600
601 s = yajl_gen_array_open(hand);
602 if (s != yajl_gen_status_ok) goto out;
603
604 if (!policy || !policy->msr) goto done;
605 msr = policy->msr;
606
607 for (i = 0; msr[i].index != XC_MSR_INPUT_UNUSED; i++) {
608 s = yajl_gen_map_open(hand);
609 if (s != yajl_gen_status_ok) goto out;
610
611 s = libxl__yajl_gen_asciiz(hand, "index");
612 if (s != yajl_gen_status_ok) goto out;
613 s = yajl_gen_integer(hand, msr[i].index);
614 if (s != yajl_gen_status_ok) goto out;
615 s = libxl__yajl_gen_asciiz(hand, "policy");
616 if (s != yajl_gen_status_ok) goto out;
617 s = yajl_gen_string(hand,
618 (const unsigned char *)msr[i].policy, 64);
619 if (s != yajl_gen_status_ok) goto out;
620
621 s = yajl_gen_map_close(hand);
622 if (s != yajl_gen_status_ok) goto out;
623 }
624
625 done:
626 s = yajl_gen_array_close(hand);
627 if (s != yajl_gen_status_ok) goto out;
628 s = yajl_gen_map_close(hand);
629 out:
630 return s;
631 }
632
libxl__cpuid_policy_list_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_cpuid_policy_list * p)633 int libxl__cpuid_policy_list_parse_json(libxl__gc *gc,
634 const libxl__json_object *o,
635 libxl_cpuid_policy_list *p)
636 {
637 int i, size;
638 struct xc_xend_cpuid *l;
639 struct xc_msr *msr;
640 const libxl__json_object *co;
641 flexarray_t *array;
642 bool cpuid_only = false;
643
644 /*
645 * Old JSON field was an array with just the CPUID data. With the addition
646 * of MSRs the object is now a map with two array fields.
647 *
648 * Use the object format to detect whether the passed data contains just
649 * CPUID leafs and thus is an array, or does also contain MSRs and is a
650 * map.
651 */
652 if (libxl__json_object_is_array(o)) {
653 co = o;
654 cpuid_only = true;
655 goto parse_cpuid;
656 }
657
658 if (!libxl__json_object_is_map(o))
659 return ERROR_FAIL;
660
661 co = libxl__json_map_get("cpuid", o, JSON_ARRAY);
662 if (!libxl__json_object_is_array(co))
663 return ERROR_FAIL;
664
665 parse_cpuid:
666 *p = libxl__calloc(NOGC, 1, sizeof(**p));
667
668 array = libxl__json_object_get_array(co);
669 if (!array->count)
670 goto cpuid_empty;
671
672 size = array->count;
673 /* need one extra slot as sentinel */
674 l = (*p)->cpuid = libxl__calloc(NOGC, size + 1,
675 sizeof(struct xc_xend_cpuid));
676
677 l[size].input[0] = XEN_CPUID_INPUT_UNUSED;
678 l[size].input[1] = XEN_CPUID_INPUT_UNUSED;
679
680 for (i = 0; i < size; i++) {
681 const libxl__json_object *t;
682 int j;
683
684 if (flexarray_get(array, i, (void**)&t) != 0)
685 return ERROR_FAIL;
686
687 if (!libxl__json_object_is_map(t))
688 return ERROR_FAIL;
689
690 for (j = 0; j < ARRAY_SIZE(l[0].input); j++) {
691 const libxl__json_object *r;
692
693 r = libxl__json_map_get(input_names[j], t, JSON_INTEGER);
694 if (!r)
695 l[i].input[j] = XEN_CPUID_INPUT_UNUSED;
696 else
697 l[i].input[j] = libxl__json_object_get_integer(r);
698 }
699
700 for (j = 0; j < ARRAY_SIZE(l[0].policy); j++) {
701 const libxl__json_object *r;
702
703 r = libxl__json_map_get(policy_names[j], t, JSON_STRING);
704 if (!r)
705 l[i].policy[j] = NULL;
706 else
707 l[i].policy[j] =
708 libxl__strdup(NOGC, libxl__json_object_get_string(r));
709 }
710 }
711
712 cpuid_empty:
713 if (cpuid_only)
714 return 0;
715
716 co = libxl__json_map_get("msr", o, JSON_ARRAY);
717 if (!libxl__json_object_is_array(co))
718 return ERROR_FAIL;
719
720 array = libxl__json_object_get_array(co);
721 if (!array->count)
722 return 0;
723 size = array->count;
724 /* need one extra slot as sentinel */
725 msr = (*p)->msr = libxl__calloc(NOGC, size + 1, sizeof(struct xc_msr));
726
727 msr[size].index = XC_MSR_INPUT_UNUSED;
728
729 for (i = 0; i < size; i++) {
730 const libxl__json_object *t, *r;
731
732 if (flexarray_get(array, i, (void**)&t) != 0)
733 return ERROR_FAIL;
734
735 if (!libxl__json_object_is_map(t))
736 return ERROR_FAIL;
737
738 r = libxl__json_map_get("index", t, JSON_INTEGER);
739 if (!r) return ERROR_FAIL;
740 msr[i].index = libxl__json_object_get_integer(r);
741 r = libxl__json_map_get("policy", t, JSON_STRING);
742 if (!r) return ERROR_FAIL;
743 if (strlen(libxl__json_object_get_string(r)) !=
744 ARRAY_SIZE(msr[i].policy) - 1)
745 return ERROR_FAIL;
746 strcpy(msr[i].policy, libxl__json_object_get_string(r));
747 }
748
749 return 0;
750 }
751
libxl_cpuid_policy_list_length(const libxl_cpuid_policy_list * pl)752 int libxl_cpuid_policy_list_length(const libxl_cpuid_policy_list *pl)
753 {
754 int i = 0;
755 const struct xc_xend_cpuid *l;
756
757 if (*pl == NULL)
758 return 0;
759
760 l = (*pl)->cpuid;
761 if (l) {
762 while (l[i].input[0] != XEN_CPUID_INPUT_UNUSED)
763 i++;
764 }
765
766 return i;
767 }
768
libxl_cpuid_policy_list_copy(libxl_ctx * ctx,libxl_cpuid_policy_list * pdst,const libxl_cpuid_policy_list * psrc)769 void libxl_cpuid_policy_list_copy(libxl_ctx *ctx,
770 libxl_cpuid_policy_list *pdst,
771 const libxl_cpuid_policy_list *psrc)
772 {
773 struct xc_xend_cpuid **dst;
774 struct xc_xend_cpuid *const *src;
775 GC_INIT(ctx);
776 int i, j, len;
777
778 if (*psrc == NULL) {
779 *pdst = NULL;
780 goto out;
781 }
782
783 *pdst = libxl__calloc(NOGC, 1, sizeof(**pdst));
784
785 if (!(*psrc)->cpuid)
786 goto copy_msr;
787
788 dst = &(*pdst)->cpuid;
789 src = &(*psrc)->cpuid;
790 len = libxl_cpuid_policy_list_length(psrc);
791 /* one extra slot for sentinel */
792 *dst = libxl__calloc(NOGC, len + 1, sizeof(struct xc_xend_cpuid));
793 (*dst)[len].input[0] = XEN_CPUID_INPUT_UNUSED;
794 (*dst)[len].input[1] = XEN_CPUID_INPUT_UNUSED;
795
796 for (i = 0; i < len; i++) {
797 for (j = 0; j < 2; j++)
798 (*dst)[i].input[j] = (*src)[i].input[j];
799 for (j = 0; j < 4; j++)
800 if ((*src)[i].policy[j])
801 (*dst)[i].policy[j] =
802 libxl__strdup(NOGC, (*src)[i].policy[j]);
803 else
804 (*dst)[i].policy[j] = NULL;
805 }
806
807 copy_msr:
808 if ((*psrc)->msr) {
809 const struct xc_msr *msr = (*psrc)->msr;
810
811 for (i = 0; msr[i].index != XC_MSR_INPUT_UNUSED; i++)
812 ;
813 len = i;
814 (*pdst)->msr = libxl__calloc(NOGC, len + 1, sizeof(struct xc_msr));
815 (*pdst)->msr[len].index = XC_MSR_INPUT_UNUSED;
816
817 for (i = 0; i < len; i++) {
818 (*pdst)->msr[i].index = msr[i].index;
819 strcpy((*pdst)->msr[i].policy, msr[i].policy);
820 }
821 }
822
823 out:
824 GC_FREE;
825 }
826
827 /*
828 * Local variables:
829 * mode: C
830 * c-basic-offset: 4
831 * indent-tabs-mode: nil
832 * End:
833 */
834