[PATCH 59/60] kvm: svm: Implement max_planes x86 operation

From: Jörg Rödel

Date: Mon Jun 08 2026 - 11:23:06 EST


From: Tom Lendacky <thomas.lendacky@xxxxxxx>

Report the number of VMPL levels supported by SEV-SNP guests.

Signed-off-by: Tom Lendacky <thomas.lendacky@xxxxxxx>
Co-developed-by: Joerg Roedel <joerg.roedel@xxxxxxx>
Signed-off-by: Joerg Roedel <joerg.roedel@xxxxxxx>
---
arch/x86/kvm/svm/sev.c | 14 ++++++++++++--
arch/x86/kvm/svm/svm.c | 12 +++++++++++-
arch/x86/kvm/svm/svm.h | 3 +++
3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index b67566fcb69e..528c8bd3e8fc 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -114,6 +114,7 @@ static unsigned long sev_me_mask;
static unsigned int nr_asids;
static unsigned long *sev_asid_bitmap;
static unsigned long *sev_reclaim_asid_bitmap;
+static unsigned int vmpl_levels;

static __always_inline void kvm_lockdep_assert_sev_lock_held(struct kvm *kvm)
{
@@ -3103,6 +3104,9 @@ void __init sev_hardware_setup(void)
/* Set encryption bit location for SEV-ES guests */
sev_enc_bit = ebx & 0x3f;

+ /* Get the number of supported VMPL levels */
+ vmpl_levels = (ebx >> 12) & 0xf;
+
/* Maximum number of encrypted guests supported simultaneously */
max_sev_asid = ecx;
if (!max_sev_asid)
@@ -3217,9 +3221,10 @@ void __init sev_hardware_setup(void)
"disabled",
min_sev_es_asid, max_sev_es_asid);
if (boot_cpu_has(X86_FEATURE_SEV_SNP))
- pr_info("SEV-SNP %s (ASIDs %u - %u)\n",
+ pr_info("SEV-SNP %s (ASIDs %u - %u), VMPL Levels %u\n",
str_enabled_disabled(sev_snp_supported),
- min_snp_asid, max_snp_asid);
+ min_snp_asid, max_snp_asid,
+ vmpl_levels);

sev_enabled = sev_supported;
sev_es_enabled = sev_es_supported;
@@ -5852,3 +5857,8 @@ bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu)

return blocked;
}
+
+int sev_snp_max_planes(struct kvm *kvm)
+{
+ return vmpl_levels;
+}
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 2ae82dc058c9..705063c7f0f0 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -5321,6 +5321,16 @@ static void svm_free_plane(struct kvm_plane *plane)
kfree(svm_plane);
}

+static unsigned svm_max_planes(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+ if (____sev_snp_guest(kvm))
+ return sev_snp_max_planes(kvm);
+#endif
+
+ return kvm_x86_default_max_planes(kvm);
+}
+
struct kvm_x86_ops svm_x86_ops __initdata = {
.name = KBUILD_MODNAME,

@@ -5465,7 +5475,7 @@ struct kvm_x86_ops svm_x86_ops __initdata = {

.alloc_plane = svm_alloc_plane,
.free_plane = svm_free_plane,
- .max_planes = kvm_x86_default_max_planes,
+ .max_planes = svm_max_planes,
};

/*
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 7e860f2abafb..7aba2cceb44d 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -1008,6 +1008,8 @@ static inline bool sev_snp_is_rinj_active(struct kvm_vcpu *vcpu)
return is_sev_snp_guest(vcpu) &&
(sev->vmsa_features & SVM_SEV_FEAT_RESTRICTED_INJECTION);
};
+int sev_nr_vcpu_planes(struct kvm *kvm);
+int sev_snp_max_planes(struct kvm *kvm);
#else
static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
{
@@ -1051,6 +1053,7 @@ static inline bool sev_snp_inject(enum inject_type type, struct kvm_vcpu *vcpu)
static inline void sev_snp_cancel_injection(struct kvm_vcpu *vcpu) {}
static inline bool sev_snp_blocked(enum inject_type type, struct kvm_vcpu *vcpu) { return false; }
static inline bool sev_snp_is_rinj_active(struct kvm_vcpu *vcpu) { return false; }
+static inline unsigned sev_snp_max_planes(struct kvm *kvm) { return 1; }
#endif

/* vmenter.S */
--
2.53.0