From 6744fd8e75032c893e6a80bced8be3a991fa2901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Date: Fri, 19 Jan 2024 10:15:17 +0100 Subject: 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 --- sys/x86/x86/identcpu.c | 17 +++++++++++++++-- 1 file 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 *)®s[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; } } -- cgit v1.2.3