Index: sys/kern/subr_param.c =================================================================== --- sys/kern/subr_param.c +++ sys/kern/subr_param.c @@ -152,6 +152,7 @@ "vmware", "kvm", "bhyve", + "vbox", NULL }; CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST); Index: sys/sys/systm.h =================================================================== --- sys/sys/systm.h +++ sys/sys/systm.h @@ -78,7 +78,8 @@ * Keep in sync with vm_guest_sysctl_names[]. */ enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN, VM_GUEST_HV, - VM_GUEST_VMWARE, VM_GUEST_KVM, VM_GUEST_BHYVE, VM_LAST }; + VM_GUEST_VMWARE, VM_GUEST_KVM, VM_GUEST_BHYVE, VM_GUEST_VBOX, + VM_LAST }; /* * These functions need to be declared before the KASSERT macro is invoked in Index: sys/x86/include/x86_var.h =================================================================== --- sys/x86/include/x86_var.h +++ sys/x86/include/x86_var.h @@ -68,6 +68,7 @@ extern u_int cpu_mon_max_size; extern u_int cpu_maxphyaddr; extern char ctx_switch_xsave[]; +extern u_int hv_base; extern u_int hv_high; extern char hv_vendor[]; extern char kstack[]; Index: sys/x86/x86/identcpu.c =================================================================== --- sys/x86/x86/identcpu.c +++ sys/x86/x86/identcpu.c @@ -161,6 +161,7 @@ SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, &hw_clockrate, 0, "CPU instruction clock rate"); +u_int hv_base; u_int hv_high; char hv_vendor[16]; SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD | CTLFLAG_MPSAFE, hv_vendor, @@ -1288,11 +1289,22 @@ NULL }; -void -identify_hypervisor(void) +static struct { + const char *vm_cpuid; + int vm_guest; +} vm_cpuids[] = { + { "XENXENXEN", VM_GUEST_XEN }, /* XEN */ + { "Microsoft Hv", VM_GUEST_HV }, /* Microsoft Hyper-V */ + { "VMwareVMware", VM_GUEST_VMWARE }, /* VMware VM */ + { "KVMKVMKVM", VM_GUEST_KVM }, /* KVM */ + { "bhyve bhyve ", VM_GUEST_BHYVE }, /* bhyve */ + { "VBoxVBoxVBox", VM_GUEST_VBOX }, /* VirtualBox */ +}; + +static void +identify_hypervisor_cpuid_base(void) { - u_int regs[4]; - char *p; + u_int leaf, regs[4]; int i; /* @@ -1302,10 +1314,13 @@ * KB1009458: Mechanisms to determine if software is running in * a VMware virtual machine * http://kb.vmware.com/kb/1009458 + * + * Search for a hypervisor that we recognize. If we cannot find + * a specific hypervisor, return the first information about the + * hypervisor that we found, as others may be able to use. */ - if (cpu_feature2 & CPUID2_HV) { - vm_guest = VM_GUEST_VM; - do_cpuid(0x40000000, regs); + for (leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) { + do_cpuid(leaf, regs); /* * KVM from Linux kernels prior to commit @@ -1316,23 +1331,53 @@ */ if (regs[0] == 0 && regs[1] == 0x4b4d564b && regs[2] == 0x564b4d56 && regs[3] == 0x0000004d) - regs[0] = 0x40000001; - - if (regs[0] >= 0x40000000) { - hv_high = regs[0]; - ((u_int *)&hv_vendor)[0] = regs[1]; - ((u_int *)&hv_vendor)[1] = regs[2]; - ((u_int *)&hv_vendor)[2] = regs[3]; - hv_vendor[12] = '\0'; - if (strcmp(hv_vendor, "VMwareVMware") == 0) - vm_guest = VM_GUEST_VMWARE; - else if (strcmp(hv_vendor, "Microsoft Hv") == 0) - vm_guest = VM_GUEST_HV; - else if (strcmp(hv_vendor, "KVMKVMKVM") == 0) - vm_guest = VM_GUEST_KVM; - else if (strcmp(hv_vendor, "bhyve bhyve") == 0) - vm_guest = VM_GUEST_BHYVE; + regs[0] = leaf + 1; + + if (regs[0] >= leaf) { + for (i = 0; i < nitems(vm_cpuids); i++) + if (strncmp((const char *)®s[1], + vm_cpuids[i].vm_cpuid, 12) == 0) { + vm_guest = vm_cpuids[i].vm_guest; + break; + } + + /* + * If this is the first entry or we found a + * specific hypervisor, record the base, high value, + * and vendor identifier. + */ + if (vm_guest != VM_GUEST_VM || leaf == 0x40000000) { + hv_base = leaf; + hv_high = regs[0]; + ((u_int *)&hv_vendor)[0] = regs[1]; + ((u_int *)&hv_vendor)[1] = regs[2]; + ((u_int *)&hv_vendor)[2] = regs[3]; + hv_vendor[12] = '\0'; + + /* + * If we found a specific hypervisor, then + * we are finished. + */ + if (vm_guest != VM_GUEST_VM) + return; + } } + } +} + +void +identify_hypervisor(void) +{ + u_int regs[4]; + char *p; + int i; + + /* + * If CPUID2_HV is set, we are running in a hypervisor environment. + */ + if (cpu_feature2 & CPUID2_HV) { + vm_guest = VM_GUEST_VM; + identify_hypervisor_cpuid_base(); return; }