Mercurial > illumos > illumos-gate
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 { |