Re: [PATCH 3/4] kvm: svm: Support guest-provided VMSA for launching
From: Tom Lendacky
Date: Tue Jun 16 2026 - 17:48:40 EST
On 6/11/26 07:35, Jörg Rödel wrote:
> From: Joerg Roedel <joerg.roedel@xxxxxxx>
>
> Introduce a way to provide a guest GPA as the initial BSP VMSA and
> avoid allocating KVM-managed VMSAs in this case. Only one
> guest-provided VMSA is supported at the moment as IGVM also only
> supports to set a single VMSA.
>
> Signed-off-by: Joerg Roedel <joerg.roedel@xxxxxxx>
> ---
> arch/x86/kvm/svm/sev.c | 62 ++++++++++++++++++++++++++++++------------
> arch/x86/kvm/svm/svm.h | 1 +
> 2 files changed, 45 insertions(+), 18 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 350bb97c32c0..88db83b3ff8e 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -726,6 +726,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
>
> INIT_LIST_HEAD(&sev->regions_list);
> INIT_LIST_HEAD(&sev->mirror_vms);
> + sev->initial_vmsa_gpa = INVALID_PAGE;
> sev->need_init = false;
>
> kvm_set_apicv_inhibit(kvm, APICV_INHIBIT_REASON_SEV);
> @@ -2680,6 +2681,46 @@ static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp)
> return 0;
> }
>
> +static int snp_init_guest_vmsa(struct kvm_vcpu *vcpu, gpa_t vmsa_gpa)
> +{
> + /* Only one initial guest VMSA can exist (per IGVM) - so it belongs to the BSP */
Maybe expand this comment to indicate that none of the other vCPU VMSAs
are created by KVM, that the guest is responsible for creating them for
the first time.
Which reminds me that you will need to provide the GHCB APIC ID List NAE
event support. If OVMF was ever to be built as an IGVM file, then
without that GHCB event support it will perform a broadcast INIT-SIPI
for the first AP startup, which will fail because no VMSAs will have
been created. If OVMF sees that the HV has advertised the event, then it
will create all the VMSAs itself and use the GHCB AP Create NAE event
for initial startup of the APs.
> + if (vcpu->vcpu_idx != 0)
> + return 0;
> +
> + /* VMSA already private and encrypted via LAUNCH_UPDATE */
> + sev_es_set_guest_vmsa(vcpu, vmsa_gpa);
> +
> + return 0;
> +}
> +
> +static int snp_init_kvm_vmsa(struct kvm_vcpu *vcpu,
> + struct sev_data_snp_launch_update *data,
> + struct kvm_sev_cmd *argp)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> + int ret;
> + void *vmsa;
> +
> + ret = sev_es_sync_vmsa(svm);
> + if (ret)
> + return ret;
> +
> + vmsa = sev_es_vmsa_ref(vcpu);
> +
> + ret = sev_es_vcpu_vmsa_make_private(vcpu);
> + if (ret)
> + return ret;
> +
> + /* Issue the SNP command to encrypt the VMSA */
> + data->address = __sme_pa(vmsa);
> + ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
> + data, &argp->error);
> + if (ret)
> + sev_snp_vcpu_reclaim_vmsa(vcpu);
> +
> + return ret;
> +}
> +
> static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
> {
> struct kvm_sev_info *sev = to_kvm_sev_info(kvm);
> @@ -2700,28 +2741,13 @@ static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
>
> kvm_for_each_vcpu(i, vcpu, kvm) {
> struct vcpu_svm *svm = to_svm(vcpu);
> - void *vmsa;
>
> - ret = sev_es_sync_vmsa(svm);
> + ret = VALID_PAGE(sev->initial_vmsa_gpa) ?
> + snp_init_guest_vmsa(vcpu, sev->initial_vmsa_gpa) :
> + snp_init_kvm_vmsa(vcpu, &data, argp);
> if (ret)
> goto out;
>
> - vmsa = sev_es_vmsa_ref(vcpu);
> -
> - ret = sev_es_vcpu_vmsa_make_private(vcpu);
> - if (ret)
> - goto out;
> -
> - /* Issue the SNP command to encrypt the VMSA */
> - data.address = __sme_pa(vmsa);
> - ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
> - &data, &argp->error);
> - if (ret) {
> - sev_snp_vcpu_reclaim_vmsa(vcpu);
> -
> - goto out;
> - }
> -
> svm->vcpu.arch.guest_state_protected = true;
>
> /* VMSA encrypted - put it into the VMCB */
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 3d4799f09b23..cc7e84c230bb 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -117,6 +117,7 @@ struct kvm_sev_info {
> struct mutex guest_req_mutex; /* Must acquire before using bounce buffers */
> cpumask_var_t have_run_cpus; /* CPUs that have done VMRUN for this VM. */
> bool snp_certs_enabled; /* SNP certificate-fetching support. */
> + gpa_t initial_vmsa_gpa; /* Optinal GPA of BSP VMSA - SEV-SNP only */
s/Optinal/Optional/
Should it be called bsp_vmsa_gpa ?
Thanks,
Tom
> };
> #endif
>