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
This commit is contained in:
parent
846a64221b
commit
dd31a8ef39
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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[];
|
||||
|
@ -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 *)®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_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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user