[RFC PATCH 4/7] KVM: SVM: Maintain per-VMPL SEV features in kvm_sev_info

From: Tom Lendacky
Date: Tue Aug 27 2024 - 18:01:13 EST


From: Carlos Bilbao <carlos.bilbao@xxxxxxx>

Make struct kvm_sev_info maintain separate SEV features per VMPL, allowing
distinct SEV features depending on VMs privilege level.

Signed-off-by: Carlos Bilbao <carlos.bilbao@xxxxxxx>
Signed-off-by: Tom Lendacky <thomas.lendacky@xxxxxxx>
---
arch/x86/kvm/svm/sev.c | 22 +++++++++++++++-------
arch/x86/kvm/svm/svm.h | 4 ++--
2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index e0f5122061e6..c6c9306c86ef 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -144,7 +144,7 @@ static bool sev_vcpu_has_debug_swap(struct vcpu_svm *svm)
struct kvm_vcpu *vcpu = &svm->vcpu;
struct kvm_sev_info *sev = &to_kvm_svm(vcpu->kvm)->sev_info;

- return sev->vmsa_features & SVM_SEV_FEAT_DEBUG_SWAP;
+ return sev->vmsa_features[cur_vmpl(svm)] & SVM_SEV_FEAT_DEBUG_SWAP;
}

/* Must be called with the sev_bitmap_lock held */
@@ -428,7 +428,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,

sev->active = true;
sev->es_active = es_active;
- sev->vmsa_features = data->vmsa_features;
+ sev->vmsa_features[SVM_SEV_VMPL0] = data->vmsa_features;
sev->ghcb_version = data->ghcb_version;

/*
@@ -440,7 +440,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
sev->ghcb_version = GHCB_VERSION_DEFAULT;

if (vm_type == KVM_X86_SNP_VM)
- sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE;
+ sev->vmsa_features[SVM_SEV_VMPL0] |= SVM_SEV_FEAT_SNP_ACTIVE;

ret = sev_asid_new(sev);
if (ret)
@@ -468,7 +468,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
sev_asid_free(sev);
sev->asid = 0;
e_no_asid:
- sev->vmsa_features = 0;
+ sev->vmsa_features[SVM_SEV_VMPL0] = 0;
sev->es_active = false;
sev->active = false;
return ret;
@@ -852,7 +852,7 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm)
save->xss = svm->vcpu.arch.ia32_xss;
save->dr6 = svm->vcpu.arch.dr6;

- save->sev_features = sev->vmsa_features;
+ save->sev_features = sev->vmsa_features[SVM_SEV_VMPL0];

/*
* Skip FPU and AVX setup with KVM_SEV_ES_INIT to avoid
@@ -1985,7 +1985,7 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
dst->pages_locked = src->pages_locked;
dst->enc_context_owner = src->enc_context_owner;
dst->es_active = src->es_active;
- dst->vmsa_features = src->vmsa_features;
+ memcpy(dst->vmsa_features, src->vmsa_features, sizeof(dst->vmsa_features));

src->asid = 0;
src->active = false;
@@ -4034,8 +4034,16 @@ static int sev_snp_ap_creation(struct vcpu_svm *svm)

/* Interrupt injection mode shouldn't change for AP creation */
sev_features = vcpu->arch.regs[VCPU_REGS_RAX];
- sev_features ^= sev->vmsa_features;

+ /*
+ * The SNPActive feature must at least be set. If the SEV
+ * features of this AP are zero, this is the first vCPU created at
+ * this VMPL.
+ */
+ if (!sev->vmsa_features[vmpl])
+ sev->vmsa_features[vmpl] = sev_features | SVM_SEV_FEAT_SNP_ACTIVE;
+
+ sev_features ^= sev->vmsa_features[vmpl];
if (sev_features & SVM_SEV_FEAT_INT_INJ_MODES) {
vcpu_unimpl(vcpu, "vmgexit: invalid AP injection mode [%#lx] from guest\n",
vcpu->arch.regs[VCPU_REGS_RAX]);
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index d1ef349556f7..55f1f6ffb871 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -87,7 +87,7 @@ struct kvm_sev_info {
unsigned long pages_locked; /* Number of pages locked */
struct list_head regions_list; /* List of registered regions */
u64 ap_jump_table; /* SEV-ES AP Jump Table address */
- u64 vmsa_features;
+ u64 vmsa_features[SVM_SEV_VMPL_MAX];
u16 ghcb_version; /* Highest guest GHCB protocol version allowed */
struct kvm *enc_context_owner; /* Owner of copied encryption context */
struct list_head mirror_vms; /* List of VMs mirroring */
@@ -416,7 +416,7 @@ static __always_inline bool sev_snp_guest(struct kvm *kvm)
#ifdef CONFIG_KVM_AMD_SEV
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;

- return (sev->vmsa_features & SVM_SEV_FEAT_SNP_ACTIVE) &&
+ return (sev->vmsa_features[SVM_SEV_VMPL0] & SVM_SEV_FEAT_SNP_ACTIVE) &&
!WARN_ON_ONCE(!sev_es_guest(kvm));
#else
return false;
--
2.43.2