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