检查 CPU 获取系统虚拟化信息 (Hypervisor)

好风 发表于 2016-12-23T06:04:36.145639Z
引用地址:https://plus.ooclab.com/note/article/1327

如果我们想要知道当前系统由哪种虚拟化实现。可以通过 cpuid 获取。

golang + C 版本如下:

package main

// +build 386 amd64

/*
#include <string.h>

#if defined(__x86_64__) || defined(__i386__)

enum {
    HYPER_NONE  = 0,
    HYPER_XEN,
    HYPER_KVM,
    HYPER_MSHV,
    HYPER_VMWARE,
    HYPER_IBM,      // sys-z powervm
    HYPER_VSERVER,
    HYPER_UML,
    HYPER_INNOTEK,      // VBOX
    HYPER_HITACHI,
    HYPER_PARALLELS,    // OpenVZ/VIrtuozzo
    HYPER_VBOX,
    HYPER_OS400,
    HYPER_PHYP,
    HYPER_SPAR,
};

//
// This CPUID leaf returns the information about the hypervisor.
// EAX : maximum input value for CPUID supported by the hypervisor.
// EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
//
#define HYPERVISOR_INFO_LEAF   0x40000000

static inline void
cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
             unsigned int *ecx, unsigned int *edx)
{
    __asm__(
#if defined(__PIC__) && defined(__i386__)
        // x86 PIC cannot clobber ebx -- gcc bitches
        "xchg %%ebx, %%esi;"
        "cpuid;"
        "xchg %%esi, %%ebx;"
        : "=S" (*ebx),
#else
        "cpuid;"
        : "=b" (*ebx),
#endif
          "=a" (*eax),
          "=c" (*ecx),
          "=d" (*edx)
        : "1" (op), "c"(0));
}

static unsigned int
read_hypervisor_cpuid()
{
    unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
    char hyper_vendor_id[13];

    memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));

    cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
    memcpy(hyper_vendor_id + 0, &ebx, 4);
    memcpy(hyper_vendor_id + 4, &ecx, 4);
    memcpy(hyper_vendor_id + 8, &edx, 4);
    hyper_vendor_id[12] = '\0';

    if (!hyper_vendor_id[0])
        return 0;

    if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
//        *hv = HYPER_XEN;
return HYPER_XEN;
    else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
//        *hv = HYPER_KVM;
return HYPER_KVM;
    else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
//        *hv = HYPER_MSHV;
return HYPER_MSHV;
    else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
//        *hv = HYPER_VMWARE;
return HYPER_VMWARE;
    else if (!strncmp("UnisysSpar64", hyper_vendor_id, 12))
//        *hv = HYPER_SPAR;
return HYPER_SPAR;
return HYPER_NONE;
}

#else // ! (__x86_64__ || __i386__)
static void
read_hypervisor_cpuid()
{
}
#endif
*/
import "C"

func Hypervisor() string {
    code := C.read_hypervisor_cpuid()
    switch code {
    case 0:
        return "None"
    case 1:
        return "Xen"
    case 2:
        return "KVM"
    case 3:
        return "Microsoft Hv"
    case 4:
        return "VMware"
    case 5:
        return "UnisysSpar64"
    default:
        return "N/A"
    }
}

func main() {
    println(Hypervisor())
}