comparison usr/src/uts/i86pc/os/cpuid.c @ 14043:0291cd939b43

3506 Use "hypervisor" CPUID bit to detect hypervisor environment Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com> Reviewed by: Albert Lee <trisk@nexenta.com> Approved by: Robert Mustacchi <rm@joyent.com>
author Yuri Pankov <yuri.pankov@nexenta.com>
date Mon, 10 Jun 2013 09:51:40 -0700
parents b151bd260b71
children
comparison
equal deleted inserted replaced
14042:e5bd6d1f1685 14043:0291cd939b43
19 * CDDL HEADER END 19 * CDDL HEADER END
20 */ 20 */
21 /* 21 /*
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011 by Delphix. All rights reserved. 23 * Copyright (c) 2011 by Delphix. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 */ 25 */
25 /* 26 /*
26 * Copyright (c) 2010, Intel Corporation. 27 * Copyright (c) 2010, Intel Corporation.
27 * All rights reserved. 28 * All rights reserved.
28 */ 29 */
218 static size_t xsave_state_size = 0; 219 static size_t xsave_state_size = 0;
219 uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE); 220 uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE);
220 boolean_t xsave_force_disable = B_FALSE; 221 boolean_t xsave_force_disable = B_FALSE;
221 222
222 /* 223 /*
223 * This is set to platform type Solaris is running on. 224 * This is set to platform type we are running on.
224 */ 225 */
225 static int platform_type = -1; 226 static int platform_type = -1;
226 227
227 #if !defined(__xpv) 228 #if !defined(__xpv)
228 /* 229 /*
595 kmem_free(cpi, sizeof (*cpi)); 596 kmem_free(cpi, sizeof (*cpi));
596 cpu->cpu_m.mcpu_cpi = NULL; 597 cpu->cpu_m.mcpu_cpi = NULL;
597 } 598 }
598 599
599 #if !defined(__xpv) 600 #if !defined(__xpv)
600
601 /* 601 /*
602 * Determine the type of the underlying platform. This is used to customize 602 * Determine the type of the underlying platform. This is used to customize
603 * initialization of various subsystems (e.g. TSC). determine_platform() must 603 * initialization of various subsystems (e.g. TSC). determine_platform() must
604 * only ever be called once to prevent two processors from seeing different 604 * only ever be called once to prevent two processors from seeing different
605 * values of platform_type, it must be called before cpuid_pass1(), the 605 * values of platform_type. Must be called before cpuid_pass1(), the earliest
606 * earliest consumer to execute. 606 * consumer to execute (uses _cpuid_chiprev --> synth_amd_info --> get_hwenv).
607 */ 607 */
608 void 608 void
609 determine_platform(void) 609 determine_platform(void)
610 { 610 {
611 struct cpuid_regs cp; 611 struct cpuid_regs cp;
612 char *xen_str; 612 uint32_t base;
613 uint32_t xen_signature[4], base; 613 uint32_t regs[4];
614 char *hvstr = (char *)regs;
614 615
615 ASSERT(platform_type == -1); 616 ASSERT(platform_type == -1);
616 617
617 platform_type = HW_NATIVE; 618 platform_type = HW_NATIVE;
618 619
619 if (!enable_platform_detection) 620 if (!enable_platform_detection)
620 return; 621 return;
621 622
622 /* 623 /*
623 * In a fully virtualized domain, Xen's pseudo-cpuid function 624 * If Hypervisor CPUID bit is set, try to determine hypervisor
624 * returns a string representing the Xen signature in %ebx, %ecx, 625 * vendor signature, and set platform type accordingly.
625 * and %edx. %eax contains the maximum supported cpuid function. 626 *
626 * We need at least a (base + 2) leaf value to do what we want 627 * References:
627 * to do. Try different base values, since the hypervisor might 628 * http://lkml.org/lkml/2008/10/1/246
628 * use a different one depending on whether hyper-v emulation 629 * http://kb.vmware.com/kb/1009458
629 * is switched on by default or not. 630 */
631 cp.cp_eax = 0x1;
632 (void) __cpuid_insn(&cp);
633 if ((cp.cp_ecx & CPUID_INTC_ECX_HV) != 0) {
634 cp.cp_eax = 0x40000000;
635 (void) __cpuid_insn(&cp);
636 regs[0] = cp.cp_ebx;
637 regs[1] = cp.cp_ecx;
638 regs[2] = cp.cp_edx;
639 regs[3] = 0;
640 if (strcmp(hvstr, HVSIG_XEN_HVM) == 0) {
641 platform_type = HW_XEN_HVM;
642 return;
643 }
644 if (strcmp(hvstr, HVSIG_VMWARE) == 0) {
645 platform_type = HW_VMWARE;
646 return;
647 }
648 if (strcmp(hvstr, HVSIG_KVM) == 0) {
649 platform_type = HW_KVM;
650 return;
651 }
652 if (strcmp(hvstr, HVSIG_MICROSOFT) == 0)
653 platform_type = HW_MICROSOFT;
654 } else {
655 /*
656 * Check older VMware hardware versions. VMware hypervisor is
657 * detected by performing an IN operation to VMware hypervisor
658 * port and checking that value returned in %ebx is VMware
659 * hypervisor magic value.
660 *
661 * References: http://kb.vmware.com/kb/1009458
662 */
663 vmware_port(VMWARE_HVCMD_GETVERSION, regs);
664 if (regs[1] == VMWARE_HVMAGIC) {
665 platform_type = HW_VMWARE;
666 return;
667 }
668 }
669
670 /*
671 * Check Xen hypervisor. In a fully virtualized domain,
672 * Xen's pseudo-cpuid function returns a string representing the
673 * Xen signature in %ebx, %ecx, and %edx. %eax contains the maximum
674 * supported cpuid function. We need at least a (base + 2) leaf value
675 * to do what we want to do. Try different base values, since the
676 * hypervisor might use a different one depending on whether Hyper-V
677 * emulation is switched on by default or not.
630 */ 678 */
631 for (base = 0x40000000; base < 0x40010000; base += 0x100) { 679 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
632 cp.cp_eax = base; 680 cp.cp_eax = base;
633 (void) __cpuid_insn(&cp); 681 (void) __cpuid_insn(&cp);
634 xen_signature[0] = cp.cp_ebx; 682 regs[0] = cp.cp_ebx;
635 xen_signature[1] = cp.cp_ecx; 683 regs[1] = cp.cp_ecx;
636 xen_signature[2] = cp.cp_edx; 684 regs[2] = cp.cp_edx;
637 xen_signature[3] = 0; 685 regs[3] = 0;
638 xen_str = (char *)xen_signature; 686 if (strcmp(hvstr, HVSIG_XEN_HVM) == 0 &&
639 if (strcmp("XenVMMXenVMM", xen_str) == 0 &&
640 cp.cp_eax >= (base + 2)) { 687 cp.cp_eax >= (base + 2)) {
641 platform_type = HW_XEN_HVM; 688 platform_type &= ~HW_NATIVE;
689 platform_type |= HW_XEN_HVM;
642 return; 690 return;
643 } 691 }
644 } 692 }
645
646 if (vmware_platform()) /* running under vmware hypervisor? */
647 platform_type = HW_VMWARE;
648 } 693 }
649 694
650 int 695 int
651 get_hwenv(void) 696 get_hwenv(void)
652 { 697 {
2364 * This routine is called just after kernel memory allocation 2409 * This routine is called just after kernel memory allocation
2365 * becomes available on cpu0, and as part of mp_startup() on 2410 * becomes available on cpu0, and as part of mp_startup() on
2366 * the other cpus. 2411 * the other cpus.
2367 * 2412 *
2368 * Fixup the brand string, and collect any information from cpuid 2413 * Fixup the brand string, and collect any information from cpuid
2369 * that requires dynamicically allocated storage to represent. 2414 * that requires dynamically allocated storage to represent.
2370 */ 2415 */
2371 /*ARGSUSED*/ 2416 /*ARGSUSED*/
2372 void 2417 void
2373 cpuid_pass3(cpu_t *cpu) 2418 cpuid_pass3(cpu_t *cpu)
2374 { 2419 {