Skip to content

Commit b210402

Browse files
mdrothbonzini
authored andcommitted
KVM: x86: Implement hook for determining max NPT mapping level
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. The existing mixed-attribute tracking in KVM is insufficient here, for instance: - gmem allocates 2MB page - guest issues PVALIDATE on 2MB page - guest later converts a subpage to shared - SNP host code issues PSMASH to split 2MB RMP mapping to 4K - KVM MMU splits NPT mapping to 4K - guest later converts that shared page back to private At this point there are no mixed attributes, and KVM would normally allow for 2MB NPT mappings again, but this is actually not allowed because the RMP table mappings are 4K and cannot be promoted on the hypervisor side, so the NPT mappings must still be limited to 4K to match this. Implement a kvm_x86_ops.private_max_mapping_level() hook for SEV that checks for this condition and adjusts the mapping level accordingly. Reviewed-by: Paolo Bonzini <[email protected]> Signed-off-by: Michael Roth <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 8eb0190 commit b210402

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4727,3 +4727,18 @@ void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end)
47274727
cond_resched();
47284728
}
47294729
}
4730+
4731+
int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
4732+
{
4733+
int level, rc;
4734+
bool assigned;
4735+
4736+
if (!sev_snp_guest(kvm))
4737+
return 0;
4738+
4739+
rc = snp_lookup_rmpentry(pfn, &assigned, &level);
4740+
if (rc || !assigned)
4741+
return PG_LEVEL_4K;
4742+
4743+
return level;
4744+
}

arch/x86/kvm/svm/svm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5084,6 +5084,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
50845084

50855085
.gmem_prepare = sev_gmem_prepare,
50865086
.gmem_invalidate = sev_gmem_invalidate,
5087+
.private_max_mapping_level = sev_private_max_mapping_level,
50875088
};
50885089

50895090
/*

arch/x86/kvm/svm/svm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ void sev_vcpu_unblocking(struct kvm_vcpu *vcpu);
738738
void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu);
739739
int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order);
740740
void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end);
741+
int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn);
741742
#else
742743
static inline struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) {
743744
return alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
@@ -759,6 +760,10 @@ static inline int sev_gmem_prepare(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, in
759760
return 0;
760761
}
761762
static inline void sev_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end) {}
763+
static inline int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
764+
{
765+
return 0;
766+
}
762767

763768
#endif
764769

0 commit comments

Comments
 (0)