summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen J. Kiernan <stevek@FreeBSD.org>2019-05-17 17:21:32 +0000
committerStephen J. Kiernan <stevek@FreeBSD.org>2019-05-17 17:21:32 +0000
commit949f834a614e76695719bc7ca9209a5cb7601f3c (patch)
treed9d0f595c23d6d9d43e817514a4da14eb65e4731
parent8f7f38457f940798c149ae40b73e0d20672812de (diff)
Notes
-rw-r--r--sys/kern/subr_param.c1
-rw-r--r--sys/sys/systm.h3
-rw-r--r--sys/x86/include/x86_var.h1
-rw-r--r--sys/x86/x86/identcpu.c88
4 files changed, 70 insertions, 23 deletions
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
index d8f390bbd5a8..6cb8e5d48d2b 100644
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -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);
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 24413cf32be0..01300e5e8f3c 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -78,7 +78,8 @@ extern int vm_guest; /* Running as virtual machine guest? */
* 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
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
index 1a1c4d271b60..2028d73998ca 100644
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -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[];
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index 867c061d3c7d..9f3fe1e8cfde 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -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;
}