debuggers.hg

view tools/libxl/libxl_cpuid.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents c553d3035fd5
children 6067a17114bc
line source
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 */
13 #include <string.h>
15 #include "libxl.h"
16 #include "libxl_osdeps.h"
17 #include "libxl_internal.h"
19 void libxl_cpuid_destroy(libxl_cpuid_policy_list *p_cpuid_list)
20 {
21 int i, j;
22 libxl_cpuid_policy_list cpuid_list = *p_cpuid_list;
24 if (cpuid_list == NULL)
25 return;
26 for (i = 0; cpuid_list[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
27 for (j = 0; j < 4; j++)
28 if (cpuid_list[i].policy[j] != NULL)
29 free(cpuid_list[i].policy[j]);
30 }
31 return;
32 }
34 #define CPUID_REG_INV 0
35 #define CPUID_REG_EAX 1
36 #define CPUID_REG_EBX 2
37 #define CPUID_REG_ECX 3
38 #define CPUID_REG_EDX 4
40 /* mapping CPUID features to names
41 * holds a "name" for each feature, specified by the "leaf" number (and an
42 * optional "subleaf" in ECX), the "reg"ister (EAX-EDX) used and a number of
43 * bits starting with "bit" and being "length" bits long.
44 * Used for the static structure describing all features.
45 */
46 struct cpuid_flags {
47 char* name;
48 uint32_t leaf;
49 uint32_t subleaf;
50 int reg;
51 int bit;
52 int length;
53 };
55 /* go through the dynamic array finding the entry for a specified leaf.
56 * if no entry exists, allocate one and return that.
57 */
58 static libxl_cpuid_policy_list cpuid_find_match(libxl_cpuid_policy_list *list,
59 uint32_t leaf, uint32_t subleaf)
60 {
61 int i = 0;
63 if (*list != NULL) {
64 for (i = 0; (*list)[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
65 if ((*list)[i].input[0] == leaf && (*list)[i].input[1] == subleaf)
66 return *list + i;
67 }
68 }
69 *list = realloc(*list, sizeof((*list)[0]) * (i + 2));
70 (*list)[i].input[0] = leaf;
71 (*list)[i].input[1] = subleaf;
72 memset((*list)[i].policy, 0, 4 * sizeof(char*));
73 (*list)[i + 1].input[0] = XEN_CPUID_INPUT_UNUSED;
74 return *list + i;
75 }
77 /* parse a single key=value pair and translate it into the libxc
78 * used interface using 32-characters strings for each register.
79 * Will overwrite earlier entries and thus can be called multiple
80 * times.
81 */
82 int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
83 {
84 #define NA XEN_CPUID_INPUT_UNUSED
85 struct cpuid_flags cpuid_flags[] = {
86 {"maxleaf", 0x00000000, NA, CPUID_REG_EAX, 0, 32},
87 /* the following two entries are subject to tweaking later in the code */
88 {"family", 0x00000001, NA, CPUID_REG_EAX, 8, 8},
89 {"model", 0x00000001, NA, CPUID_REG_EAX, 4, 8},
90 {"stepping", 0x00000001, NA, CPUID_REG_EAX, 0, 4},
91 {"localapicid", 0x00000001, NA, CPUID_REG_EBX, 24, 8},
92 {"proccount", 0x00000001, NA, CPUID_REG_EBX, 16, 8},
93 {"clflush", 0x00000001, NA, CPUID_REG_EBX, 8, 8},
94 {"brandid", 0x00000001, NA, CPUID_REG_EBX, 0, 8},
95 {"f16c", 0x00000001, NA, CPUID_REG_ECX, 29, 1},
96 {"avx", 0x00000001, NA, CPUID_REG_ECX, 28, 1},
97 {"osxsave", 0x00000001, NA, CPUID_REG_ECX, 27, 1},
98 {"xsave", 0x00000001, NA, CPUID_REG_ECX, 26, 1},
99 {"aes", 0x00000001, NA, CPUID_REG_ECX, 25, 1},
100 {"popcnt", 0x00000001, NA, CPUID_REG_ECX, 23, 1},
101 {"movbe", 0x00000001, NA, CPUID_REG_ECX, 22, 1},
102 {"x2apic", 0x00000001, NA, CPUID_REG_ECX, 21, 1},
103 {"sse4.2", 0x00000001, NA, CPUID_REG_ECX, 20, 1},
104 {"sse4.1", 0x00000001, NA, CPUID_REG_ECX, 19, 1},
105 {"dca", 0x00000001, NA, CPUID_REG_ECX, 18, 1},
106 {"pdcm", 0x00000001, NA, CPUID_REG_ECX, 15, 1},
107 {"xtpr", 0x00000001, NA, CPUID_REG_ECX, 14, 1},
108 {"cmpxchg16", 0x00000001, NA, CPUID_REG_ECX, 13, 1},
109 {"cntxid", 0x00000001, NA, CPUID_REG_ECX, 10, 1},
110 {"ssse3", 0x00000001, NA, CPUID_REG_ECX, 9, 1},
111 {"tm2", 0x00000001, NA, CPUID_REG_ECX, 8, 1},
112 {"est", 0x00000001, NA, CPUID_REG_ECX, 7, 1},
113 {"smx", 0x00000001, NA, CPUID_REG_ECX, 6, 1},
114 {"vmx", 0x00000001, NA, CPUID_REG_ECX, 5, 1},
115 {"dscpl", 0x00000001, NA, CPUID_REG_ECX, 4, 1},
116 {"monitor", 0x00000001, NA, CPUID_REG_ECX, 3, 1},
117 {"dtes64", 0x00000001, NA, CPUID_REG_ECX, 2, 1},
118 {"sse3", 0x00000001, NA, CPUID_REG_ECX, 0, 1},
119 {"pbe", 0x00000001, NA, CPUID_REG_EDX, 31, 1},
120 {"ia64", 0x00000001, NA, CPUID_REG_EDX, 30, 1},
121 {"tm", 0x00000001, NA, CPUID_REG_EDX, 29, 1},
122 {"htt", 0x00000001, NA, CPUID_REG_EDX, 28, 1},
123 {"ss", 0x00000001, NA, CPUID_REG_EDX, 27, 1},
124 {"sse2", 0x00000001, NA, CPUID_REG_EDX, 26, 1},
125 {"sse", 0x00000001, NA, CPUID_REG_EDX, 25, 1},
126 {"fxsr", 0x00000001, NA, CPUID_REG_EDX, 24, 1},
127 {"mmx", 0x00000001, NA, CPUID_REG_EDX, 23, 1},
128 {"acpi", 0x00000001, NA, CPUID_REG_EDX, 22, 1},
129 {"ds", 0x00000001, NA, CPUID_REG_EDX, 21, 1},
130 {"clfsh", 0x00000001, NA, CPUID_REG_EDX, 19, 1},
131 {"psn", 0x00000001, NA, CPUID_REG_EDX, 18, 1},
132 {"pse36", 0x00000001, NA, CPUID_REG_EDX, 17, 1},
133 {"pat", 0x00000001, NA, CPUID_REG_EDX, 16, 1},
134 {"cmov", 0x00000001, NA, CPUID_REG_EDX, 15, 1},
135 {"mca", 0x00000001, NA, CPUID_REG_EDX, 14, 1},
136 {"pge", 0x00000001, NA, CPUID_REG_EDX, 13, 1},
137 {"mtrr", 0x00000001, NA, CPUID_REG_EDX, 12, 1},
138 {"sysenter", 0x00000001, NA, CPUID_REG_EDX, 11, 1},
139 {"apic", 0x00000001, NA, CPUID_REG_EDX, 9, 1},
140 {"cmpxchg8", 0x00000001, NA, CPUID_REG_EDX, 8, 1},
141 {"mce", 0x00000001, NA, CPUID_REG_EDX, 7, 1},
142 {"pae", 0x00000001, NA, CPUID_REG_EDX, 6, 1},
143 {"msr", 0x00000001, NA, CPUID_REG_EDX, 5, 1},
144 {"tsc", 0x00000001, NA, CPUID_REG_EDX, 4, 1},
145 {"pse", 0x00000001, NA, CPUID_REG_EDX, 3, 1},
146 {"de", 0x00000001, NA, CPUID_REG_EDX, 2, 1},
147 {"vme", 0x00000001, NA, CPUID_REG_EDX, 1, 1},
148 {"fpu", 0x00000001, NA, CPUID_REG_EDX, 0, 1},
149 {"topoext", 0x80000001, NA, CPUID_REG_ECX, 22, 1},
150 {"tbm", 0x80000001, NA, CPUID_REG_ECX, 21, 1},
151 {"nodeid", 0x80000001, NA, CPUID_REG_ECX, 19, 1},
152 {"fma4", 0x80000001, NA, CPUID_REG_ECX, 16, 1},
153 {"lwp", 0x80000001, NA, CPUID_REG_ECX, 15, 1},
154 {"wdt", 0x80000001, NA, CPUID_REG_ECX, 13, 1},
155 {"skinit", 0x80000001, NA, CPUID_REG_ECX, 12, 1},
156 {"xop", 0x80000001, NA, CPUID_REG_ECX, 11, 1},
157 {"ibs", 0x80000001, NA, CPUID_REG_ECX, 10, 1},
158 {"osvw", 0x80000001, NA, CPUID_REG_ECX, 10, 1},
159 {"3dnowprefetch",0x80000001, NA, CPUID_REG_ECX, 8, 1},
160 {"misalignsse", 0x80000001, NA, CPUID_REG_ECX, 7, 1},
161 {"sse4a", 0x80000001, NA, CPUID_REG_ECX, 6, 1},
162 {"abm", 0x80000001, NA, CPUID_REG_ECX, 5, 1},
163 {"altmovcr8", 0x80000001, NA, CPUID_REG_ECX, 4, 1},
164 {"extapic", 0x80000001, NA, CPUID_REG_ECX, 3, 1},
165 {"svm", 0x80000001, NA, CPUID_REG_ECX, 2, 1},
166 {"cmplegacy", 0x80000001, NA, CPUID_REG_ECX, 1, 1},
167 {"lahfsahf", 0x80000001, NA, CPUID_REG_ECX, 0, 1},
168 {"3dnow", 0x80000001, NA, CPUID_REG_EDX, 31, 1},
169 {"3dnowext", 0x80000001, NA, CPUID_REG_EDX, 30, 1},
170 {"lm", 0x80000001, NA, CPUID_REG_EDX, 29, 1},
171 {"rdtscp", 0x80000001, NA, CPUID_REG_EDX, 27, 1},
172 {"page1gb", 0x80000001, NA, CPUID_REG_EDX, 26, 1},
173 {"ffxsr", 0x80000001, NA, CPUID_REG_EDX, 25, 1},
174 {"mmxext", 0x80000001, NA, CPUID_REG_EDX, 22, 1},
175 {"nx", 0x80000001, NA, CPUID_REG_EDX, 20, 1},
176 {"syscall", 0x80000001, NA, CPUID_REG_EDX, 11, 1},
177 {"procpkg", 0x00000004, 0, CPUID_REG_EAX, 26, 6},
178 {"apicidsize", 0x80000008, NA, CPUID_REG_ECX, 12, 4},
179 {"nc", 0x80000008, NA, CPUID_REG_ECX, 0, 8},
181 {NULL, 0, CPUID_REG_INV, 0, 0}
182 };
183 #undef NA
184 char *sep, *val, *endptr;
185 int i;
186 struct cpuid_flags *flag;
187 struct libxl__cpuid_policy *entry;
188 unsigned long num;
189 char flags[33], *resstr;
191 sep = strchr(str, '=');
192 if (sep == NULL) {
193 return 1;
194 } else {
195 val = sep + 1;
196 }
197 for (flag = cpuid_flags; flag->name != NULL; flag++) {
198 if(!strncmp(str, flag->name, sep - str) && flag->name[sep - str] == 0)
199 break;
200 }
201 if (flag->name == NULL) {
202 return 2;
203 }
204 entry = cpuid_find_match(cpuid, flag->leaf, flag->subleaf);
205 resstr = entry->policy[flag->reg - 1];
206 if (resstr == NULL) {
207 resstr = strdup("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
208 }
209 num = strtoull(val, &endptr, 0);
210 flags[flag->length] = 0;
211 if (endptr != val) {
212 /* is this was a valid number, write the binary form into the string */
213 for (i = 0; i < flag->length; i++) {
214 flags[flag->length - 1 - i] = "01"[!!(num & (1 << i))];
215 }
216 } else {
217 switch(val[0]) {
218 case 'x': case 'k': case 's':
219 memset(flags, val[0], flag->length);
220 break;
221 default:
222 return 3;
223 }
224 }
225 /* the family and model entry is potentially split up across
226 * two fields in Fn0000_0001_EAX, so handle them here separately.
227 */
228 if (!strncmp(str, "family", sep - str)) {
229 if (num < 16) {
230 memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
231 memcpy(resstr + (32 - 8) - 20, "00000000", 8);
232 } else {
233 num -= 15;
234 memcpy(resstr + (32 - 4) - flag->bit, "1111", 4);
235 for (i = 0; i < 7; i++) {
236 flags[7 - i] = "01"[num & 1];
237 num >>= 1;
238 }
239 memcpy(resstr + (32 - 8) - 20, flags, 8);
240 }
241 } else if (!strncmp(str, "model", sep - str)) {
242 memcpy(resstr + (32 - 4) - 16, flags, 4);
243 memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
244 } else {
245 memcpy(resstr + (32 - flag->length) - flag->bit, flags,
246 flag->length);
247 }
248 entry->policy[flag->reg - 1] = resstr;
250 return 0;
251 }
253 /* parse a single list item from the legacy Python xend syntax, where
254 * the strings for each register were directly exposed to the user.
255 * Used for maintaining compatibility with older config files
256 */
257 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
258 const char* str)
259 {
260 char *endptr;
261 unsigned long value;
262 uint32_t leaf, subleaf = XEN_CPUID_INPUT_UNUSED;
263 struct libxl__cpuid_policy *entry;
265 /* parse the leaf number */
266 value = strtoul(str, &endptr, 0);
267 if (str == endptr) {
268 return 1;
269 }
270 leaf = value;
271 /* check for an optional subleaf number */
272 if (*endptr == ',') {
273 str = endptr + 1;
274 value = strtoul(str, &endptr, 0);
275 if (str == endptr) {
276 return 2;
277 }
278 subleaf = value;
279 }
280 if (*endptr != ':') {
281 return 3;
282 }
283 str = endptr + 1;
284 entry = cpuid_find_match(cpuid, leaf, subleaf);
285 for (str = endptr + 1; *str != 0;) {
286 if (str[0] != 'e' || str[2] != 'x') {
287 return 4;
288 }
289 value = str[1] - 'a';
290 endptr = strchr(str, '=');
291 if (value < 0 || value > 3 || endptr == NULL) {
292 return 4;
293 }
294 str = endptr + 1;
295 endptr = strchr(str, ',');
296 if (endptr == NULL) {
297 endptr = strchr(str, 0);
298 }
299 if (endptr - str != 32) {
300 return 5;
301 }
302 entry->policy[value] = calloc(32 + 1, 1);
303 strncpy(entry->policy[value], str, 32);
304 entry->policy[value][32] = 0;
305 if (*endptr == 0) {
306 break;
307 }
308 for (str = endptr + 1; *str == ' ' || *str == '\n'; str++);
309 }
310 return 0;
311 }
313 void libxl_cpuid_apply_policy(libxl_ctx *ctx, uint32_t domid)
314 {
315 xc_cpuid_apply_policy(ctx->xch, domid);
316 }
318 void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid,
319 libxl_cpuid_policy_list cpuid)
320 {
321 int i;
322 char *cpuid_res[4];
324 for (i = 0; cpuid[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++)
325 xc_cpuid_set(ctx->xch, domid, cpuid[i].input,
326 (const char**)(cpuid[i].policy), cpuid_res);
327 }