Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 May 2019 17:21:32 +0000 (UTC)
From:      "Stephen J. Kiernan" <stevek@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r347932 - in head/sys: kern sys x86/include x86/x86
Message-ID:  <201905171721.x4HHLWwk065974@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: stevek
Date: Fri May 17 17:21:32 2019
New Revision: 347932
URL: https://svnweb.freebsd.org/changeset/base/347932

Log:
  Instead of individual conditional statements to look for each hypervisor
  type, use a table to make it easier to add more in the future, if needed.
  
  Add VirtualBox detection to the table ("VBoxVBoxVBox" is the hypervisor
  vendor string to look for.) Also add VM_GUEST_VBOX to the VM_GUEST
  enumeration to indicate VirtualBox.
  
  Save the CPUID base for the hypervisor entry that we detected. Driver code
  may need to know about it in order to obtain additional CPUID features.
  
  Approved by:	bryanv, jhb
  Differential Revision:	https://reviews.freebsd.org/D16305

Modified:
  head/sys/kern/subr_param.c
  head/sys/sys/systm.h
  head/sys/x86/include/x86_var.h
  head/sys/x86/x86/identcpu.c

Modified: head/sys/kern/subr_param.c
==============================================================================
--- head/sys/kern/subr_param.c	Fri May 17 17:11:01 2019	(r347931)
+++ head/sys/kern/subr_param.c	Fri May 17 17:21:32 2019	(r347932)
@@ -153,6 +153,7 @@ static const char *const vm_guest_sysctl_names[] = {
 	"vmware",
 	"kvm",
 	"bhyve",
+	"vbox",
 	NULL
 };
 CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST);

Modified: head/sys/sys/systm.h
==============================================================================
--- head/sys/sys/systm.h	Fri May 17 17:11:01 2019	(r347931)
+++ head/sys/sys/systm.h	Fri May 17 17:21:32 2019	(r347932)
@@ -78,7 +78,8 @@ extern int vm_guest;		/* Running as virtual machine gu
  * 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

Modified: head/sys/x86/include/x86_var.h
==============================================================================
--- head/sys/x86/include/x86_var.h	Fri May 17 17:11:01 2019	(r347931)
+++ head/sys/x86/include/x86_var.h	Fri May 17 17:21:32 2019	(r347932)
@@ -68,6 +68,7 @@ extern	u_int	cpu_mon_min_size;
 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[];

Modified: head/sys/x86/x86/identcpu.c
==============================================================================
--- head/sys/x86/x86/identcpu.c	Fri May 17 17:11:01 2019	(r347931)
+++ head/sys/x86/x86/identcpu.c	Fri May 17 17:21:32 2019	(r347932)
@@ -164,6 +164,7 @@ static int hw_clockrate;
 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,
@@ -1323,11 +1324,22 @@ static const char *const vm_pnames[] = {
 	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;
 
 	/*
@@ -1337,10 +1349,13 @@ identify_hypervisor(void)
 	 * 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
@@ -1351,23 +1366,52 @@ identify_hypervisor(void)
 		 */
 		if (regs[0] == 0 && regs[1] == 0x4b4d564b &&
 		    regs[2] == 0x564b4d56 && regs[3] == 0x0000004d)
-			regs[0] = 0x40000001;
+			regs[0] = leaf + 1;
 			
-		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;
+		if (regs[0] >= leaf) {
+			for (i = 0; i < nitems(vm_cpuids); i++)
+				if (strncmp((const char *)&regs[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_high = leaf;
+				((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;
 	}
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905171721.x4HHLWwk065974>