Message ID | 3d5079d0a58616726e7471a93e3295676148865a.1692119201.git.isaku.yamahata@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: gmem: Adding hooks for SEV and TDX | expand |
On Tue Aug 15, 2023 at 8:18 PM EEST, wrote: > From: Michael Roth <michael.roth@amd.com> > > All gmem pages are expected to be 'private' as defined by a particular > arch/platform. Platforms like SEV-SNP require additional operations to > move these pages into a private state, so implement a hook that can be > used to prepare this memory prior to mapping it into a guest. > > In the case of SEV-SNP, whether or not a 2MB page can be mapped via a > 2MB mapping in the guest's nested page table depends on whether or not > any subpages within the range have already been initialized as private > in the RMP table, so this hook will also be used by the KVM MMU to clamp > the maximum mapping size accordingly. > > Signed-off-by: Michael Roth <michael.roth@amd.com> > Link: https://lore.kernel.org/r/20230612042559.375660-2-michael.roth@amd.com > > --- > Changes v2 -> v3: > - Newly added > --- > arch/x86/include/asm/kvm-x86-ops.h | 1 + > arch/x86/include/asm/kvm_host.h | 3 +++ > arch/x86/kvm/mmu/mmu.c | 12 ++++++++++-- > 3 files changed, 14 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h > index 13bc212cd4bc..439ba4beb5af 100644 > --- a/arch/x86/include/asm/kvm-x86-ops.h > +++ b/arch/x86/include/asm/kvm-x86-ops.h > @@ -133,6 +133,7 @@ KVM_X86_OP(msr_filter_changed) > KVM_X86_OP(complete_emulated_msr) > KVM_X86_OP(vcpu_deliver_sipi_vector) > KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); > +KVM_X86_OP_OPTIONAL_RET0(gmem_prepare) > > #undef KVM_X86_OP > #undef KVM_X86_OP_OPTIONAL > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index bbefd79b7950..2bc42f2887fa 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1732,6 +1732,9 @@ struct kvm_x86_ops { > * Returns vCPU specific APICv inhibit reasons > */ > unsigned long (*vcpu_get_apicv_inhibit_reasons)(struct kvm_vcpu *vcpu); > + > + int (*gmem_prepare)(struct kvm *kvm, struct kvm_memory_slot *slot, > + kvm_pfn_t pfn, gfn_t gfn, u8 *max_level); > }; > > struct kvm_x86_nested_ops { > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c > index 05943ccb55a4..06900b01b8f0 100644 > --- a/arch/x86/kvm/mmu/mmu.c > +++ b/arch/x86/kvm/mmu/mmu.c > @@ -4352,6 +4352,7 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, > struct kvm_page_fault *fault) > { > int max_order, r; > + u8 max_level; > > if (!kvm_slot_can_be_private(fault->slot)) > return kvm_do_memory_fault_exit(vcpu, fault); > @@ -4361,8 +4362,15 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, > if (r) > return r; > > - fault->max_level = min(kvm_max_level_for_order(max_order), > - fault->max_level); > + max_level = kvm_max_level_for_order(max_order); > + r = static_call(kvm_x86_gmem_prepare)(vcpu->kvm, fault->slot, fault->pfn, > + fault->gfn, &max_level); > + if (r) { > + kvm_release_pfn_clean(fault->pfn); > + return r; > + } > + > + fault->max_level = min(max_level, fault->max_level); > fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY); > return RET_PF_CONTINUE; > } > -- > 2.25.1 Acked-by: Jarkko Sakkinen <jarkko@kernel.org> BR, Jarkko
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 13bc212cd4bc..439ba4beb5af 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -133,6 +133,7 @@ KVM_X86_OP(msr_filter_changed) KVM_X86_OP(complete_emulated_msr) KVM_X86_OP(vcpu_deliver_sipi_vector) KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); +KVM_X86_OP_OPTIONAL_RET0(gmem_prepare) #undef KVM_X86_OP #undef KVM_X86_OP_OPTIONAL diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index bbefd79b7950..2bc42f2887fa 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1732,6 +1732,9 @@ struct kvm_x86_ops { * Returns vCPU specific APICv inhibit reasons */ unsigned long (*vcpu_get_apicv_inhibit_reasons)(struct kvm_vcpu *vcpu); + + int (*gmem_prepare)(struct kvm *kvm, struct kvm_memory_slot *slot, + kvm_pfn_t pfn, gfn_t gfn, u8 *max_level); }; struct kvm_x86_nested_ops { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 05943ccb55a4..06900b01b8f0 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4352,6 +4352,7 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { int max_order, r; + u8 max_level; if (!kvm_slot_can_be_private(fault->slot)) return kvm_do_memory_fault_exit(vcpu, fault); @@ -4361,8 +4362,15 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, if (r) return r; - fault->max_level = min(kvm_max_level_for_order(max_order), - fault->max_level); + max_level = kvm_max_level_for_order(max_order); + r = static_call(kvm_x86_gmem_prepare)(vcpu->kvm, fault->slot, fault->pfn, + fault->gfn, &max_level); + if (r) { + kvm_release_pfn_clean(fault->pfn); + return r; + } + + fault->max_level = min(max_level, fault->max_level); fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY); return RET_PF_CONTINUE; }