Changeset View
Standalone View
sys/x86/x86/identcpu.c
Show First 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | |||||
static char cpu_model[128]; | static char cpu_model[128]; | ||||
SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD | CTLFLAG_MPSAFE, | SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD | CTLFLAG_MPSAFE, | ||||
cpu_model, 0, "Machine model"); | cpu_model, 0, "Machine model"); | ||||
static int hw_clockrate; | static int hw_clockrate; | ||||
SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, | SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, | ||||
&hw_clockrate, 0, "CPU instruction clock rate"); | &hw_clockrate, 0, "CPU instruction clock rate"); | ||||
u_int hv_base; | |||||
u_int hv_high; | u_int hv_high; | ||||
char hv_vendor[16]; | char hv_vendor[16]; | ||||
SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD | CTLFLAG_MPSAFE, hv_vendor, | SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD | CTLFLAG_MPSAFE, hv_vendor, | ||||
0, "Hypervisor vendor"); | 0, "Hypervisor vendor"); | ||||
static eventhandler_tag tsc_post_tag; | static eventhandler_tag tsc_post_tag; | ||||
static char cpu_brand[48]; | static char cpu_brand[48]; | ||||
▲ Show 20 Lines • Show All 1,087 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
hook_tsc_freq(void *arg __unused) | hook_tsc_freq(void *arg __unused) | ||||
{ | { | ||||
if (tsc_is_invariant) | if (tsc_is_invariant) | ||||
return; | return; | ||||
tsc_post_tag = EVENTHANDLER_REGISTER(cpufreq_post_change, | tsc_post_tag = EVENTHANDLER_REGISTER(cpufreq_post_change, | ||||
tsc_freq_changed, NULL, EVENTHANDLER_PRI_ANY); | tsc_freq_changed, NULL, EVENTHANDLER_PRI_ANY); | ||||
bryanv: You copied this correctly from the if/else below but it appears the existing bhyve cpuid string… | |||||
Not Done Inline Actions@bryanv Do you mean instead to use "bhyve bhyve" we use "bhyvebhyve"? araujo: @bryanv Do you mean instead to use "bhyve bhyve" we use "bhyvebhyve"? | |||||
Not Done Inline ActionsI think would be great to fix that in this patch too and then MFC it to 11 if possible. araujo: I think would be great to fix that in this patch too and then MFC it to 11 if possible. | |||||
} | } | ||||
SYSINIT(hook_tsc_freq, SI_SUB_CONFIGURE, SI_ORDER_ANY, hook_tsc_freq, NULL); | SYSINIT(hook_tsc_freq, SI_SUB_CONFIGURE, SI_ORDER_ANY, hook_tsc_freq, NULL); | ||||
static const char *const vm_bnames[] = { | static const char *const vm_bnames[] = { | ||||
"QEMU", /* QEMU */ | "QEMU", /* QEMU */ | ||||
"Plex86", /* Plex86 */ | "Plex86", /* Plex86 */ | ||||
"Bochs", /* Bochs */ | "Bochs", /* Bochs */ | ||||
"Xen", /* Xen */ | "Xen", /* Xen */ | ||||
"BHYVE", /* bhyve */ | "BHYVE", /* bhyve */ | ||||
"Seabios", /* KVM */ | "Seabios", /* KVM */ | ||||
NULL | NULL | ||||
}; | }; | ||||
static const char *const vm_pnames[] = { | static const char *const vm_pnames[] = { | ||||
"VMware Virtual Platform", /* VMWare VM */ | "VMware Virtual Platform", /* VMWare VM */ | ||||
"Virtual Machine", /* Microsoft VirtualPC */ | "Virtual Machine", /* Microsoft VirtualPC */ | ||||
"VirtualBox", /* Sun xVM VirtualBox */ | "VirtualBox", /* Sun xVM VirtualBox */ | ||||
"Parallels Virtual Platform", /* Parallels VM */ | "Parallels Virtual Platform", /* Parallels VM */ | ||||
"KVM", /* KVM */ | "KVM", /* KVM */ | ||||
NULL | NULL | ||||
}; | }; | ||||
void | static struct { | ||||
identify_hypervisor(void) | 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 | |||||
Not Done Inline ActionsPerhaps add a comment here in the function or as part of the first block comment above the for to note that we are searching for the first hypervisor we recognize. jhb: Perhaps add a comment here in the function or as part of the first block comment above the for… | |||||
Not Done Inline ActionsSure, makes sense, I'll update that. stevek: Sure, makes sense, I'll update that. | |||||
identify_hypervisor_cpuid_base(void) | |||||
{ | { | ||||
u_int regs[4]; | u_int leaf, regs[4]; | ||||
char *p; | |||||
int i; | int i; | ||||
/* | /* | ||||
Not Done Inline ActionsIt looks like this block of comments got copied above so I think this block can be removed. bryanv: It looks like this block of comments got copied above so I think this block can be removed. | |||||
* [RFC] CPUID usage for interaction between Hypervisors and Linux. | * [RFC] CPUID usage for interaction between Hypervisors and Linux. | ||||
* http://lkml.org/lkml/2008/10/1/246 | * http://lkml.org/lkml/2008/10/1/246 | ||||
* | * | ||||
* KB1009458: Mechanisms to determine if software is running in | * KB1009458: Mechanisms to determine if software is running in | ||||
* a VMware virtual machine | * a VMware virtual machine | ||||
* http://kb.vmware.com/kb/1009458 | * 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) { | for (leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) { | ||||
vm_guest = VM_GUEST_VM; | do_cpuid(leaf, regs); | ||||
do_cpuid(0x40000000, regs); | |||||
/* | /* | ||||
* KVM from Linux kernels prior to commit | * KVM from Linux kernels prior to commit | ||||
* 57c22e5f35aa4b9b2fe11f73f3e62bbf9ef36190 set %eax | * 57c22e5f35aa4b9b2fe11f73f3e62bbf9ef36190 set %eax | ||||
* to 0 rather than a valid hv_high value. Check for | * to 0 rather than a valid hv_high value. Check for | ||||
* the KVM signature bytes and fixup %eax to the | * the KVM signature bytes and fixup %eax to the | ||||
* highest supported leaf in that case. | * highest supported leaf in that case. | ||||
*/ | */ | ||||
if (regs[0] == 0 && regs[1] == 0x4b4d564b && | if (regs[0] == 0 && regs[1] == 0x4b4d564b && | ||||
regs[2] == 0x564b4d56 && regs[3] == 0x0000004d) | regs[2] == 0x564b4d56 && regs[3] == 0x0000004d) | ||||
regs[0] = 0x40000001; | regs[0] = leaf + 1; | ||||
Not Done Inline ActionsThis should be 'regs[0] >= leaf' I think. jhb: This should be 'regs[0] >= leaf' I think. | |||||
Not Done Inline ActionsYes, I think you are correct here. I'll change that. stevek: Yes, I think you are correct here. I'll change that. | |||||
if (regs[0] >= 0x40000000) { | 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. | |||||
*/ | |||||
Not Done Inline ActionsI feel like we should always expose this string, not just known strings. Perhaps we should alter the if to: if (vm_guest != VM_GUEST_VM || leaf == 0x40000000) This would always store the first one in hv_vendor[] on the first pass and then only overwrite it if we later find a matching hypervisor. jhb: I feel like we should always expose this string, not just known strings. Perhaps we should… | |||||
Not Done Inline ActionsOkay, I can see that. stevek: Okay, I can see that. | |||||
if (vm_guest != VM_GUEST_VM || leaf == 0x40000000) { | |||||
hv_base = leaf; | |||||
hv_high = regs[0]; | hv_high = regs[0]; | ||||
((u_int *)&hv_vendor)[0] = regs[1]; | ((u_int *)&hv_vendor)[0] = regs[1]; | ||||
((u_int *)&hv_vendor)[1] = regs[2]; | ((u_int *)&hv_vendor)[1] = regs[2]; | ||||
((u_int *)&hv_vendor)[2] = regs[3]; | ((u_int *)&hv_vendor)[2] = regs[3]; | ||||
hv_vendor[12] = '\0'; | hv_vendor[12] = '\0'; | ||||
if (strcmp(hv_vendor, "VMwareVMware") == 0) | |||||
vm_guest = VM_GUEST_VMWARE; | /* | ||||
else if (strcmp(hv_vendor, "Microsoft Hv") == 0) | * If we found a specific hypervisor, then | ||||
vm_guest = VM_GUEST_HV; | * we are finished. | ||||
else if (strcmp(hv_vendor, "KVMKVMKVM") == 0) | */ | ||||
vm_guest = VM_GUEST_KVM; | if (vm_guest != VM_GUEST_VM) | ||||
else if (strcmp(hv_vendor, "bhyve bhyve") == 0) | return; | ||||
vm_guest = VM_GUEST_BHYVE; | |||||
} | } | ||||
} | |||||
} | |||||
} | |||||
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; | return; | ||||
} | } | ||||
/* | /* | ||||
* Examine SMBIOS strings for older hypervisors. | * Examine SMBIOS strings for older hypervisors. | ||||
*/ | */ | ||||
p = kern_getenv("smbios.system.serial"); | p = kern_getenv("smbios.system.serial"); | ||||
if (p != NULL) { | if (p != NULL) { | ||||
▲ Show 20 Lines • Show All 1,160 Lines • Show Last 20 Lines |
You copied this correctly from the if/else below but it appears the existing bhyve cpuid string is incorrect.
It should be "bhyve bhyve " (note the trailing space) https://github.com/freebsd/freebsd/blob/master/sys/amd64/vmm/x86.c#L57.
Adding the space to this diff fixed bhyve detection.
bhyve detection was added in D11090 by @araujo . It is probably easiest to just fix it in this patch, assuming @stevek have plans to MFC this to 11.