aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Pau Monné <royger@FreeBSD.org>2024-01-19 09:15:17 +0000
committerRoger Pau Monné <royger@FreeBSD.org>2024-02-22 10:08:04 +0000
commit6744fd8e75032c893e6a80bced8be3a991fa2901 (patch)
tree49d6878b9836eaf64c4bf34be9a761b98bec9990
parent399386f190f157073baaa56925e92cc90edded8c (diff)
downloadsrc-6744fd8e75032c893e6a80bced8be3a991fa2901.tar.gz
src-6744fd8e75032c893e6a80bced8be3a991fa2901.zip
x86/cpu: improve hypervisor detection
Some hypervisors can expose multiple signatures, for example Xen will expose both the Xen and the HyperV signatures if Viridian extensions are enabled for the guest. Presence of multiple signatures is currently not handled by FreeBSD, that will exit once a known signature is found in cpuid output. Exposing the HyperV signature on hypervisors different than HyperV is not uncommon, this is done so that such hypervisor can expose a (subset) of the Viridian extensions to Windows guests for performance reasons. Likely for compatibility purposes the HyperV signature is always exposed on the first leaf, and the Xen signature is exposed in the secondary leaf. Fix the specific case of HyperV by not exiting from the scan if the HyperV signature is found, and prefer a second signature if one is found. Note that long term we might wish to convert vm_guest into a bitmap, so that it can signal detection of multiple hypervisor interfaces. Fixes: b0165dc4539f ('x86/xen: fix HVM guest hypercall page setup') PR: 276421 Sponsored by: Cloud Software Group Reviewed by: markj kib Differential revision: https://reviews.freebsd.org/D43508
-rw-r--r--sys/x86/x86/identcpu.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index 9c82f9f8a882..df24c5bddffd 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -1385,6 +1385,8 @@ identify_hypervisor_cpuid_base(void)
regs[0] = leaf + 1;
if (regs[0] >= leaf) {
+ enum VM_GUEST prev_vm_guest = vm_guest;
+
for (i = 0; i < nitems(vm_cpuids); i++)
if (strncmp((const char *)&regs[1],
vm_cpuids[i].vm_cpuid, 12) == 0) {
@@ -1397,7 +1399,7 @@ identify_hypervisor_cpuid_base(void)
* specific hypervisor, record the base, high value,
* and vendor identifier.
*/
- if (vm_guest != VM_GUEST_VM || leaf == 0x40000000) {
+ if (vm_guest != prev_vm_guest || leaf == 0x40000000) {
hv_base = leaf;
hv_high = regs[0];
((u_int *)&hv_vendor)[0] = regs[1];
@@ -1409,7 +1411,18 @@ identify_hypervisor_cpuid_base(void)
* If we found a specific hypervisor, then
* we are finished.
*/
- if (vm_guest != VM_GUEST_VM)
+ if (vm_guest != VM_GUEST_VM &&
+ /*
+ * Xen and other hypervisors can expose the
+ * HyperV signature in addition to the
+ * native one in order to support Viridian
+ * extensions for Windows guests.
+ *
+ * Do the full cpuid scan if HyperV is
+ * detected, as the native hypervisor is
+ * preferred.
+ */
+ vm_guest != VM_GUEST_HV)
return;
}
}