From 1177d38ce1d34d8cf23c6fd1b4320467771d2ee0 Mon Sep 17 00:00:00 2001 From: "Stephen J. Kiernan" Date: Tue, 21 May 2019 13:29:53 +0000 Subject: [PATCH] The older detection methods (smbios.bios.vendor and smbios.system.product) are able to determine some virtual machines, but the vm_guest variable was still only being set to VM_GUEST_VM. Since we do know what some of them specifically are, we can set vm_guest appropriately. Also, if we see the CPUID has the HV flag, but we were unable to find a definitive vendor in the Hypervisor CPUID Information Leaf, fall back to the older detection methods, as they may be able to determine a specific HV type. Add VM_GUEST_PARALLELS value to VM_GUEST for Parallels. Approved by: cem Differential Revision: https://reviews.freebsd.org/D20305 --- sys/kern/subr_param.c | 19 ++++++------ sys/sys/systm.h | 2 +- sys/x86/x86/identcpu.c | 65 ++++++++++++++++++++++++++---------------- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c index 6cb8e5d48d2b..92d1066da383 100644 --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -146,15 +146,16 @@ SYSCTL_PROC(_kern, OID_AUTO, vm_guest, CTLFLAG_RD | CTLTYPE_STRING, * corresponding enum VM_GUEST members. */ static const char *const vm_guest_sysctl_names[] = { - "none", - "generic", - "xen", - "hv", - "vmware", - "kvm", - "bhyve", - "vbox", - NULL + [VM_GUEST_NO] = "none", + [VM_GUEST_VM] = "generic", + [VM_GUEST_XEN] = "xen", + [VM_GUEST_HV] = "hv", + [VM_GUEST_VMWARE] = "vmware", + [VM_GUEST_KVM] = "kvm", + [VM_GUEST_BHYVE] = "bhyve", + [VM_GUEST_VBOX] = "vbox", + [VM_GUEST_PARALLELS] = "parallels", + [VM_LAST] = NULL }; CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST); diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 01300e5e8f3c..097b5af9a8eb 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -79,7 +79,7 @@ extern int vm_guest; /* Running as virtual machine guest? */ */ 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_GUEST_VBOX, - VM_LAST }; + VM_GUEST_PARALLELS, VM_LAST }; /* * These functions need to be declared before the KASSERT macro is invoked in diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c index c01d2e58b600..822db9d10e2d 100644 --- a/sys/x86/x86/identcpu.c +++ b/sys/x86/x86/identcpu.c @@ -1305,23 +1305,27 @@ hook_tsc_freq(void *arg __unused) SYSINIT(hook_tsc_freq, SI_SUB_CONFIGURE, SI_ORDER_ANY, hook_tsc_freq, NULL); -static const char *const vm_bnames[] = { - "QEMU", /* QEMU */ - "Plex86", /* Plex86 */ - "Bochs", /* Bochs */ - "Xen", /* Xen */ - "BHYVE", /* bhyve */ - "Seabios", /* KVM */ - NULL +static const struct { + const char * vm_bname; + int vm_guest; +} vm_bnames[] = { + { "QEMU", VM_GUEST_VM }, /* QEMU */ + { "Plex86", VM_GUEST_VM }, /* Plex86 */ + { "Bochs", VM_GUEST_VM }, /* Bochs */ + { "Xen", VM_GUEST_XEN }, /* Xen */ + { "BHYVE", VM_GUEST_BHYVE }, /* bhyve */ + { "Seabios", VM_GUEST_KVM }, /* KVM */ }; -static const char *const vm_pnames[] = { - "VMware Virtual Platform", /* VMWare VM */ - "Virtual Machine", /* Microsoft VirtualPC */ - "VirtualBox", /* Sun xVM VirtualBox */ - "Parallels Virtual Platform", /* Parallels VM */ - "KVM", /* KVM */ - NULL +static const struct { + const char * vm_pname; + int vm_guest; +} vm_pnames[] = { + { "VMware Virtual Platform", VM_GUEST_VMWARE }, + { "Virtual Machine", VM_GUEST_VM }, /* Microsoft VirtualPC */ + { "VirtualBox", VM_GUEST_VBOX }, + { "Parallels Virtual Platform", VM_GUEST_PARALLELS }, + { "KVM", VM_GUEST_KVM }, }; static struct { @@ -1413,7 +1417,10 @@ identify_hypervisor(void) if (cpu_feature2 & CPUID2_HV) { vm_guest = VM_GUEST_VM; identify_hypervisor_cpuid_base(); - return; + + /* If we have a definitive vendor, we can return now. */ + if (*hv_vendor != '\0') + return; } /* @@ -1438,19 +1445,27 @@ identify_hypervisor(void) */ p = kern_getenv("smbios.bios.vendor"); if (p != NULL) { - for (i = 0; vm_bnames[i] != NULL; i++) - if (strcmp(p, vm_bnames[i]) == 0) { - vm_guest = VM_GUEST_VM; - freeenv(p); - return; + for (i = 0; i < nitems(vm_bnames); i++) + if (strcmp(p, vm_bnames[i].vm_bname) == 0) { + vm_guest = vm_bnames[i].vm_guest; + /* If we have a specific match, return */ + if (vm_guest != VM_GUEST_VM) { + freeenv(p); + return; + } + /* + * We are done with bnames, but there might be + * a more specific match in the pnames + */ + break; } freeenv(p); } p = kern_getenv("smbios.system.product"); if (p != NULL) { - for (i = 0; vm_pnames[i] != NULL; i++) - if (strcmp(p, vm_pnames[i]) == 0) { - vm_guest = VM_GUEST_VM; + for (i = 0; i < nitems(vm_pnames); i++) + if (strcmp(p, vm_pnames[i].vm_pname) == 0) { + vm_guest = vm_pnames[i].vm_guest; freeenv(p); return; } @@ -2586,7 +2601,7 @@ static void print_hypervisor_info(void) { - if (*hv_vendor) + if (*hv_vendor != '\0') printf("Hypervisor: Origin = \"%s\"\n", hv_vendor); }