Skip to content

Commit d52734d

Browse files
maciejsszmigierobonzini
authored andcommitted
KVM: x86: Give a hint when Win2016 might fail to boot due to XSAVES erratum
Since commit b056346 ("x86/CPU/AMD: Disable XSAVES on AMD family 0x17") kernel unconditionally clears the XSAVES CPU feature bit on Zen1/2 CPUs. Because KVM CPU caps are initialized from the kernel boot CPU features this makes the XSAVES feature also unavailable for KVM guests in this case. At the same time the XSAVEC feature is left enabled. Unfortunately, having XSAVEC but no XSAVES in CPUID breaks Hyper-V enabled Windows Server 2016 VMs that have more than one vCPU. Let's at least give users hint in the kernel log what could be wrong since these VMs currently simply hang at boot with a black screen - giving no clue what suddenly broke them and how to make them work again. Trigger the kernel message hint based on the particular guest ID written to the Guest OS Identity Hyper-V MSR implemented by KVM. Defer this check to when the L1 Hyper-V hypervisor enables SVM in EFER since we want to limit this message to Hyper-V enabled Windows guests only (Windows session running nested as L2) but the actual Guest OS Identity MSR write is done by L1 and happens before it enables SVM. Fixes: b056346 ("x86/CPU/AMD: Disable XSAVES on AMD family 0x17") Signed-off-by: Maciej S. Szmigiero <[email protected]> Message-Id: <b83ab45c5e239e5d148b0ae7750133a67ac9575c.1706127425.git.maciej.szmigiero@oracle.com> [Move some checks before mutex_lock(), rename function. - Paolo] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 9e05d9b commit d52734d

File tree

4 files changed

+59
-0
lines changed

4 files changed

+59
-0
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,8 @@ struct kvm_hv {
11451145
unsigned int synic_auto_eoi_used;
11461146

11471147
struct kvm_hv_syndbg hv_syndbg;
1148+
1149+
bool xsaves_xsavec_checked;
11481150
};
11491151
#endif
11501152

arch/x86/kvm/hyperv.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,56 @@ static bool hv_check_msr_access(struct kvm_vcpu_hv *hv_vcpu, u32 msr)
13221322
return false;
13231323
}
13241324

1325+
#define KVM_HV_WIN2016_GUEST_ID 0x1040a00003839
1326+
#define KVM_HV_WIN2016_GUEST_ID_MASK (~GENMASK_ULL(23, 16)) /* mask out the service version */
1327+
1328+
/*
1329+
* Hyper-V enabled Windows Server 2016 SMP VMs fail to boot in !XSAVES && XSAVEC
1330+
* configuration.
1331+
* Such configuration can result from, for example, AMD Erratum 1386 workaround.
1332+
*
1333+
* Print a notice so users aren't left wondering what's suddenly gone wrong.
1334+
*/
1335+
static void __kvm_hv_xsaves_xsavec_maybe_warn(struct kvm_vcpu *vcpu)
1336+
{
1337+
struct kvm *kvm = vcpu->kvm;
1338+
struct kvm_hv *hv = to_kvm_hv(kvm);
1339+
1340+
/* Check again under the hv_lock. */
1341+
if (hv->xsaves_xsavec_checked)
1342+
return;
1343+
1344+
if ((hv->hv_guest_os_id & KVM_HV_WIN2016_GUEST_ID_MASK) !=
1345+
KVM_HV_WIN2016_GUEST_ID)
1346+
return;
1347+
1348+
hv->xsaves_xsavec_checked = true;
1349+
1350+
/* UP configurations aren't affected */
1351+
if (atomic_read(&kvm->online_vcpus) < 2)
1352+
return;
1353+
1354+
if (guest_cpuid_has(vcpu, X86_FEATURE_XSAVES) ||
1355+
!guest_cpuid_has(vcpu, X86_FEATURE_XSAVEC))
1356+
return;
1357+
1358+
pr_notice_ratelimited("Booting SMP Windows KVM VM with !XSAVES && XSAVEC. "
1359+
"If it fails to boot try disabling XSAVEC in the VM config.\n");
1360+
}
1361+
1362+
void kvm_hv_xsaves_xsavec_maybe_warn(struct kvm_vcpu *vcpu)
1363+
{
1364+
struct kvm_hv *hv = to_kvm_hv(vcpu->kvm);
1365+
1366+
if (!vcpu->arch.hyperv_enabled ||
1367+
hv->xsaves_xsavec_checked)
1368+
return;
1369+
1370+
mutex_lock(&hv->hv_lock);
1371+
__kvm_hv_xsaves_xsavec_maybe_warn(vcpu);
1372+
mutex_unlock(&hv->hv_lock);
1373+
}
1374+
13251375
static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
13261376
bool host)
13271377
{

arch/x86/kvm/hyperv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
182182
struct pvclock_vcpu_time_info *hv_clock);
183183
void kvm_hv_request_tsc_page_update(struct kvm *kvm);
184184

185+
void kvm_hv_xsaves_xsavec_maybe_warn(struct kvm_vcpu *vcpu);
186+
185187
void kvm_hv_init_vm(struct kvm *kvm);
186188
void kvm_hv_destroy_vm(struct kvm *kvm);
187189
int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu);
@@ -267,6 +269,7 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
267269
static inline void kvm_hv_setup_tsc_page(struct kvm *kvm,
268270
struct pvclock_vcpu_time_info *hv_clock) {}
269271
static inline void kvm_hv_request_tsc_page_update(struct kvm *kvm) {}
272+
static inline void kvm_hv_xsaves_xsavec_maybe_warn(struct kvm_vcpu *vcpu) {}
270273
static inline void kvm_hv_init_vm(struct kvm *kvm) {}
271274
static inline void kvm_hv_destroy_vm(struct kvm *kvm) {}
272275
static inline int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)

arch/x86/kvm/x86.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,10 @@ static int set_efer(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
17821782
if ((efer ^ old_efer) & KVM_MMU_EFER_ROLE_BITS)
17831783
kvm_mmu_reset_context(vcpu);
17841784

1785+
if (!static_cpu_has(X86_FEATURE_XSAVES) &&
1786+
(efer & EFER_SVME))
1787+
kvm_hv_xsaves_xsavec_maybe_warn(vcpu);
1788+
17851789
return 0;
17861790
}
17871791

0 commit comments

Comments
 (0)