debuggers.hg

view tools/libxc/xc_cpuid_x86.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents f8692cc67d67
children 23291daa9da4
line source
1 /******************************************************************************
2 * xc_cpuid_x86.c
3 *
4 * Compute cpuid of a domain.
5 *
6 * Copyright (c) 2008, Citrix Systems, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
20 */
22 #include <stdlib.h>
23 #include "xc_private.h"
24 #include "xc_cpufeature.h"
25 #include <xen/hvm/params.h>
27 #define bitmaskof(idx) (1u << ((idx) & 31))
28 #define clear_bit(idx, dst) ((dst) &= ~(1u << ((idx) & 31)))
29 #define set_bit(idx, dst) ((dst) |= (1u << ((idx) & 31)))
31 #define DEF_MAX_BASE 0x0000000du
32 #define DEF_MAX_EXT 0x80000008u
34 static int hypervisor_is_64bit(int xc)
35 {
36 xen_capabilities_info_t xen_caps = "";
37 return ((xc_version(xc, XENVER_capabilities, &xen_caps) == 0) &&
38 (strstr(xen_caps, "x86_64") != NULL));
39 }
41 static void cpuid(const unsigned int *input, unsigned int *regs)
42 {
43 unsigned int count = (input[1] == XEN_CPUID_INPUT_UNUSED) ? 0 : input[1];
44 asm (
45 #ifdef __i386__
46 "push %%ebx; push %%edx\n\t"
47 #else
48 "push %%rbx; push %%rdx\n\t"
49 #endif
50 "cpuid\n\t"
51 "mov %%ebx,4(%4)\n\t"
52 "mov %%edx,12(%4)\n\t"
53 #ifdef __i386__
54 "pop %%edx; pop %%ebx\n\t"
55 #else
56 "pop %%rdx; pop %%rbx\n\t"
57 #endif
58 : "=a" (regs[0]), "=c" (regs[2])
59 : "0" (input[0]), "1" (count), "S" (regs)
60 : "memory" );
61 }
63 /* Get the manufacturer brand name of the host processor. */
64 static void xc_cpuid_brand_get(char *str)
65 {
66 unsigned int input[2] = { 0, 0 };
67 unsigned int regs[4];
69 cpuid(input, regs);
71 *(uint32_t *)(str + 0) = regs[1];
72 *(uint32_t *)(str + 4) = regs[3];
73 *(uint32_t *)(str + 8) = regs[2];
74 str[12] = '\0';
75 }
77 static void amd_xc_cpuid_policy(
78 int xc, domid_t domid, const unsigned int *input, unsigned int *regs,
79 int is_pae)
80 {
81 switch ( input[0] )
82 {
83 case 0x00000002:
84 case 0x00000004:
85 regs[0] = regs[1] = regs[2] = 0;
86 break;
88 case 0x80000001: {
89 int is_64bit = hypervisor_is_64bit(xc) && is_pae;
91 if ( !is_pae )
92 clear_bit(X86_FEATURE_PAE, regs[3]);
93 clear_bit(X86_FEATURE_PSE36, regs[3]);
95 /* Filter all other features according to a whitelist. */
96 regs[2] &= ((is_64bit ? bitmaskof(X86_FEATURE_LAHF_LM) : 0) |
97 bitmaskof(X86_FEATURE_CMP_LEGACY) |
98 bitmaskof(X86_FEATURE_ALTMOVCR) |
99 bitmaskof(X86_FEATURE_ABM) |
100 bitmaskof(X86_FEATURE_SSE4A) |
101 bitmaskof(X86_FEATURE_MISALIGNSSE) |
102 bitmaskof(X86_FEATURE_3DNOWPF));
103 regs[3] &= (0x0183f3ff | /* features shared with 0x00000001:EDX */
104 (is_pae ? bitmaskof(X86_FEATURE_NX) : 0) |
105 (is_64bit ? bitmaskof(X86_FEATURE_LM) : 0) |
106 bitmaskof(X86_FEATURE_SYSCALL) |
107 bitmaskof(X86_FEATURE_MP) |
108 bitmaskof(X86_FEATURE_MMXEXT) |
109 bitmaskof(X86_FEATURE_FFXSR) |
110 bitmaskof(X86_FEATURE_3DNOW) |
111 bitmaskof(X86_FEATURE_3DNOWEXT));
112 break;
113 }
115 case 0x80000008:
116 /*
117 * ECX[15:12] is ApicIdCoreSize: ECX[7:0] is NumberOfCores (minus one).
118 * Update to reflect vLAPIC_ID = vCPU_ID * 2.
119 */
120 regs[2] = ((regs[2] & 0xf000u) + 1) | ((regs[2] & 0xffu) << 1) | 1u;
121 break;
122 }
123 }
125 static void intel_xc_cpuid_policy(
126 int xc, domid_t domid, const unsigned int *input, unsigned int *regs,
127 int is_pae)
128 {
129 switch ( input[0] )
130 {
131 case 0x00000004:
132 /*
133 * EAX[31:26] is Maximum Cores Per Package (minus one).
134 * Update to reflect vLAPIC_ID = vCPU_ID * 2.
135 */
136 regs[0] = (((regs[0] & 0x7c000000u) << 1) | 0x04000000u |
137 (regs[0] & 0x3ffu));
138 regs[3] &= 0x3ffu;
139 break;
141 case 0x80000001: {
142 int is_64bit = hypervisor_is_64bit(xc) && is_pae;
144 /* Only a few features are advertised in Intel's 0x80000001. */
145 regs[2] &= (is_64bit ? bitmaskof(X86_FEATURE_LAHF_LM) : 0);
146 regs[3] &= ((is_pae ? bitmaskof(X86_FEATURE_NX) : 0) |
147 (is_64bit ? bitmaskof(X86_FEATURE_LM) : 0) |
148 (is_64bit ? bitmaskof(X86_FEATURE_SYSCALL) : 0) |
149 (is_64bit ? bitmaskof(X86_FEATURE_RDTSCP) : 0));
150 break;
151 }
153 case 0x80000005:
154 regs[0] = regs[1] = regs[2] = 0;
155 break;
157 case 0x80000008:
158 /* Mask AMD Number of Cores information. */
159 regs[2] = 0;
160 break;
161 }
162 }
164 static void xc_cpuid_hvm_policy(
165 int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
166 {
167 char brand[13];
168 unsigned long pae;
169 int is_pae;
171 xc_get_hvm_param(xc, domid, HVM_PARAM_PAE_ENABLED, &pae);
172 is_pae = !!pae;
174 switch ( input[0] )
175 {
176 case 0x00000000:
177 if ( regs[0] > DEF_MAX_BASE )
178 regs[0] = DEF_MAX_BASE;
179 break;
181 case 0x00000001:
182 /*
183 * EBX[23:16] is Maximum Logical Processors Per Package.
184 * Update to reflect vLAPIC_ID = vCPU_ID * 2.
185 */
186 regs[1] = (regs[1] & 0x0000ffffu) | ((regs[1] & 0x007f0000u) << 1);
188 regs[2] &= (bitmaskof(X86_FEATURE_XMM3) |
189 bitmaskof(X86_FEATURE_SSSE3) |
190 bitmaskof(X86_FEATURE_CX16) |
191 bitmaskof(X86_FEATURE_SSE4_1) |
192 bitmaskof(X86_FEATURE_SSE4_2) |
193 bitmaskof(X86_FEATURE_POPCNT));
195 regs[2] |= bitmaskof(X86_FEATURE_HYPERVISOR);
197 regs[3] &= (bitmaskof(X86_FEATURE_FPU) |
198 bitmaskof(X86_FEATURE_VME) |
199 bitmaskof(X86_FEATURE_DE) |
200 bitmaskof(X86_FEATURE_PSE) |
201 bitmaskof(X86_FEATURE_TSC) |
202 bitmaskof(X86_FEATURE_MSR) |
203 bitmaskof(X86_FEATURE_PAE) |
204 bitmaskof(X86_FEATURE_MCE) |
205 bitmaskof(X86_FEATURE_CX8) |
206 bitmaskof(X86_FEATURE_APIC) |
207 bitmaskof(X86_FEATURE_SEP) |
208 bitmaskof(X86_FEATURE_MTRR) |
209 bitmaskof(X86_FEATURE_PGE) |
210 bitmaskof(X86_FEATURE_MCA) |
211 bitmaskof(X86_FEATURE_CMOV) |
212 bitmaskof(X86_FEATURE_PAT) |
213 bitmaskof(X86_FEATURE_CLFLSH) |
214 bitmaskof(X86_FEATURE_MMX) |
215 bitmaskof(X86_FEATURE_FXSR) |
216 bitmaskof(X86_FEATURE_XMM) |
217 bitmaskof(X86_FEATURE_XMM2) |
218 bitmaskof(X86_FEATURE_HT));
220 /* We always support MTRR MSRs. */
221 regs[3] |= bitmaskof(X86_FEATURE_MTRR);
223 if ( !is_pae )
224 clear_bit(X86_FEATURE_PAE, regs[3]);
225 break;
227 case 0x80000000:
228 if ( regs[0] > DEF_MAX_EXT )
229 regs[0] = DEF_MAX_EXT;
230 break;
232 case 0x80000001:
233 if ( !is_pae )
234 clear_bit(X86_FEATURE_NX, regs[3]);
235 break;
237 case 0x80000007:
238 /*
239 * Keep only TSCInvariant. This may be cleared by the hypervisor
240 * depending on guest TSC and migration settings.
241 */
242 regs[0] = regs[1] = regs[2] = 0;
243 regs[3] &= 1u<<8;
244 break;
246 case 0x80000008:
247 regs[0] &= 0x0000ffffu;
248 regs[1] = regs[3] = 0;
249 break;
251 case 0x00000002: /* Intel cache info (dumped by AMD policy) */
252 case 0x00000004: /* Intel cache info (dumped by AMD policy) */
253 case 0x80000002: /* Processor name string */
254 case 0x80000003: /* ... continued */
255 case 0x80000004: /* ... continued */
256 case 0x80000005: /* AMD L1 cache/TLB info (dumped by Intel policy) */
257 case 0x80000006: /* AMD L2/3 cache/TLB info ; Intel L2 cache features */
258 break;
260 default:
261 regs[0] = regs[1] = regs[2] = regs[3] = 0;
262 break;
263 }
265 xc_cpuid_brand_get(brand);
266 if ( strstr(brand, "AMD") )
267 amd_xc_cpuid_policy(xc, domid, input, regs, is_pae);
268 else
269 intel_xc_cpuid_policy(xc, domid, input, regs, is_pae);
271 }
273 static void xc_cpuid_pv_policy(
274 int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
275 {
276 DECLARE_DOMCTL;
277 int guest_64bit, xen_64bit = hypervisor_is_64bit(xc);
278 char brand[13];
280 xc_cpuid_brand_get(brand);
282 memset(&domctl, 0, sizeof(domctl));
283 domctl.domain = domid;
284 domctl.cmd = XEN_DOMCTL_get_address_size;
285 do_domctl(xc, &domctl);
286 guest_64bit = (domctl.u.address_size.size == 64);
288 if ( (input[0] & 0x7fffffff) == 1 )
289 {
290 clear_bit(X86_FEATURE_VME, regs[3]);
291 clear_bit(X86_FEATURE_PSE, regs[3]);
292 clear_bit(X86_FEATURE_PGE, regs[3]);
293 clear_bit(X86_FEATURE_MCE, regs[3]);
294 clear_bit(X86_FEATURE_MCA, regs[3]);
295 clear_bit(X86_FEATURE_MTRR, regs[3]);
296 clear_bit(X86_FEATURE_PSE36, regs[3]);
297 }
299 switch ( input[0] )
300 {
301 case 1:
302 if ( !xen_64bit || strstr(brand, "AMD") )
303 clear_bit(X86_FEATURE_SEP, regs[3]);
304 clear_bit(X86_FEATURE_DS, regs[3]);
305 clear_bit(X86_FEATURE_ACC, regs[3]);
306 clear_bit(X86_FEATURE_PBE, regs[3]);
308 clear_bit(X86_FEATURE_DTES64, regs[2]);
309 clear_bit(X86_FEATURE_MWAIT, regs[2]);
310 clear_bit(X86_FEATURE_DSCPL, regs[2]);
311 clear_bit(X86_FEATURE_VMXE, regs[2]);
312 clear_bit(X86_FEATURE_SMXE, regs[2]);
313 clear_bit(X86_FEATURE_EST, regs[2]);
314 clear_bit(X86_FEATURE_TM2, regs[2]);
315 if ( !guest_64bit )
316 clear_bit(X86_FEATURE_CX16, regs[2]);
317 clear_bit(X86_FEATURE_XTPR, regs[2]);
318 clear_bit(X86_FEATURE_PDCM, regs[2]);
319 clear_bit(X86_FEATURE_DCA, regs[2]);
320 clear_bit(X86_FEATURE_XSAVE, regs[2]);
321 set_bit(X86_FEATURE_HYPERVISOR, regs[2]);
322 break;
323 case 0x80000001:
324 if ( !guest_64bit )
325 {
326 clear_bit(X86_FEATURE_LM, regs[3]);
327 clear_bit(X86_FEATURE_LAHF_LM, regs[2]);
328 if ( !strstr(brand, "AMD") )
329 clear_bit(X86_FEATURE_SYSCALL, regs[3]);
330 }
331 else
332 {
333 set_bit(X86_FEATURE_SYSCALL, regs[3]);
334 }
335 clear_bit(X86_FEATURE_PAGE1GB, regs[3]);
336 clear_bit(X86_FEATURE_RDTSCP, regs[3]);
338 clear_bit(X86_FEATURE_SVME, regs[2]);
339 clear_bit(X86_FEATURE_OSVW, regs[2]);
340 clear_bit(X86_FEATURE_IBS, regs[2]);
341 clear_bit(X86_FEATURE_SKINIT, regs[2]);
342 clear_bit(X86_FEATURE_WDT, regs[2]);
343 break;
344 case 5: /* MONITOR/MWAIT */
345 case 0xa: /* Architectural Performance Monitor Features */
346 case 0x8000000a: /* SVM revision and features */
347 case 0x8000001b: /* Instruction Based Sampling */
348 regs[0] = regs[1] = regs[2] = regs[3] = 0;
349 break;
350 }
351 }
353 static int xc_cpuid_policy(
354 int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
355 {
356 xc_dominfo_t info;
358 if ( xc_domain_getinfo(xc, domid, 1, &info) == 0 )
359 return -EINVAL;
361 if ( info.hvm )
362 xc_cpuid_hvm_policy(xc, domid, input, regs);
363 else
364 xc_cpuid_pv_policy(xc, domid, input, regs);
366 return 0;
367 }
369 static int xc_cpuid_do_domctl(
370 int xc, domid_t domid,
371 const unsigned int *input, const unsigned int *regs)
372 {
373 DECLARE_DOMCTL;
375 memset(&domctl, 0, sizeof (domctl));
376 domctl.domain = domid;
377 domctl.cmd = XEN_DOMCTL_set_cpuid;
378 domctl.u.cpuid.input[0] = input[0];
379 domctl.u.cpuid.input[1] = input[1];
380 domctl.u.cpuid.eax = regs[0];
381 domctl.u.cpuid.ebx = regs[1];
382 domctl.u.cpuid.ecx = regs[2];
383 domctl.u.cpuid.edx = regs[3];
385 return do_domctl(xc, &domctl);
386 }
388 static char *alloc_str(void)
389 {
390 char *s = malloc(33);
391 memset(s, 0, 33);
392 return s;
393 }
395 void xc_cpuid_to_str(const unsigned int *regs, char **strs)
396 {
397 int i, j;
399 for ( i = 0; i < 4; i++ )
400 {
401 strs[i] = alloc_str();
402 for ( j = 0; j < 32; j++ )
403 strs[i][j] = !!((regs[i] & (1U << (31 - j)))) ? '1' : '0';
404 }
405 }
407 int xc_cpuid_apply_policy(int xc, domid_t domid)
408 {
409 unsigned int input[2] = { 0, 0 }, regs[4];
410 unsigned int base_max, ext_max;
411 int rc;
413 cpuid(input, regs);
414 base_max = (regs[0] <= DEF_MAX_BASE) ? regs[0] : DEF_MAX_BASE;
415 input[0] = 0x80000000;
416 cpuid(input, regs);
417 ext_max = (regs[0] <= DEF_MAX_EXT) ? regs[0] : DEF_MAX_EXT;
419 input[0] = 0;
420 input[1] = XEN_CPUID_INPUT_UNUSED;
421 for ( ; ; )
422 {
423 cpuid(input, regs);
424 xc_cpuid_policy(xc, domid, input, regs);
426 if ( regs[0] || regs[1] || regs[2] || regs[3] )
427 {
428 rc = xc_cpuid_do_domctl(xc, domid, input, regs);
429 if ( rc )
430 return rc;
432 /* Intel cache descriptor leaves. */
433 if ( input[0] == 4 )
434 {
435 input[1]++;
436 /* More to do? Then loop keeping %%eax==0x00000004. */
437 if ( (regs[0] & 0x1f) != 0 )
438 continue;
439 }
440 }
442 input[0]++;
443 input[1] = (input[0] == 4) ? 0 : XEN_CPUID_INPUT_UNUSED;
444 if ( !(input[0] & 0x80000000u) && (input[0] > base_max ) )
445 input[0] = 0x80000000u;
447 if ( (input[0] & 0x80000000u) && (input[0] > ext_max) )
448 break;
449 }
451 return 0;
452 }
454 /*
455 * Check whether a VM is allowed to launch on this host's processor type.
456 *
457 * @config format is similar to that of xc_cpuid_set():
458 * '1' -> the bit must be set to 1
459 * '0' -> must be 0
460 * 'x' -> we don't care
461 * 's' -> (same) must be the same
462 */
463 int xc_cpuid_check(
464 int xc, const unsigned int *input,
465 const char **config,
466 char **config_transformed)
467 {
468 int i, j;
469 unsigned int regs[4];
471 memset(config_transformed, 0, 4 * sizeof(*config_transformed));
473 cpuid(input, regs);
475 for ( i = 0; i < 4; i++ )
476 {
477 if ( config[i] == NULL )
478 continue;
479 config_transformed[i] = alloc_str();
480 for ( j = 0; j < 32; j++ )
481 {
482 unsigned char val = !!((regs[i] & (1U << (31 - j))));
483 if ( !strchr("10xs", config[i][j]) ||
484 ((config[i][j] == '1') && !val) ||
485 ((config[i][j] == '0') && val) )
486 goto fail;
487 config_transformed[i][j] = config[i][j];
488 if ( config[i][j] == 's' )
489 config_transformed[i][j] = '0' + val;
490 }
491 }
493 return 0;
495 fail:
496 for ( i = 0; i < 4; i++ )
497 {
498 free(config_transformed[i]);
499 config_transformed[i] = NULL;
500 }
501 return -EPERM;
502 }
504 /*
505 * Configure a single input with the informatiom from config.
506 *
507 * Config is an array of strings:
508 * config[0] = eax
509 * config[1] = ebx
510 * config[2] = ecx
511 * config[3] = edx
512 *
513 * The format of the string is the following:
514 * '1' -> force to 1
515 * '0' -> force to 0
516 * 'x' -> we don't care (use default)
517 * 'k' -> pass through host value
518 * 's' -> pass through the first time and then keep the same value
519 * across save/restore and migration.
520 *
521 * For 's' and 'x' the configuration is overwritten with the value applied.
522 */
523 int xc_cpuid_set(
524 int xc, domid_t domid, const unsigned int *input,
525 const char **config, char **config_transformed)
526 {
527 int rc;
528 unsigned int i, j, regs[4], polregs[4];
530 memset(config_transformed, 0, 4 * sizeof(*config_transformed));
532 cpuid(input, regs);
534 memcpy(polregs, regs, sizeof(regs));
535 xc_cpuid_policy(xc, domid, input, polregs);
537 for ( i = 0; i < 4; i++ )
538 {
539 if ( config[i] == NULL )
540 {
541 regs[i] = polregs[i];
542 continue;
543 }
545 config_transformed[i] = alloc_str();
547 for ( j = 0; j < 32; j++ )
548 {
549 unsigned char val = !!((regs[i] & (1U << (31 - j))));
550 unsigned char polval = !!((polregs[i] & (1U << (31 - j))));
552 rc = -EINVAL;
553 if ( !strchr("10xks", config[i][j]) )
554 goto fail;
556 if ( config[i][j] == '1' )
557 val = 1;
558 else if ( config[i][j] == '0' )
559 val = 0;
560 else if ( config[i][j] == 'x' )
561 val = polval;
563 if ( val )
564 set_bit(31 - j, regs[i]);
565 else
566 clear_bit(31 - j, regs[i]);
568 config_transformed[i][j] = config[i][j];
569 if ( config[i][j] == 's' )
570 config_transformed[i][j] = '0' + val;
571 }
572 }
574 rc = xc_cpuid_do_domctl(xc, domid, input, regs);
575 if ( rc == 0 )
576 return 0;
578 fail:
579 for ( i = 0; i < 4; i++ )
580 {
581 free(config_transformed[i]);
582 config_transformed[i] = NULL;
583 }
584 return rc;
585 }