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