Re: [PATCH RFC gmem v1 8/8] KVM: x86: Determine shared/private faults based on vm_type
From: Sean Christopherson
Date: Tue Jan 30 2024 - 20:13:41 EST
On Mon, Oct 16, 2023, Michael Roth wrote:
> For KVM_X86_SNP_VM, only the PFERR_GUEST_ENC_MASK flag is needed to
> determine with an #NPF is due to a private/shared access by the guest.
> Implement that handling here. Also add handling needed to deal with
> SNP guests which in some cases will make MMIO accesses with the
> encryption bit.
..
> @@ -4356,12 +4357,19 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
> return RET_PF_EMULATE;
> }
>
> - if (fault->is_private != kvm_mem_is_private(vcpu->kvm, fault->gfn)) {
> + /*
> + * In some cases SNP guests will make MMIO accesses with the encryption
> + * bit set. Handle these via the normal MMIO fault path.
> + */
> + if (!slot && private_fault && kvm_is_vm_type(vcpu->kvm, KVM_X86_SNP_VM))
> + private_fault = false;
Why? This is inarguably a guest bug.
> + if (private_fault != kvm_mem_is_private(vcpu->kvm, fault->gfn)) {
> kvm_mmu_prepare_memory_fault_exit(vcpu, fault);
> return -EFAULT;
> }
>
> - if (fault->is_private)
> + if (private_fault)
> return kvm_faultin_pfn_private(vcpu, fault);
>
> async = false;
> diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h
> index 759c8b718201..e5b973051ad9 100644
> --- a/arch/x86/kvm/mmu/mmu_internal.h
> +++ b/arch/x86/kvm/mmu/mmu_internal.h
> @@ -251,6 +251,24 @@ struct kvm_page_fault {
>
> int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault);
>
> +static bool kvm_mmu_fault_is_private(struct kvm *kvm, gpa_t gpa, u64 err)
> +{
> + bool private_fault = false;
> +
> + if (kvm_is_vm_type(kvm, KVM_X86_SNP_VM)) {
> + private_fault = !!(err & PFERR_GUEST_ENC_MASK);
> + } else if (kvm_is_vm_type(kvm, KVM_X86_SW_PROTECTED_VM)) {
> + /*
> + * This handling is for gmem self-tests and guests that treat
> + * userspace as the authority on whether a fault should be
> + * private or not.
> + */
> + private_fault = kvm_mem_is_private(kvm, gpa >> PAGE_SHIFT);
> + }
This can be more simply:
if (kvm_is_vm_type(kvm, KVM_X86_SNP_VM))
return !!(err & PFERR_GUEST_ENC_MASK);
if (kvm_is_vm_type(kvm, KVM_X86_SW_PROTECTED_VM))
return kvm_mem_is_private(kvm, gpa >> PAGE_SHIFT);