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         {"avx512-ifma",  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         {"prefetchwt1",  0x00000007,  0, CPUID_REG_ECX,  0,  1},
199         {"avx512-vbmi",  0x00000007,  0, CPUID_REG_ECX,  1,  1},
200         {"umip",         0x00000007,  0, CPUID_REG_ECX,  2,  1},
201         {"pku",          0x00000007,  0, CPUID_REG_ECX,  3,  1},
202         {"ospke",        0x00000007,  0, CPUID_REG_ECX,  4,  1},
203         {"avx512-vbmi2", 0x00000007,  0, CPUID_REG_ECX,  6,  1},
204         {"cet-ss",       0x00000007,  0, CPUID_REG_ECX,  7,  1},
205         {"gfni",         0x00000007,  0, CPUID_REG_ECX,  8,  1},
206         {"vaes",         0x00000007,  0, CPUID_REG_ECX,  9,  1},
207         {"vpclmulqdq",   0x00000007,  0, CPUID_REG_ECX, 10,  1},
208         {"avx512-vnni",  0x00000007,  0, CPUID_REG_ECX, 11,  1},
209         {"avx512-bitalg",0x00000007,  0, CPUID_REG_ECX, 12,  1},
210         {"avx512-vpopcntdq",0x00000007,0,CPUID_REG_ECX, 14,  1},
211         {"tsxldtrk",     0x00000007,  0, CPUID_REG_ECX, 16,  1},
212         {"rdpid",        0x00000007,  0, CPUID_REG_ECX, 22,  1},
213         {"cldemote",     0x00000007,  0, CPUID_REG_ECX, 25,  1},
214 
215         {"avx512-4vnniw",0x00000007,  0, CPUID_REG_EDX,  2,  1},
216         {"avx512-4fmaps",0x00000007,  0, CPUID_REG_EDX,  3,  1},
217         {"srbds-ctrl",   0x00000007,  0, CPUID_REG_EDX,  9,  1},
218         {"md-clear",     0x00000007,  0, CPUID_REG_EDX, 10,  1},
219         {"serialize",    0x00000007,  0, CPUID_REG_EDX, 14,  1},
220         {"cet-ibt",      0x00000007,  0, CPUID_REG_EDX, 20,  1},
221         {"ibrsb",        0x00000007,  0, CPUID_REG_EDX, 26,  1},
222         {"stibp",        0x00000007,  0, CPUID_REG_EDX, 27,  1},
223         {"l1d-flush",    0x00000007,  0, CPUID_REG_EDX, 28,  1},
224         {"arch-caps",    0x00000007,  0, CPUID_REG_EDX, 29,  1},
225         {"core-caps",    0x00000007,  0, CPUID_REG_EDX, 30,  1},
226         {"ssbd",         0x00000007,  0, CPUID_REG_EDX, 31,  1},
227 
228         {"avx512-bf16",  0x00000007,  1, CPUID_REG_EAX,  5,  1},
229 
230         {"lahfsahf",     0x80000001, NA, CPUID_REG_ECX,  0,  1},
231         {"cmplegacy",    0x80000001, NA, CPUID_REG_ECX,  1,  1},
232         {"svm",          0x80000001, NA, CPUID_REG_ECX,  2,  1},
233         {"extapic",      0x80000001, NA, CPUID_REG_ECX,  3,  1},
234         {"altmovcr8",    0x80000001, NA, CPUID_REG_ECX,  4,  1},
235         {"abm",          0x80000001, NA, CPUID_REG_ECX,  5,  1},
236         {"sse4a",        0x80000001, NA, CPUID_REG_ECX,  6,  1},
237         {"misalignsse",  0x80000001, NA, CPUID_REG_ECX,  7,  1},
238         {"3dnowprefetch",0x80000001, NA, CPUID_REG_ECX,  8,  1},
239         {"osvw",         0x80000001, NA, CPUID_REG_ECX,  9,  1},
240         {"ibs",          0x80000001, NA, CPUID_REG_ECX, 10,  1},
241         {"xop",          0x80000001, NA, CPUID_REG_ECX, 11,  1},
242         {"skinit",       0x80000001, NA, CPUID_REG_ECX, 12,  1},
243         {"wdt",          0x80000001, NA, CPUID_REG_ECX, 13,  1},
244         {"lwp",          0x80000001, NA, CPUID_REG_ECX, 15,  1},
245         {"fma4",         0x80000001, NA, CPUID_REG_ECX, 16,  1},
246         {"nodeid",       0x80000001, NA, CPUID_REG_ECX, 19,  1},
247         {"tbm",          0x80000001, NA, CPUID_REG_ECX, 21,  1},
248         {"topoext",      0x80000001, NA, CPUID_REG_ECX, 22,  1},
249         {"perfctr_core", 0x80000001, NA, CPUID_REG_ECX, 23,  1},
250         {"perfctr_nb",   0x80000001, NA, CPUID_REG_ECX, 24,  1},
251 
252         {"syscall",      0x80000001, NA, CPUID_REG_EDX, 11,  1},
253         {"nx",           0x80000001, NA, CPUID_REG_EDX, 20,  1},
254         {"mmxext",       0x80000001, NA, CPUID_REG_EDX, 22,  1},
255         {"ffxsr",        0x80000001, NA, CPUID_REG_EDX, 25,  1},
256         {"page1gb",      0x80000001, NA, CPUID_REG_EDX, 26,  1},
257         {"rdtscp",       0x80000001, NA, CPUID_REG_EDX, 27,  1},
258         {"lm",           0x80000001, NA, CPUID_REG_EDX, 29,  1},
259         {"3dnowext",     0x80000001, NA, CPUID_REG_EDX, 30,  1},
260         {"3dnow",        0x80000001, NA, CPUID_REG_EDX, 31,  1},
261 
262         {"procpkg",      0x00000004,  0, CPUID_REG_EAX, 26,  6},
263 
264         {"invtsc",       0x80000007, NA, CPUID_REG_EDX,  8,  1},
265 
266         {"clzero",       0x80000008, NA, CPUID_REG_EBX,  0,  1},
267         {"rstr-fp-err-ptrs", 0x80000008, NA, CPUID_REG_EBX, 2, 1},
268         {"wbnoinvd",     0x80000008, NA, CPUID_REG_EBX,  9,  1},
269         {"ibpb",         0x80000008, NA, CPUID_REG_EBX, 12,  1},
270         {"ppin",         0x80000008, NA, CPUID_REG_EBX, 23,  1},
271 
272         {"nc",           0x80000008, NA, CPUID_REG_ECX,  0,  8},
273         {"apicidsize",   0x80000008, NA, CPUID_REG_ECX, 12,  4},
274 
275         {"svm_npt",      0x8000000a, NA, CPUID_REG_EDX,  0,  1},
276         {"svm_lbrv",     0x8000000a, NA, CPUID_REG_EDX,  1,  1},
277         {"svm_nrips",    0x8000000a, NA, CPUID_REG_EDX,  3,  1},
278         {"svm_tscrate",  0x8000000a, NA, CPUID_REG_EDX,  4,  1},
279         {"svm_vmcbclean",0x8000000a, NA, CPUID_REG_EDX,  5,  1},
280         {"svm_decode",   0x8000000a, NA, CPUID_REG_EDX,  7,  1},
281         {"svm_pausefilt",0x8000000a, NA, CPUID_REG_EDX, 10,  1},
282 
283         {"maxhvleaf",    0x40000000, NA, CPUID_REG_EAX,  0,  8},
284 
285         {NULL, 0, NA, CPUID_REG_INV, 0, 0}
286     };
287 #undef NA
288     char *sep, *val, *endptr;
289     int i;
290     const struct cpuid_flags *flag;
291     struct xc_xend_cpuid *entry;
292     unsigned long num;
293     char flags[33], *resstr;
294 
295     sep = strchr(str, '=');
296     if (sep == NULL) {
297         return 1;
298     } else {
299         val = sep + 1;
300     }
301     for (flag = cpuid_flags; flag->name != NULL; flag++) {
302         if(!strncmp(str, flag->name, sep - str) && flag->name[sep - str] == 0)
303             break;
304     }
305     if (flag->name == NULL) {
306         return 2;
307     }
308     entry = cpuid_find_match(cpuid, flag->leaf, flag->subleaf);
309     resstr = entry->policy[flag->reg - 1];
310     num = strtoull(val, &endptr, 0);
311     flags[flag->length] = 0;
312     if (endptr != val) {
313         /* if this was a valid number, write the binary form into the string */
314         for (i = 0; i < flag->length; i++) {
315             flags[flag->length - 1 - i] = "01"[!!(num & (1 << i))];
316         }
317     } else {
318         switch(val[0]) {
319         case 'x': case 'k': case 's':
320             memset(flags, val[0], flag->length);
321             break;
322         default:
323             return 3;
324         }
325     }
326 
327     if (resstr == NULL) {
328         resstr = strdup("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
329     }
330 
331     /* the family and model entry is potentially split up across
332      * two fields in Fn0000_0001_EAX, so handle them here separately.
333      */
334     if (!strncmp(str, "family", sep - str)) {
335         if (num < 16) {
336             memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
337             memcpy(resstr + (32 - 8) - 20, "00000000", 8);
338         } else {
339             num -= 15;
340             memcpy(resstr + (32 - 4) - flag->bit, "1111", 4);
341             for (i = 0; i < 7; i++) {
342                 flags[7 - i] = "01"[num & 1];
343                 num >>= 1;
344             }
345             memcpy(resstr + (32 - 8) - 20, flags, 8);
346         }
347     } else if (!strncmp(str, "model", sep - str)) {
348         memcpy(resstr + (32 - 4) - 16, flags, 4);
349         memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
350     } else {
351         memcpy(resstr + (32 - flag->length) - flag->bit, flags,
352                flag->length);
353     }
354     entry->policy[flag->reg - 1] = resstr;
355 
356     return 0;
357 }
358 
359 /* parse a single list item from the legacy Python xend syntax, where
360  * the strings for each register were directly exposed to the user.
361  * Used for maintaining compatibility with older config files
362  */
libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list * cpuid,const char * str)363 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
364                                   const char* str)
365 {
366     char *endptr;
367     unsigned long value;
368     uint32_t leaf, subleaf = XEN_CPUID_INPUT_UNUSED;
369     struct xc_xend_cpuid *entry;
370 
371     /* parse the leaf number */
372     value = strtoul(str, &endptr, 0);
373     if (str == endptr) {
374         return 1;
375     }
376     leaf = value;
377     /* check for an optional subleaf number */
378     if (*endptr == ',') {
379         str = endptr + 1;
380         value = strtoul(str, &endptr, 0);
381         if (str == endptr) {
382             return 2;
383         }
384         subleaf = value;
385     }
386     if (*endptr != ':') {
387         return 3;
388     }
389     str = endptr + 1;
390     entry = cpuid_find_match(cpuid, leaf, subleaf);
391     for (str = endptr + 1; *str != 0;) {
392         if (str[0] != 'e' || str[2] != 'x') {
393             return 4;
394         }
395         value = str[1] - 'a';
396         endptr = strchr(str, '=');
397         if (value > 3 || endptr == NULL) {
398             return 4;
399         }
400         str = endptr + 1;
401         endptr = strchr(str, ',');
402         if (endptr == NULL) {
403             endptr = strchr(str, 0);
404         }
405         if (endptr - str != 32) {
406             return 5;
407         }
408         entry->policy[value] = calloc(32 + 1, 1);
409         strncpy(entry->policy[value], str, 32);
410         entry->policy[value][32] = 0;
411         if (*endptr == 0) {
412             break;
413         }
414         for (str = endptr + 1; *str == ' ' || *str == '\n'; str++);
415     }
416     return 0;
417 }
418 
libxl__cpuid_legacy(libxl_ctx * ctx,uint32_t domid,bool restore,libxl_domain_build_info * info)419 void libxl__cpuid_legacy(libxl_ctx *ctx, uint32_t domid, bool restore,
420                          libxl_domain_build_info *info)
421 {
422     bool pae = true;
423 
424     /*
425      * For PV guests, PAE is Xen-controlled (it is the 'p' that differentiates
426      * the xen-3.0-x86_32 and xen-3.0-x86_32p ABIs).  It is mandatory as Xen
427      * is 64bit only these days.
428      *
429      * For PVH guests, there is no top-level PAE control in the domain config,
430      * so is treated as always available.
431      *
432      * HVM guests get a top-level choice of whether PAE is available.
433      */
434     if (info->type == LIBXL_DOMAIN_TYPE_HVM)
435         pae = libxl_defbool_val(info->u.hvm.pae);
436 
437     xc_cpuid_apply_policy(ctx->xch, domid, restore, NULL, 0, pae, info->cpuid);
438 }
439 
440 static const char *input_names[2] = { "leaf", "subleaf" };
441 static const char *policy_names[4] = { "eax", "ebx", "ecx", "edx" };
442 /*
443  * Aiming for:
444  * [
445  *     { 'leaf':    'val-eax',
446  *       'subleaf': 'val-ecx',
447  *       'eax':     'filter',
448  *       'ebx':     'filter',
449  *       'ecx':     'filter',
450  *       'edx':     'filter' },
451  *     { 'leaf':    'val-eax', ..., 'eax': 'filter', ... },
452  *     ... etc ...
453  * ]
454  */
455 
libxl_cpuid_policy_list_gen_json(yajl_gen hand,libxl_cpuid_policy_list * pcpuid)456 yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand,
457                                 libxl_cpuid_policy_list *pcpuid)
458 {
459     libxl_cpuid_policy_list cpuid = *pcpuid;
460     yajl_gen_status s;
461     int i, j;
462 
463     s = yajl_gen_array_open(hand);
464     if (s != yajl_gen_status_ok) goto out;
465 
466     if (cpuid == NULL) goto empty;
467 
468     for (i = 0; cpuid[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
469         s = yajl_gen_map_open(hand);
470         if (s != yajl_gen_status_ok) goto out;
471 
472         for (j = 0; j < 2; j++) {
473             if (cpuid[i].input[j] != XEN_CPUID_INPUT_UNUSED) {
474                 s = libxl__yajl_gen_asciiz(hand, input_names[j]);
475                 if (s != yajl_gen_status_ok) goto out;
476                 s = yajl_gen_integer(hand, cpuid[i].input[j]);
477                 if (s != yajl_gen_status_ok) goto out;
478             }
479         }
480 
481         for (j = 0; j < 4; j++) {
482             if (cpuid[i].policy[j] != NULL) {
483                 s = libxl__yajl_gen_asciiz(hand, policy_names[j]);
484                 if (s != yajl_gen_status_ok) goto out;
485                 s = yajl_gen_string(hand,
486                                (const unsigned char *)cpuid[i].policy[j], 32);
487                 if (s != yajl_gen_status_ok) goto out;
488             }
489         }
490         s = yajl_gen_map_close(hand);
491         if (s != yajl_gen_status_ok) goto out;
492     }
493 
494 empty:
495     s = yajl_gen_array_close(hand);
496 out:
497     return s;
498 }
499 
libxl__cpuid_policy_list_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_cpuid_policy_list * p)500 int libxl__cpuid_policy_list_parse_json(libxl__gc *gc,
501                                         const libxl__json_object *o,
502                                         libxl_cpuid_policy_list *p)
503 {
504     int i, size;
505     libxl_cpuid_policy_list l;
506     flexarray_t *array;
507 
508     if (!libxl__json_object_is_array(o))
509         return ERROR_FAIL;
510 
511     array = libxl__json_object_get_array(o);
512     if (!array->count)
513         return 0;
514 
515     size = array->count;
516     /* need one extra slot as sentinel */
517     l = *p = libxl__calloc(NOGC, size + 1, sizeof(libxl_cpuid_policy));
518 
519     l[size].input[0] = XEN_CPUID_INPUT_UNUSED;
520     l[size].input[1] = XEN_CPUID_INPUT_UNUSED;
521 
522     for (i = 0; i < size; i++) {
523         const libxl__json_object *t;
524         int j;
525 
526         if (flexarray_get(array, i, (void**)&t) != 0)
527             return ERROR_FAIL;
528 
529         if (!libxl__json_object_is_map(t))
530             return ERROR_FAIL;
531 
532         for (j = 0; j < ARRAY_SIZE(l[0].input); j++) {
533             const libxl__json_object *r;
534 
535             r = libxl__json_map_get(input_names[j], t, JSON_INTEGER);
536             if (!r)
537                 l[i].input[j] = XEN_CPUID_INPUT_UNUSED;
538             else
539                 l[i].input[j] = libxl__json_object_get_integer(r);
540         }
541 
542         for (j = 0; j < ARRAY_SIZE(l[0].policy); j++) {
543             const libxl__json_object *r;
544 
545             r = libxl__json_map_get(policy_names[j], t, JSON_STRING);
546             if (!r)
547                 l[i].policy[j] = NULL;
548             else
549                 l[i].policy[j] =
550                     libxl__strdup(NOGC, libxl__json_object_get_string(r));
551         }
552     }
553 
554     return 0;
555 }
556 
libxl_cpuid_policy_list_length(const libxl_cpuid_policy_list * pl)557 int libxl_cpuid_policy_list_length(const libxl_cpuid_policy_list *pl)
558 {
559     int i = 0;
560     libxl_cpuid_policy_list l = *pl;
561 
562     if (l) {
563         while (l[i].input[0] != XEN_CPUID_INPUT_UNUSED)
564             i++;
565     }
566 
567     return i;
568 }
569 
libxl_cpuid_policy_list_copy(libxl_ctx * ctx,libxl_cpuid_policy_list * dst,const libxl_cpuid_policy_list * src)570 void libxl_cpuid_policy_list_copy(libxl_ctx *ctx,
571                                   libxl_cpuid_policy_list *dst,
572                                   const libxl_cpuid_policy_list *src)
573 {
574     GC_INIT(ctx);
575     int i, j, len;
576 
577     if (*src == NULL) {
578         *dst = NULL;
579         goto out;
580     }
581 
582     len = libxl_cpuid_policy_list_length(src);
583     /* one extra slot for sentinel */
584     *dst = libxl__calloc(NOGC, len + 1, sizeof(libxl_cpuid_policy));
585     (*dst)[len].input[0] = XEN_CPUID_INPUT_UNUSED;
586     (*dst)[len].input[1] = XEN_CPUID_INPUT_UNUSED;
587 
588     for (i = 0; i < len; i++) {
589         for (j = 0; j < 2; j++)
590             (*dst)[i].input[j] = (*src)[i].input[j];
591         for (j = 0; j < 4; j++)
592             if ((*src)[i].policy[j])
593                 (*dst)[i].policy[j] =
594                     libxl__strdup(NOGC, (*src)[i].policy[j]);
595             else
596                 (*dst)[i].policy[j] = NULL;
597     }
598 
599 out:
600     GC_FREE;
601 }
602 
603 /*
604  * Local variables:
605  * mode: C
606  * c-basic-offset: 4
607  * indent-tabs-mode: nil
608  * End:
609  */
610