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: b0165dc453 ('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
This commit is contained in:
Roger Pau Monné 2024-01-19 10:15:17 +01:00
parent 399386f190
commit 6744fd8e75

View file

@ -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;
}
}