On Tue, 2023-12-05 at 17:49 -0600, Michael Roth wrote: > In general, activating long mode involves setting the EFER_LME bit in > the EFER register and then enabling the X86_CR0_PG bit in the CR0 > register. At this point, the EFER_LMA bit will be set automatically by > hardware. > > In the case of SVM/SEV guests where writes to CR0 are intercepted, it's > necessary for the host to set EFER_LMA on behalf of the guest since > hardware does not see the actual CR0 write. Could you explain in which case the writes to CR0 will be still intercepted? It's for CPUs that only support SEV-ES and nothing beyond it? > > In the case of SEV-ES guests where writes to CR0 are trapped instead of > intercepted, the hardware *does* see/record the write to CR0 before > exiting and passing the value on to the host, so as part of enabling > SEV-ES support commit f1c6366e3043 ("KVM: SVM: Add required changes to > support intercepts under SEV-ES") dropped special handling of the > EFER_LMA bit with the understanding that it would be set automatically. > > However, since the guest never explicitly sets the EFER_LMA bit, the > host never becomes aware that it has been set. This becomes problematic > when userspace tries to get/set the EFER values via > KVM_GET_SREGS/KVM_SET_SREGS, since the EFER contents tracked by the host > will be missing the EFER_LMA bit, and when userspace attempts to pass > the EFER value back via KVM_SET_SREGS it will fail a sanity check that > asserts that EFER_LMA should always be set when X86_CR0_PG and EFER_LME > are set. > > Fix this by always inferring the value of EFER_LMA based on X86_CR0_PG > and EFER_LME, regardless of whether or not SEV-ES is enabled. > > Fixes: f1c6366e3043 ("KVM: SVM: Add required changes to support intercepts under SEV-ES") > Suggested-by: Tom Lendacky <thomas.lendacky@xxxxxxx> > Cc: Sean Christopherson <seanjc@xxxxxxxxxx> > Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> > Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> > Cc: Ingo Molnar <mingo@xxxxxxxxxx> > Cc: Borislav Petkov <bp@xxxxxxxxx> > Cc: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx> > Cc: "H. Peter Anvin" <hpa@xxxxxxxxx> > Cc: Tom Lendacky <thomas.lendacky@xxxxxxx> > Cc: x86@xxxxxxxxxx > Cc: linux-kernel@xxxxxxxxxxxxxxx > Signed-off-by: Michael Roth <michael.roth@xxxxxxx> > --- > arch/x86/kvm/svm/svm.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c > index 5d75a1732da4..b31d4f2deb66 100644 > --- a/arch/x86/kvm/svm/svm.c > +++ b/arch/x86/kvm/svm/svm.c > @@ -1869,7 +1869,7 @@ void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) > bool old_paging = is_paging(vcpu); > > #ifdef CONFIG_X86_64 > - if (vcpu->arch.efer & EFER_LME && !vcpu->arch.guest_state_protected) { > + if (vcpu->arch.efer & EFER_LME) { > if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { > vcpu->arch.efer |= EFER_LMA; > svm->vmcb->save.efer |= EFER_LMA | EFER_LME; Purely from the point of view of not confusing future readers of this code: Due to encrypted guest state, if I understand correctly, the 'svm->vmcb->save.efer' is only given for the hypervisor to see but not to modify. While the modification of save.efer is a nop, can we still guard it with 'vcpu->arch.guest_state_protected'? Besides these nitpicks: Reviewed-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx> Best regards, Maxim Levitsky