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