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 
libxl__cpuid_policy_is_empty(libxl_cpuid_policy_list * pl)17 int libxl__cpuid_policy_is_empty(libxl_cpuid_policy_list *pl)
18 {
19     return !libxl_cpuid_policy_list_length(pl);
20 }
21 
libxl_cpuid_dispose(libxl_cpuid_policy_list * p_cpuid_list)22 void libxl_cpuid_dispose(libxl_cpuid_policy_list *p_cpuid_list)
23 {
24     int i, j;
25     libxl_cpuid_policy_list cpuid_list = *p_cpuid_list;
26 
27     if (cpuid_list == NULL)
28         return;
29     for (i = 0; cpuid_list[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
30         for (j = 0; j < 4; j++)
31             if (cpuid_list[i].policy[j] != NULL) {
32                 free(cpuid_list[i].policy[j]);
33                 cpuid_list[i].policy[j] = NULL;
34             }
35     }
36     free(cpuid_list);
37     *p_cpuid_list = NULL;
38     return;
39 }
40 
41 #define CPUID_REG_INV 0
42 #define CPUID_REG_EAX 1
43 #define CPUID_REG_EBX 2
44 #define CPUID_REG_ECX 3
45 #define CPUID_REG_EDX 4
46 
47 /* mapping CPUID features to names
48  * holds a "name" for each feature, specified by the "leaf" number (and an
49  * optional "subleaf" in ECX), the "reg"ister (EAX-EDX) used and a number of
50  * bits starting with "bit" and being "length" bits long.
51  * Used for the static structure describing all features.
52  */
53 struct cpuid_flags {
54     char* name;
55     uint32_t leaf;
56     uint32_t subleaf;
57     int reg;
58     int bit;
59     int length;
60 };
61 
62 /* go through the dynamic array finding the entry for a specified leaf.
63  * if no entry exists, allocate one and return that.
64  */
cpuid_find_match(libxl_cpuid_policy_list * list,uint32_t leaf,uint32_t subleaf)65 static libxl_cpuid_policy_list cpuid_find_match(libxl_cpuid_policy_list *list,
66                                           uint32_t leaf, uint32_t subleaf)
67 {
68     int i = 0;
69 
70     if (*list != NULL) {
71         for (i = 0; (*list)[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
72             if ((*list)[i].input[0] == leaf && (*list)[i].input[1] == subleaf)
73                 return *list + i;
74         }
75     }
76     *list = realloc(*list, sizeof((*list)[0]) * (i + 2));
77     (*list)[i].input[0] = leaf;
78     (*list)[i].input[1] = subleaf;
79     memset((*list)[i].policy, 0, 4 * sizeof(char*));
80     (*list)[i + 1].input[0] = XEN_CPUID_INPUT_UNUSED;
81     return *list + i;
82 }
83 
84 /* parse a single key=value pair and translate it into the libxc
85  * used interface using 32-characters strings for each register.
86  * Will overwrite earlier entries and thus can be called multiple
87  * times.
88  */
libxl_cpuid_parse_config(libxl_cpuid_policy_list * cpuid,const char * str)89 int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
90 {
91 #define NA XEN_CPUID_INPUT_UNUSED
92     static const struct cpuid_flags cpuid_flags[] = {
93         {"maxleaf",      0x00000000, NA, CPUID_REG_EAX,  0, 32},
94       /* the following two entries are subject to tweaking later in the code */
95         {"stepping",     0x00000001, NA, CPUID_REG_EAX,  0,  4},
96         {"model",        0x00000001, NA, CPUID_REG_EAX,  4,  8},
97         {"family",       0x00000001, NA, CPUID_REG_EAX,  8,  8},
98 
99         {"brandid",      0x00000001, NA, CPUID_REG_EBX,  0,  8},
100         {"clflush",      0x00000001, NA, CPUID_REG_EBX,  8,  8},
101         {"proccount",    0x00000001, NA, CPUID_REG_EBX, 16,  8},
102         {"localapicid",  0x00000001, NA, CPUID_REG_EBX, 24,  8},
103 
104         {"sse3",         0x00000001, NA, CPUID_REG_ECX,  0,  1},
105         {"pclmulqdq",    0x00000001, NA, CPUID_REG_ECX,  1,  1},
106         {"dtes64",       0x00000001, NA, CPUID_REG_ECX,  2,  1},
107         {"monitor",      0x00000001, NA, CPUID_REG_ECX,  3,  1},
108         {"dscpl",        0x00000001, NA, CPUID_REG_ECX,  4,  1},
109         {"vmx",          0x00000001, NA, CPUID_REG_ECX,  5,  1},
110         {"smx",          0x00000001, NA, CPUID_REG_ECX,  6,  1},
111         {"est",          0x00000001, NA, CPUID_REG_ECX,  7,  1},
112         {"tm2",          0x00000001, NA, CPUID_REG_ECX,  8,  1},
113         {"ssse3",        0x00000001, NA, CPUID_REG_ECX,  9,  1},
114         {"cntxid",       0x00000001, NA, CPUID_REG_ECX, 10,  1},
115         {"fma",          0x00000001, NA, CPUID_REG_ECX, 12,  1},
116         {"cmpxchg16",    0x00000001, NA, CPUID_REG_ECX, 13,  1},
117         {"xtpr",         0x00000001, NA, CPUID_REG_ECX, 14,  1},
118         {"pdcm",         0x00000001, NA, CPUID_REG_ECX, 15,  1},
119         {"pcid",         0x00000001, NA, CPUID_REG_ECX, 17,  1},
120         {"dca",          0x00000001, NA, CPUID_REG_ECX, 18,  1},
121         /* Linux uses sse4_{1,2}.  Keep sse4.{1,2} for compatibility */
122         {"sse4_1",       0x00000001, NA, CPUID_REG_ECX, 19,  1},
123         {"sse4.1",       0x00000001, NA, CPUID_REG_ECX, 19,  1},
124         {"sse4_2",       0x00000001, NA, CPUID_REG_ECX, 20,  1},
125         {"sse4.2",       0x00000001, NA, CPUID_REG_ECX, 20,  1},
126         {"x2apic",       0x00000001, NA, CPUID_REG_ECX, 21,  1},
127         {"movbe",        0x00000001, NA, CPUID_REG_ECX, 22,  1},
128         {"popcnt",       0x00000001, NA, CPUID_REG_ECX, 23,  1},
129         {"tsc-deadline", 0x00000001, NA, CPUID_REG_ECX, 24,  1},
130         {"aes",          0x00000001, NA, CPUID_REG_ECX, 25,  1},
131         {"xsave",        0x00000001, NA, CPUID_REG_ECX, 26,  1},
132         {"osxsave",      0x00000001, NA, CPUID_REG_ECX, 27,  1},
133         {"avx",          0x00000001, NA, CPUID_REG_ECX, 28,  1},
134         {"f16c",         0x00000001, NA, CPUID_REG_ECX, 29,  1},
135         {"rdrand",       0x00000001, NA, CPUID_REG_ECX, 30,  1},
136         {"hypervisor",   0x00000001, NA, CPUID_REG_ECX, 31,  1},
137 
138         {"fpu",          0x00000001, NA, CPUID_REG_EDX,  0,  1},
139         {"vme",          0x00000001, NA, CPUID_REG_EDX,  1,  1},
140         {"de",           0x00000001, NA, CPUID_REG_EDX,  2,  1},
141         {"pse",          0x00000001, NA, CPUID_REG_EDX,  3,  1},
142         {"tsc",          0x00000001, NA, CPUID_REG_EDX,  4,  1},
143         {"msr",          0x00000001, NA, CPUID_REG_EDX,  5,  1},
144         {"pae",          0x00000001, NA, CPUID_REG_EDX,  6,  1},
145         {"mce",          0x00000001, NA, CPUID_REG_EDX,  7,  1},
146         {"cmpxchg8",     0x00000001, NA, CPUID_REG_EDX,  8,  1},
147         {"apic",         0x00000001, NA, CPUID_REG_EDX,  9,  1},
148         {"sysenter",     0x00000001, NA, CPUID_REG_EDX, 11,  1},
149         {"mtrr",         0x00000001, NA, CPUID_REG_EDX, 12,  1},
150         {"pge",          0x00000001, NA, CPUID_REG_EDX, 13,  1},
151         {"mca",          0x00000001, NA, CPUID_REG_EDX, 14,  1},
152         {"cmov",         0x00000001, NA, CPUID_REG_EDX, 15,  1},
153         {"pat",          0x00000001, NA, CPUID_REG_EDX, 16,  1},
154         {"pse36",        0x00000001, NA, CPUID_REG_EDX, 17,  1},
155         {"psn",          0x00000001, NA, CPUID_REG_EDX, 18,  1},
156         {"clfsh",        0x00000001, NA, CPUID_REG_EDX, 19,  1},
157         {"ds",           0x00000001, NA, CPUID_REG_EDX, 21,  1},
158         {"acpi",         0x00000001, NA, CPUID_REG_EDX, 22,  1},
159         {"mmx",          0x00000001, NA, CPUID_REG_EDX, 23,  1},
160         {"fxsr",         0x00000001, NA, CPUID_REG_EDX, 24,  1},
161         {"sse",          0x00000001, NA, CPUID_REG_EDX, 25,  1},
162         {"sse2",         0x00000001, NA, CPUID_REG_EDX, 26,  1},
163         {"ss",           0x00000001, NA, CPUID_REG_EDX, 27,  1},
164         {"htt",          0x00000001, NA, CPUID_REG_EDX, 28,  1},
165         {"tm",           0x00000001, NA, CPUID_REG_EDX, 29,  1},
166         {"ia64",         0x00000001, NA, CPUID_REG_EDX, 30,  1},
167         {"pbe",          0x00000001, NA, CPUID_REG_EDX, 31,  1},
168 
169         {"arat",         0x00000006, NA, CPUID_REG_EAX,  2,  1},
170 
171         {"fsgsbase",     0x00000007,  0, CPUID_REG_EBX,  0,  1},
172         {"tsc_adjust",   0x00000007,  0, CPUID_REG_EBX,  1,  1},
173         {"bmi1",         0x00000007,  0, CPUID_REG_EBX,  3,  1},
174         {"hle",          0x00000007,  0, CPUID_REG_EBX,  4,  1},
175         {"avx2",         0x00000007,  0, CPUID_REG_EBX,  5,  1},
176         {"smep",         0x00000007,  0, CPUID_REG_EBX,  7,  1},
177         {"bmi2",         0x00000007,  0, CPUID_REG_EBX,  8,  1},
178         {"erms",         0x00000007,  0, CPUID_REG_EBX,  9,  1},
179         {"invpcid",      0x00000007,  0, CPUID_REG_EBX, 10,  1},
180         {"rtm",          0x00000007,  0, CPUID_REG_EBX, 11,  1},
181         {"cmt",          0x00000007,  0, CPUID_REG_EBX, 12,  1},
182         {"mpx",          0x00000007,  0, CPUID_REG_EBX, 14,  1},
183         {"avx512f",      0x00000007,  0, CPUID_REG_EBX, 16,  1},
184         {"avx512dq",     0x00000007,  0, CPUID_REG_EBX, 17,  1},
185         {"rdseed",       0x00000007,  0, CPUID_REG_EBX, 18,  1},
186         {"adx",          0x00000007,  0, CPUID_REG_EBX, 19,  1},
187         {"smap",         0x00000007,  0, CPUID_REG_EBX, 20,  1},
188         {"avx512ifma",   0x00000007,  0, CPUID_REG_EBX, 21,  1},
189         {"clflushopt",   0x00000007,  0, CPUID_REG_EBX, 23,  1},
190         {"clwb",         0x00000007,  0, CPUID_REG_EBX, 24,  1},
191         {"avx512pf",     0x00000007,  0, CPUID_REG_EBX, 26,  1},
192         {"avx512er",     0x00000007,  0, CPUID_REG_EBX, 27,  1},
193         {"avx512cd",     0x00000007,  0, CPUID_REG_EBX, 28,  1},
194         {"sha",          0x00000007,  0, CPUID_REG_EBX, 29,  1},
195         {"avx512bw",     0x00000007,  0, CPUID_REG_EBX, 30,  1},
196         {"avx512vl",     0x00000007,  0, CPUID_REG_EBX, 31,  1},
197 
198         {"avx512vbmi",   0x00000007,  0, CPUID_REG_ECX,  1,  1},
199         {"umip",         0x00000007,  0, CPUID_REG_ECX,  2,  1},
200         {"pku",          0x00000007,  0, CPUID_REG_ECX,  3,  1},
201         {"ospke",        0x00000007,  0, CPUID_REG_ECX,  4,  1},
202 
203         {"avx512-4vnniw",0x00000007,  0, CPUID_REG_EDX,  2,  1},
204         {"avx512-4fmaps",0x00000007,  0, CPUID_REG_EDX,  3,  1},
205 
206         {"lahfsahf",     0x80000001, NA, CPUID_REG_ECX,  0,  1},
207         {"cmplegacy",    0x80000001, NA, CPUID_REG_ECX,  1,  1},
208         {"svm",          0x80000001, NA, CPUID_REG_ECX,  2,  1},
209         {"extapic",      0x80000001, NA, CPUID_REG_ECX,  3,  1},
210         {"altmovcr8",    0x80000001, NA, CPUID_REG_ECX,  4,  1},
211         {"abm",          0x80000001, NA, CPUID_REG_ECX,  5,  1},
212         {"sse4a",        0x80000001, NA, CPUID_REG_ECX,  6,  1},
213         {"misalignsse",  0x80000001, NA, CPUID_REG_ECX,  7,  1},
214         {"3dnowprefetch",0x80000001, NA, CPUID_REG_ECX,  8,  1},
215         {"osvw",         0x80000001, NA, CPUID_REG_ECX,  9,  1},
216         {"ibs",          0x80000001, NA, CPUID_REG_ECX, 10,  1},
217         {"xop",          0x80000001, NA, CPUID_REG_ECX, 11,  1},
218         {"skinit",       0x80000001, NA, CPUID_REG_ECX, 12,  1},
219         {"wdt",          0x80000001, NA, CPUID_REG_ECX, 13,  1},
220         {"lwp",          0x80000001, NA, CPUID_REG_ECX, 15,  1},
221         {"fma4",         0x80000001, NA, CPUID_REG_ECX, 16,  1},
222         {"nodeid",       0x80000001, NA, CPUID_REG_ECX, 19,  1},
223         {"tbm",          0x80000001, NA, CPUID_REG_ECX, 21,  1},
224         {"topoext",      0x80000001, NA, CPUID_REG_ECX, 22,  1},
225         {"perfctr_core", 0x80000001, NA, CPUID_REG_ECX, 23,  1},
226         {"perfctr_nb",   0x80000001, NA, CPUID_REG_ECX, 24,  1},
227 
228         {"syscall",      0x80000001, NA, CPUID_REG_EDX, 11,  1},
229         {"nx",           0x80000001, NA, CPUID_REG_EDX, 20,  1},
230         {"mmxext",       0x80000001, NA, CPUID_REG_EDX, 22,  1},
231         {"ffxsr",        0x80000001, NA, CPUID_REG_EDX, 25,  1},
232         {"page1gb",      0x80000001, NA, CPUID_REG_EDX, 26,  1},
233         {"rdtscp",       0x80000001, NA, CPUID_REG_EDX, 27,  1},
234         {"lm",           0x80000001, NA, CPUID_REG_EDX, 29,  1},
235         {"3dnowext",     0x80000001, NA, CPUID_REG_EDX, 30,  1},
236         {"3dnow",        0x80000001, NA, CPUID_REG_EDX, 31,  1},
237 
238         {"procpkg",      0x00000004,  0, CPUID_REG_EAX, 26,  6},
239 
240         {"invtsc",       0x80000007, NA, CPUID_REG_EDX,  8,  1},
241 
242         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
243         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
244 
245         {"svm_npt",      0x8000000a, NA, CPUID_REG_EDX,  0,  1},
246         {"svm_lbrv",     0x8000000a, NA, CPUID_REG_EDX,  1,  1},
247         {"svm_nrips",    0x8000000a, NA, CPUID_REG_EDX,  3,  1},
248         {"svm_tscrate",  0x8000000a, NA, CPUID_REG_EDX,  4,  1},
249         {"svm_vmcbclean",0x8000000a, NA, CPUID_REG_EDX,  5,  1},
250         {"svm_decode",   0x8000000a, NA, CPUID_REG_EDX,  7,  1},
251         {"svm_pausefilt",0x8000000a, NA, CPUID_REG_EDX, 10,  1},
252 
253         {"maxhvleaf",    0x40000000, NA, CPUID_REG_EAX,  0,  8},
254 
255         {NULL, 0, NA, CPUID_REG_INV, 0, 0}
256     };
257 #undef NA
258     char *sep, *val, *endptr;
259     int i;
260     const struct cpuid_flags *flag;
261     struct libxl__cpuid_policy *entry;
262     unsigned long num;
263     char flags[33], *resstr;
264 
265     sep = strchr(str, '=');
266     if (sep == NULL) {
267         return 1;
268     } else {
269         val = sep + 1;
270     }
271     for (flag = cpuid_flags; flag->name != NULL; flag++) {
272         if(!strncmp(str, flag->name, sep - str) && flag->name[sep - str] == 0)
273             break;
274     }
275     if (flag->name == NULL) {
276         return 2;
277     }
278     entry = cpuid_find_match(cpuid, flag->leaf, flag->subleaf);
279     resstr = entry->policy[flag->reg - 1];
280     num = strtoull(val, &endptr, 0);
281     flags[flag->length] = 0;
282     if (endptr != val) {
283         /* if this was a valid number, write the binary form into the string */
284         for (i = 0; i < flag->length; i++) {
285             flags[flag->length - 1 - i] = "01"[!!(num & (1 << i))];
286         }
287     } else {
288         switch(val[0]) {
289         case 'x': case 'k': case 's':
290             memset(flags, val[0], flag->length);
291             break;
292         default:
293             return 3;
294         }
295     }
296 
297     if (resstr == NULL) {
298         resstr = strdup("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
299     }
300 
301     /* the family and model entry is potentially split up across
302      * two fields in Fn0000_0001_EAX, so handle them here separately.
303      */
304     if (!strncmp(str, "family", sep - str)) {
305         if (num < 16) {
306             memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
307             memcpy(resstr + (32 - 8) - 20, "00000000", 8);
308         } else {
309             num -= 15;
310             memcpy(resstr + (32 - 4) - flag->bit, "1111", 4);
311             for (i = 0; i < 7; i++) {
312                 flags[7 - i] = "01"[num & 1];
313                 num >>= 1;
314             }
315             memcpy(resstr + (32 - 8) - 20, flags, 8);
316         }
317     } else if (!strncmp(str, "model", sep - str)) {
318         memcpy(resstr + (32 - 4) - 16, flags, 4);
319         memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
320     } else {
321         memcpy(resstr + (32 - flag->length) - flag->bit, flags,
322                flag->length);
323     }
324     entry->policy[flag->reg - 1] = resstr;
325 
326     return 0;
327 }
328 
329 /* parse a single list item from the legacy Python xend syntax, where
330  * the strings for each register were directly exposed to the user.
331  * Used for maintaining compatibility with older config files
332  */
libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list * cpuid,const char * str)333 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
334                                   const char* str)
335 {
336     char *endptr;
337     unsigned long value;
338     uint32_t leaf, subleaf = XEN_CPUID_INPUT_UNUSED;
339     struct libxl__cpuid_policy *entry;
340 
341     /* parse the leaf number */
342     value = strtoul(str, &endptr, 0);
343     if (str == endptr) {
344         return 1;
345     }
346     leaf = value;
347     /* check for an optional subleaf number */
348     if (*endptr == ',') {
349         str = endptr + 1;
350         value = strtoul(str, &endptr, 0);
351         if (str == endptr) {
352             return 2;
353         }
354         subleaf = value;
355     }
356     if (*endptr != ':') {
357         return 3;
358     }
359     str = endptr + 1;
360     entry = cpuid_find_match(cpuid, leaf, subleaf);
361     for (str = endptr + 1; *str != 0;) {
362         if (str[0] != 'e' || str[2] != 'x') {
363             return 4;
364         }
365         value = str[1] - 'a';
366         endptr = strchr(str, '=');
367         if (value > 3 || endptr == NULL) {
368             return 4;
369         }
370         str = endptr + 1;
371         endptr = strchr(str, ',');
372         if (endptr == NULL) {
373             endptr = strchr(str, 0);
374         }
375         if (endptr - str != 32) {
376             return 5;
377         }
378         entry->policy[value] = calloc(32 + 1, 1);
379         strncpy(entry->policy[value], str, 32);
380         entry->policy[value][32] = 0;
381         if (*endptr == 0) {
382             break;
383         }
384         for (str = endptr + 1; *str == ' ' || *str == '\n'; str++);
385     }
386     return 0;
387 }
388 
libxl_cpuid_apply_policy(libxl_ctx * ctx,uint32_t domid)389 void libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid)
390 {
391     xc_cpuid_apply_policy(ctx->xch, domid, NULL, 0);
392 }
393 
libxl_cpuid_set(libxl_ctx * ctx,uint32_t domid,libxl_cpuid_policy_list cpuid)394 void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid,
395                      libxl_cpuid_policy_list cpuid)
396 {
397     int i;
398     char *cpuid_res[4];
399 
400     for (i = 0; cpuid[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++)
401         xc_cpuid_set(ctx->xch, domid, cpuid[i].input,
402                      (const char**)(cpuid[i].policy), cpuid_res);
403 }
404 
405 static const char *input_names[2] = { "leaf", "subleaf" };
406 static const char *policy_names[4] = { "eax", "ebx", "ecx", "edx" };
407 /*
408  * Aiming for:
409  * [
410  *     { 'leaf':    'val-eax',
411  *       'subleaf': 'val-ecx',
412  *       'eax':     'filter',
413  *       'ebx':     'filter',
414  *       'ecx':     'filter',
415  *       'edx':     'filter' },
416  *     { 'leaf':    'val-eax', ..., 'eax': 'filter', ... },
417  *     ... etc ...
418  * ]
419  */
420 
libxl_cpuid_policy_list_gen_json(yajl_gen hand,libxl_cpuid_policy_list * pcpuid)421 yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand,
422                                 libxl_cpuid_policy_list *pcpuid)
423 {
424     libxl_cpuid_policy_list cpuid = *pcpuid;
425     yajl_gen_status s;
426     int i, j;
427 
428     s = yajl_gen_array_open(hand);
429     if (s != yajl_gen_status_ok) goto out;
430 
431     if (cpuid == NULL) goto empty;
432 
433     for (i = 0; cpuid[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
434         s = yajl_gen_map_open(hand);
435         if (s != yajl_gen_status_ok) goto out;
436 
437         for (j = 0; j < 2; j++) {
438             if (cpuid[i].input[j] != XEN_CPUID_INPUT_UNUSED) {
439                 s = libxl__yajl_gen_asciiz(hand, input_names[j]);
440                 if (s != yajl_gen_status_ok) goto out;
441                 s = yajl_gen_integer(hand, cpuid[i].input[j]);
442                 if (s != yajl_gen_status_ok) goto out;
443             }
444         }
445 
446         for (j = 0; j < 4; j++) {
447             if (cpuid[i].policy[j] != NULL) {
448                 s = libxl__yajl_gen_asciiz(hand, policy_names[j]);
449                 if (s != yajl_gen_status_ok) goto out;
450                 s = yajl_gen_string(hand,
451                                (const unsigned char *)cpuid[i].policy[j], 32);
452                 if (s != yajl_gen_status_ok) goto out;
453             }
454         }
455         s = yajl_gen_map_close(hand);
456         if (s != yajl_gen_status_ok) goto out;
457     }
458 
459 empty:
460     s = yajl_gen_array_close(hand);
461 out:
462     return s;
463 }
464 
libxl__cpuid_policy_list_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_cpuid_policy_list * p)465 int libxl__cpuid_policy_list_parse_json(libxl__gc *gc,
466                                         const libxl__json_object *o,
467                                         libxl_cpuid_policy_list *p)
468 {
469     int i, size;
470     libxl_cpuid_policy_list l;
471     flexarray_t *array;
472 
473     if (!libxl__json_object_is_array(o))
474         return ERROR_FAIL;
475 
476     array = libxl__json_object_get_array(o);
477     if (!array->count)
478         return 0;
479 
480     size = array->count;
481     /* need one extra slot as sentinel */
482     l = *p = libxl__calloc(NOGC, size + 1, sizeof(libxl_cpuid_policy));
483 
484     l[size].input[0] = XEN_CPUID_INPUT_UNUSED;
485     l[size].input[1] = XEN_CPUID_INPUT_UNUSED;
486 
487     for (i = 0; i < size; i++) {
488         const libxl__json_object *t;
489         int j;
490 
491         if (flexarray_get(array, i, (void**)&t) != 0)
492             return ERROR_FAIL;
493 
494         if (!libxl__json_object_is_map(t))
495             return ERROR_FAIL;
496 
497         for (j = 0; j < ARRAY_SIZE(l[0].input); j++) {
498             const libxl__json_object *r;
499 
500             r = libxl__json_map_get(input_names[j], t, JSON_INTEGER);
501             if (!r)
502                 l[i].input[j] = XEN_CPUID_INPUT_UNUSED;
503             else
504                 l[i].input[j] = libxl__json_object_get_integer(r);
505         }
506 
507         for (j = 0; j < ARRAY_SIZE(l[0].policy); j++) {
508             const libxl__json_object *r;
509 
510             r = libxl__json_map_get(policy_names[j], t, JSON_STRING);
511             if (!r)
512                 l[i].policy[j] = NULL;
513             else
514                 l[i].policy[j] =
515                     libxl__strdup(NOGC, libxl__json_object_get_string(r));
516         }
517     }
518 
519     return 0;
520 }
521 
libxl_cpuid_policy_list_length(const libxl_cpuid_policy_list * pl)522 int libxl_cpuid_policy_list_length(const libxl_cpuid_policy_list *pl)
523 {
524     int i = 0;
525     libxl_cpuid_policy_list l = *pl;
526 
527     if (l) {
528         while (l[i].input[0] != XEN_CPUID_INPUT_UNUSED)
529             i++;
530     }
531 
532     return i;
533 }
534 
libxl_cpuid_policy_list_copy(libxl_ctx * ctx,libxl_cpuid_policy_list * dst,const libxl_cpuid_policy_list * src)535 void libxl_cpuid_policy_list_copy(libxl_ctx *ctx,
536                                   libxl_cpuid_policy_list *dst,
537                                   const libxl_cpuid_policy_list *src)
538 {
539     GC_INIT(ctx);
540     int i, j, len;
541 
542     if (*src == NULL) {
543         *dst = NULL;
544         goto out;
545     }
546 
547     len = libxl_cpuid_policy_list_length(src);
548     /* one extra slot for sentinel */
549     *dst = libxl__calloc(NOGC, len + 1, sizeof(libxl_cpuid_policy));
550     (*dst)[len].input[0] = XEN_CPUID_INPUT_UNUSED;
551     (*dst)[len].input[1] = XEN_CPUID_INPUT_UNUSED;
552 
553     for (i = 0; i < len; i++) {
554         for (j = 0; j < 2; j++)
555             (*dst)[i].input[j] = (*src)[i].input[j];
556         for (j = 0; j < 4; j++)
557             if ((*src)[i].policy[j])
558                 (*dst)[i].policy[j] =
559                     libxl__strdup(NOGC, (*src)[i].policy[j]);
560             else
561                 (*dst)[i].policy[j] = NULL;
562     }
563 
564 out:
565     GC_FREE;
566 }
567 
568 /*
569  * Local variables:
570  * mode: C
571  * c-basic-offset: 4
572  * indent-tabs-mode: nil
573  * End:
574  */
575