All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>, kvm@vger.kernel.org
Cc: Sean Christopherson <sean.j.christopherson@intel.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Jim Mattson <jmattson@google.com>,
	Junaid Shahid <junaids@google.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/3] KVM: nSVM: properly call kvm_mmu_new_pgd() upon switching to guest
Date: Wed, 08 Jul 2020 16:39:14 +0200	[thread overview]
Message-ID: <87eepmul4d.fsf@vitty.brq.redhat.com> (raw)
In-Reply-To: <b7989497-562e-c9a1-3f62-dd5afb9fd3d5@redhat.com>

Paolo Bonzini <pbonzini@redhat.com> writes:

> On 08/07/20 11:36, Vitaly Kuznetsov wrote:
>> Undesired triple fault gets injected to L1 guest on SVM when L2 is
>> launched with certain CR3 values. #TF is raised by mmu_check_root()
>> check in fast_pgd_switch() and the root cause is that when
>> kvm_set_cr3() is called from nested_prepare_vmcb_save() with NPT
>> enabled CR3 points to a nGPA so we can't check it with
>> kvm_is_visible_gfn().
>> 
>> Calling kvm_mmu_new_pgd() with L2's CR3 idea when NPT is in use
>> seems to be wrong, an acceptable place for it seems to be
>> kvm_init_shadow_npt_mmu(). This also matches nVMX code.
>> 
>> Fixes: 7c390d350f8b ("kvm: x86: Add fast CR3 switch code path")
>> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
>> ---
>>  arch/x86/include/asm/kvm_host.h | 7 ++++++-
>>  arch/x86/kvm/mmu/mmu.c          | 2 ++
>>  arch/x86/kvm/svm/nested.c       | 2 +-
>>  arch/x86/kvm/x86.c              | 8 +++++---
>>  4 files changed, 14 insertions(+), 5 deletions(-)
>> 
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index be5363b21540..49b62f024f51 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1459,7 +1459,12 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
>>  		    int reason, bool has_error_code, u32 error_code);
>>  
>>  int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
>> -int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
>> +int __kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool cr3_is_nested);
>> +static inline int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
>> +{
>> +	return __kvm_set_cr3(vcpu, cr3, false);
>> +}
>> +
>>  int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
>>  int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8);
>>  int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val);
>> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
>> index 167d12ab957a..ebf0cb3f1ce0 100644
>> --- a/arch/x86/kvm/mmu/mmu.c
>> +++ b/arch/x86/kvm/mmu/mmu.c
>> @@ -4987,6 +4987,8 @@ void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, u32 cr0, u32 cr4, u32 efer,
>>  	union kvm_mmu_role new_role =
>>  		kvm_calc_shadow_mmu_root_page_role(vcpu, false);
>>  
>> +	__kvm_mmu_new_pgd(vcpu, nested_cr3, new_role.base, true, true);
>> +
>>  	if (new_role.as_u64 != context->mmu_role.as_u64)
>>  		shadow_mmu_init_context(vcpu, cr0, cr4, efer, new_role);
>>  }
>> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
>> index e424bce13e6c..b467917a9784 100644
>> --- a/arch/x86/kvm/svm/nested.c
>> +++ b/arch/x86/kvm/svm/nested.c
>> @@ -324,7 +324,7 @@ static void nested_prepare_vmcb_save(struct vcpu_svm *svm, struct vmcb *nested_v
>>  	svm_set_efer(&svm->vcpu, nested_vmcb->save.efer);
>>  	svm_set_cr0(&svm->vcpu, nested_vmcb->save.cr0);
>>  	svm_set_cr4(&svm->vcpu, nested_vmcb->save.cr4);
>> -	(void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
>> +	(void)__kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3, npt_enabled);
>>  
>>  	svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
>>  	kvm_rax_write(&svm->vcpu, nested_vmcb->save.rax);
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> index 3b92db412335..3761135eb052 100644
>> --- a/arch/x86/kvm/x86.c
>> +++ b/arch/x86/kvm/x86.c
>> @@ -1004,7 +1004,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
>>  }
>>  EXPORT_SYMBOL_GPL(kvm_set_cr4);
>>  
>> -int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
>> +int __kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool cr3_is_nested)
>>  {
>>  	bool skip_tlb_flush = false;
>>  #ifdef CONFIG_X86_64
>> @@ -1031,13 +1031,15 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
>>  		 !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))
>>  		return 1;
>>  
>> -	kvm_mmu_new_pgd(vcpu, cr3, skip_tlb_flush, skip_tlb_flush);
>> +	if (!cr3_is_nested)
>> +		kvm_mmu_new_pgd(vcpu, cr3, skip_tlb_flush, skip_tlb_flush);
>> +
>>  	vcpu->arch.cr3 = cr3;
>>  	kvm_register_mark_available(vcpu, VCPU_EXREG_CR3);
>>  
>>  	return 0;
>>  }
>> -EXPORT_SYMBOL_GPL(kvm_set_cr3);
>> +EXPORT_SYMBOL_GPL(__kvm_set_cr3);
>>  
>>  int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
>>  {
>> 
>
> Instead of the new argument (which is not really named right since it's
> never true for !NPT) you could perhaps check vcpu->arch.mmu.  But also,
> for NPT=1 the kvm_mmu_new_pgd is also unnecessary on vmexit, because the
> old roots are still valid (or has been invalidated otherwise) while L2
> was running.
>
> I'm also not sure if skip_tlb_flush can use X86_CR3_PCID_NOFLUSH the way
> kvm_set_cr3 does, so I wouldn't mind duplicating the code completely as
> is already the case for nested_vmx_load_cr3.  It would introduce some
> code duplication, but overall the code would be better.  For now, there
> need not be an equivalent to nested_vmx_transition_mmu_sync, ASID
> handling can be left for later.

Sounds reasonable,

let's introduce nested_svm_load_cr3() to not mix these two concepts
together. I'll be back with v3 shortly, thanks!

-- 
Vitaly


  reply	other threads:[~2020-07-08 14:39 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-08  9:36 [PATCH v2 0/3] KVM: nSVM: fix #TF from CR3 switch when entering guest Vitaly Kuznetsov
2020-07-08  9:36 ` [PATCH v2 1/3] KVM: nSVM: split kvm_init_shadow_npt_mmu() from kvm_init_shadow_mmu() Vitaly Kuznetsov
2020-07-08 11:25   ` Paolo Bonzini
2020-07-08  9:36 ` [PATCH v2 2/3] KVM: nSVM: properly call kvm_mmu_new_pgd() upon switching to guest Vitaly Kuznetsov
2020-07-08 11:49   ` Paolo Bonzini
2020-07-08 14:39     ` Vitaly Kuznetsov [this message]
2020-07-08  9:36 ` [PATCH v2 3/3] KVM: x86: drop superfluous mmu_check_root() from fast_pgd_switch() Vitaly Kuznetsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87eepmul4d.fsf@vitty.brq.redhat.com \
    --to=vkuznets@redhat.com \
    --cc=jmattson@google.com \
    --cc=junaids@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=sean.j.christopherson@intel.com \
    --cc=wanpengli@tencent.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.