svn commit: r276456 - in projects/paravirt/sys/x86: include x86
Bryan Venteicher
bryanv at FreeBSD.org
Wed Dec 31 07:03:10 UTC 2014
Author: bryanv
Date: Wed Dec 31 07:03:07 2014
New Revision: 276456
URL: https://svnweb.freebsd.org/changeset/base/276456
Log:
Rework hypervisor detection
To be more like the existing Xen code, detect the supported hypervisors
from the SI_SUB_HYPERVISOR sysinit instead from identcpu(). I do prefer
the later method, but preserve the status quo for now.
Hook in the KVM callback when a CPU is stopped and misc cleanup elsewhere.
Modified:
projects/paravirt/sys/x86/include/hypervisor.h
projects/paravirt/sys/x86/include/kvm.h
projects/paravirt/sys/x86/x86/bhyve.c
projects/paravirt/sys/x86/x86/hypervisor.c
projects/paravirt/sys/x86/x86/identcpu.c
projects/paravirt/sys/x86/x86/kvm.c
projects/paravirt/sys/x86/x86/kvm_clock.c
projects/paravirt/sys/x86/x86/vmware.c
Modified: projects/paravirt/sys/x86/include/hypervisor.h
==============================================================================
--- projects/paravirt/sys/x86/include/hypervisor.h Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/include/hypervisor.h Wed Dec 31 07:03:07 2014 (r276456)
@@ -29,18 +29,30 @@
#ifndef _X86_HYPERVISOR_H_
#define _X86_HYPERVISOR_H_
-typedef int hypervisor_info_identify_t(void);
+#include <sys/param.h>
+#include <sys/kernel.h>
-struct hypervisor_info {
- const char *hvi_name;
- const char *hvi_signature;
- enum VM_GUEST hvi_type;
- hypervisor_info_identify_t *hvi_identify;
+typedef void hypervisor_init_func_t(void);
+typedef void hypervisor_op_cpu_stop_t(int);
+
+/*
+ * The guest hypervisor support may provide paravirtualized or have special
+ * requirements for various operations. The callback functions are provided
+ * when a hypervisor is detected and registered.
+ */
+struct hypervisor_ops {
+ hypervisor_op_cpu_stop_t *hvo_cpu_stop;
};
-void hypervisor_cpuid_identify(void);
+void hypervisor_sysinit(void *func);
+void hypervisor_register(const char *vendor, enum VM_GUEST guest,
+ struct hypervisor_ops *ops);
int hypervisor_cpuid_base(const char *signature, int leaves,
uint32_t *base, uint32_t *high);
void hypervisor_print_info(void);
+#define HYPERVISOR_SYSINIT(name, func) \
+ SYSINIT(name ## _hypervisor_sysinit, SI_SUB_HYPERVISOR, \
+ SI_ORDER_FIRST, hypervisor_sysinit, func)
+
#endif /* !_X86_HYPERVISOR_H_ */
Modified: projects/paravirt/sys/x86/include/kvm.h
==============================================================================
--- projects/paravirt/sys/x86/include/kvm.h Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/include/kvm.h Wed Dec 31 07:03:07 2014 (r276456)
@@ -43,6 +43,8 @@
int kvm_paravirt_supported(void);
uint32_t kvm_get_features(void);
+
+void kvm_clock_cpu_stop(int restart);
uint64_t kvm_clock_tsc_freq(void);
#endif /* !_X86_KVM_H_ */
Modified: projects/paravirt/sys/x86/x86/bhyve.c
==============================================================================
--- projects/paravirt/sys/x86/x86/bhyve.c Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/x86/bhyve.c Wed Dec 31 07:03:07 2014 (r276456)
@@ -32,33 +32,27 @@ __FBSDID("$FreeBSD$");
#include <x86/hypervisor.h>
-static int bhyve_identify(void);
-
-const struct hypervisor_info bhyve_hypervisor_info = {
- .hvi_name = "bhyve",
- .hvi_signature = "bhyve bhyve",
- .hvi_type = VM_GUEST_BHYVE,
- .hvi_identify = bhyve_identify,
-};
-
static uint32_t bhyve_cpuid_base = -1;
static uint32_t bhyve_cpuid_high = -1;
-static uint32_t
+static int
bhyve_cpuid_identify(void)
{
if (bhyve_cpuid_base == -1) {
- hypervisor_cpuid_base(bhyve_hypervisor_info.hvi_signature,
- 0, &bhyve_cpuid_base, &bhyve_cpuid_high);
+ hypervisor_cpuid_base("bhyve bhyve", 0, &bhyve_cpuid_base,
+ &bhyve_cpuid_high);
}
- return (bhyve_cpuid_base);
+ return (bhyve_cpuid_base > 0);
}
-static int
-bhyve_identify(void)
+static void
+bhyve_init(void)
{
- return (bhyve_cpuid_identify() != 0);
+ if (bhyve_cpuid_identify() != 0)
+ hypervisor_register("bhyve", VM_GUEST_BHYVE, NULL);
}
+
+HYPERVISOR_SYSINIT(bhyve, bhyve_init);
Modified: projects/paravirt/sys/x86/x86/hypervisor.c
==============================================================================
--- projects/paravirt/sys/x86/x86/hypervisor.c Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/x86/hypervisor.c Wed Dec 31 07:03:07 2014 (r276456)
@@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
#include <x86/hypervisor.h>
@@ -40,17 +42,41 @@ char hv_vendor[16];
SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD, hv_vendor, 0,
"Hypervisor vendor");
-extern const struct hypervisor_info bhyve_hypervisor_info;
-extern const struct hypervisor_info kvm_hypervisor_info;
-extern const struct hypervisor_info vmware_hypervisor_info;
-
-static const struct hypervisor_info *hypervisor_infos[] = {
- &bhyve_hypervisor_info,
- &kvm_hypervisor_info,
- &vmware_hypervisor_info,
-};
+void
+hypervisor_sysinit(void *func)
+{
+ hypervisor_init_func_t *init;
+
+ init = func;
+
+ /*
+ * Call the init function if we have not already identified the
+ * hypervisor yet. We assume the hypervisor will announce its
+ * presence via the CPUID bit.
+ */
+ if (vm_guest == VM_GUEST_VM && cpu_feature2 & CPUID2_HV)
+ (*init)();
+}
+
+static void
+hypervisor_register_cpu_ops(struct hypervisor_ops *ops)
+{
+
+ if (ops->hvo_cpu_stop != NULL)
+ cpu_ops.cpu_stop = ops->hvo_cpu_stop;
+}
+
+void
+hypervisor_register(const char *vendor, enum VM_GUEST guest,
+ struct hypervisor_ops *ops)
+{
-static const struct hypervisor_info *hv_info;
+ strlcpy(hv_vendor, vendor, sizeof(hv_vendor));
+ vm_guest = guest;
+
+ if (ops != NULL)
+ hypervisor_register_cpu_ops(ops);
+}
/*
* [RFC] CPUID usage for interaction between Hypervisors and Linux.
@@ -76,28 +102,6 @@ hypervisor_cpuid_base(const char *signat
}
void
-hypervisor_cpuid_identify(void)
-{
- const struct hypervisor_info *hvi;
- int i;
-
- for (i = 0; i < nitems(hypervisor_infos); i++) {
- hvi = hypervisor_infos[i];
-
- if (hvi->hvi_identify() != 0) {
- hv_info = hvi;
- break;
- }
- }
-
- if (hv_info != NULL) {
- vm_guest = hvi->hvi_type;
- strlcpy(hv_vendor, hvi->hvi_name, sizeof(hv_vendor));
- } else
- vm_guest = VM_GUEST_VM;
-}
-
-void
hypervisor_print_info(void)
{
Modified: projects/paravirt/sys/x86/x86/identcpu.c
==============================================================================
--- projects/paravirt/sys/x86/x86/identcpu.c Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/x86/identcpu.c Wed Dec 31 07:03:07 2014 (r276456)
@@ -1213,11 +1213,12 @@ identify_hypervisor(void)
int i;
/*
- * Modern hypervisors set the HV present feature bit, and are then
- * identifiable through a special CPUID leaf.
+ * Modern hypervisors set the HV present feature bit and are then
+ * identifiable through a special CPUID leaf. Hypervisors we know
+ * about are later detected via the SI_SUB_HYPERVISOR SYSINIT().
*/
if (cpu_feature2 & CPUID2_HV) {
- hypervisor_cpuid_identify();
+ vm_guest = VM_GUEST_VM;
return;
}
Modified: projects/paravirt/sys/x86/x86/kvm.c
==============================================================================
--- projects/paravirt/sys/x86/x86/kvm.c Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/x86/kvm.c Wed Dec 31 07:03:07 2014 (r276456)
@@ -30,46 +30,45 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <machine/cpufunc.h>
+
#include <x86/hypervisor.h>
#include <x86/kvm.h>
-static int kvm_identify(void);
-static uint32_t kvm_cpuid_identify(void);
+static int kvm_cpuid_identify(void);
+static void kvm_cpu_stop(int);
-const struct hypervisor_info kvm_hypervisor_info = {
- .hvi_name = "KVM",
- .hvi_signature = "KVMKVMKVM\0\0",
- .hvi_type = VM_GUEST_KVM,
- .hvi_identify = kvm_identify,
+static struct hypervisor_ops kvm_ops = {
+ .hvo_cpu_stop = kvm_cpu_stop,
};
static uint32_t kvm_cpuid_base = -1;
static uint32_t kvm_cpuid_high = -1;
-static uint32_t
+static int
kvm_cpuid_identify(void)
{
if (kvm_cpuid_base == -1) {
- hypervisor_cpuid_base(kvm_hypervisor_info.hvi_signature,
- 0, &kvm_cpuid_base, &kvm_cpuid_high);
+ hypervisor_cpuid_base("KVMKVMKVM\0\0", 0, &kvm_cpuid_base,
+ &kvm_cpuid_high);
}
- return (kvm_cpuid_base);
+ return (kvm_cpuid_base > 0);
}
-static int
-kvm_identify(void)
+static void
+kvm_cpu_stop(int restarted)
{
- return (kvm_cpuid_identify() != 0);
+ kvm_clock_cpu_stop(restarted);
}
int
kvm_paravirt_supported(void)
{
- return (kvm_cpuid_base != -1);
+ return (kvm_cpuid_base > 0);
}
uint32_t
@@ -77,7 +76,20 @@ kvm_get_features(void)
{
u_int regs[4];
- do_cpuid(kvm_cpuid_identify() | KVM_CPUID_FEATURES_LEAF, regs);
+ if (kvm_paravirt_supported())
+ do_cpuid(kvm_cpuid_base | KVM_CPUID_FEATURES_LEAF, regs);
+ else
+ regs[0] = 0;
return (regs[0]);
}
+
+static void
+kvm_init(void)
+{
+
+ if (kvm_cpuid_identify() != 0)
+ hypervisor_register("KVM", VM_GUEST_KVM, &kvm_ops);
+}
+
+HYPERVISOR_SYSINIT(kvm, kvm_init);
Modified: projects/paravirt/sys/x86/x86/kvm_clock.c
==============================================================================
--- projects/paravirt/sys/x86/x86/kvm_clock.c Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/x86/kvm_clock.c Wed Dec 31 07:03:07 2014 (r276456)
@@ -55,8 +55,9 @@ static struct timecounter kvm_clock_time
1000,
};
-static uint32_t kvm_clock_wall_clock_msr;
-static uint32_t kvm_clock_system_time_msr;
+static int kvm_clock_registered;
+static uint32_t kvm_clock_wall_clock_msr;
+static uint32_t kvm_clock_system_time_msr;
uint64_t
kvm_clock_tsc_freq(void)
@@ -102,11 +103,23 @@ kvm_clock_pcpu_system_time(void *arg)
wrmsr(kvm_clock_system_time_msr, data);
}
+void
+kvm_clock_cpu_stop(int restarted)
+{
+
+ /*
+ * The per-CPU shared data area must be unregistered when the CPU
+ * is stopped. Otherwise if the guest is rebooted, the host can
+ * continue to write into the shared data area causing corruption.
+ */
+ if (kvm_clock_registered != 0)
+ kvm_clock_pcpu_system_time(&restarted);
+}
+
static void
kvm_clock_init(void)
{
uint32_t features;
- int enable;
if (vm_guest != VM_GUEST_KVM || !kvm_paravirt_supported())
return;
@@ -122,9 +135,9 @@ kvm_clock_init(void)
} else
return;
- enable = 1;
+ kvm_clock_registered = 1;
smp_rendezvous(smp_no_rendevous_barrier, kvm_clock_pcpu_system_time,
- smp_no_rendevous_barrier, &enable);
+ smp_no_rendevous_barrier, &kvm_clock_registered);
tc_init(&kvm_clock_timecounter);
}
Modified: projects/paravirt/sys/x86/x86/vmware.c
==============================================================================
--- projects/paravirt/sys/x86/x86/vmware.c Wed Dec 31 07:00:36 2014 (r276455)
+++ projects/paravirt/sys/x86/x86/vmware.c Wed Dec 31 07:03:07 2014 (r276456)
@@ -34,40 +34,23 @@ __FBSDID("$FreeBSD$");
#include <x86/hypervisor.h>
#include <x86/vmware.h>
-static int vmware_identify(void);
-static uint32_t vmware_cpuid_identify(void);
-
-const struct hypervisor_info vmware_hypervisor_info = {
- .hvi_name = "VMware",
- .hvi_signature = "VMwareVMware",
- .hvi_type = VM_GUEST_VMWARE,
- .hvi_identify = vmware_identify,
-};
-
static uint32_t vmware_cpuid_base = -1;
static uint32_t vmware_cpuid_high = -1;
-static uint32_t
+static int
vmware_cpuid_identify(void)
{
+ /*
+ * KB1009458: Mechanisms to determine if software is running in a
+ * VMware virtual machine: http://kb.vmware.com/kb/1009458
+ */
if (vmware_cpuid_base == -1) {
- hypervisor_cpuid_base(vmware_hypervisor_info.hvi_signature,
- 0, &vmware_cpuid_base, &vmware_cpuid_high);
+ hypervisor_cpuid_base("VMwareVMware", 0, &vmware_cpuid_base,
+ &vmware_cpuid_high);
}
- return (vmware_cpuid_base);
-}
-
-/*
- * KB1009458: Mechanisms to determine if software is running in a VMware
- * virtual machine: http://kb.vmware.com/kb/1009458
- */
-static int
-vmware_identify(void)
-{
-
- return (vmware_cpuid_identify() != 0);
+ return (vmware_cpuid_base > 0);
}
uint64_t
@@ -89,3 +72,13 @@ vmware_tsc_freq(void)
return (freq);
}
+
+static void
+vmware_init(void)
+{
+
+ if (vmware_cpuid_identify() != 0)
+ hypervisor_register("VMware", VM_GUEST_VMWARE, NULL);
+}
+
+HYPERVISOR_SYSINIT(vmware, vmware_init);
More information about the svn-src-projects
mailing list