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,078 Lines • ▼ Show 20 Lines | tsc_freq_changed(void *arg __unused, const struct cf_level *level, int status) | ||||
/* If there was an error during the transition, don't do anything. */ | /* If there was an error during the transition, don't do anything. */ | ||||
if (status != 0) | if (status != 0) | ||||
return; | return; | ||||
/* Total setting for this level gives the new frequency in MHz. */ | /* Total setting for this level gives the new frequency in MHz. */ | ||||
hw_clockrate = level->total_set.freq; | hw_clockrate = level->total_set.freq; | ||||
} | } | ||||
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 */ | |||||
bryanv: You copied this correctly from the if/else below but it appears the existing bhyve cpuid string… | |||||
araujoUnsubmitted 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"? | |||||
araujoUnsubmitted 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. | |||||
{ "VBoxVBoxVBox", VM_GUEST_VBOX }, /* VirtualBox */ | |||||
}; | |||||
static void | static void | ||||
identify_hypervisor_cpuid_base(void) | |||||
{ | |||||
u_int leaf, regs[4]; | |||||
int i; | |||||
/* | |||||
* [RFC] CPUID usage for interaction between Hypervisors and Linux. | |||||
* http://lkml.org/lkml/2008/10/1/246 | |||||
* | |||||
* KB1009458: Mechanisms to determine if software is running in | |||||
* a VMware virtual machine | |||||
* http://kb.vmware.com/kb/1009458 | |||||
*/ | |||||
for (leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) { | |||||
do_cpuid(leaf, regs); | |||||
/* | |||||
* KVM from Linux kernels prior to commit | |||||
* 57c22e5f35aa4b9b2fe11f73f3e62bbf9ef36190 set %eax | |||||
* to 0 rather than a valid hv_high value. Check for | |||||
* the KVM signature bytes and fixup %eax to the | |||||
* highest supported leaf in that case. | |||||
*/ | |||||
if (regs[0] == 0 && regs[1] == 0x4b4d564b && | |||||
regs[2] == 0x564b4d56 && regs[3] == 0x0000004d) | |||||
regs[0] = leaf + 1; | |||||
if (regs[0] >= 0x40000000) { | |||||
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 we found a specific hypervisor, record the | |||||
* base, high value, and vendor identifier. | |||||
*/ | |||||
if (vm_guest != VM_GUEST_VM) { | |||||
hv_base = leaf; | |||||
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'; | |||||
return; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
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); | ||||
Show All 22 Lines | |||||
void | void | ||||
identify_hypervisor(void) | identify_hypervisor(void) | ||||
{ | { | ||||
u_int regs[4]; | u_int regs[4]; | ||||
char *p; | 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. | * If CPUID2_HV is set, we are running in a hypervisor environment. | ||||
* http://lkml.org/lkml/2008/10/1/246 | |||||
* | |||||
* KB1009458: Mechanisms to determine if software is running in | |||||
* a VMware virtual machine | |||||
* http://kb.vmware.com/kb/1009458 | |||||
*/ | */ | ||||
if (cpu_feature2 & CPUID2_HV) { | if (cpu_feature2 & CPUID2_HV) { | ||||
vm_guest = VM_GUEST_VM; | vm_guest = VM_GUEST_VM; | ||||
do_cpuid(0x40000000, regs); | identify_hypervisor_cpuid_base(); | ||||
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. | |||||
/* | |||||
* KVM from Linux kernels prior to commit | |||||
* 57c22e5f35aa4b9b2fe11f73f3e62bbf9ef36190 set %eax | |||||
* to 0 rather than a valid hv_high value. Check for | |||||
* the KVM signature bytes and fixup %eax to the | |||||
* highest supported leaf in that case. | |||||
*/ | |||||
if (regs[0] == 0 && regs[1] == 0x4b4d564b && | |||||
regs[2] == 0x564b4d56 && regs[3] == 0x0000004d) | |||||
regs[0] = 0x40000001; | |||||
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; | |||||
} | |||||
return; | return; | ||||
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. | |||||
} | } | ||||
/* | /* | ||||
* 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) { | ||||
if (strncmp(p, "VMware-", 7) == 0 || strncmp(p, "VMW", 3) == 0) { | if (strncmp(p, "VMware-", 7) == 0 || strncmp(p, "VMW", 3) == 0) { | ||||
vmware_hvcall(VMW_HVCMD_GETVERSION, regs); | vmware_hvcall(VMW_HVCMD_GETVERSION, regs); | ||||
if (regs[1] == VMW_HVMAGIC) { | if (regs[1] == VMW_HVMAGIC) { | ||||
vm_guest = VM_GUEST_VMWARE; | vm_guest = VM_GUEST_VMWARE; | ||||
freeenv(p); | freeenv(p); | ||||
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. | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
freeenv(p); | freeenv(p); | ||||
} | } | ||||
/* | /* | ||||
* XXX: Some of these entries may not be needed since they were | * XXX: Some of these entries may not be needed since they were | ||||
▲ Show 20 Lines • Show All 1,147 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.