Re: [PATCH 1/1] sev: Provide VMSA to kvm via KVM_SEV_SNP_LAUNCH_UPDATE

"Gupta, Pankaj" <[email protected]> Fri, 12 Jun 2026 13:25:55 +0200
Newsgroups dev.linux.lists.coconut-svsm
Message-ID <[email protected]>
> From: Roy Hopkins <[email protected]>
>
> Previously the VMSA could not be set directly. Instead the current CPU state
> was automatically populated into a VMSA within kvm as part of
> KVM_SEV_SNP_LAUNCH_FINISH. This meant that it was hard to ensure the VMSA
> provided by IGVM matched the resulting one in kvm.
>
> KVM has been updated to allow the VMSA to be provided via
> KVM_SEV_SNP_LAUNCH_UPDATE. In this case, kvm does not perform any specific
> synchronisation during FINISH and the VMSA is guaranteed to match that provided
> by QEMU.
>
> Signed-off-by: Roy Hopkins <[email protected]>
> Co-developed-by: Vaishali Thakkar <[email protected]>
> Co-developed-by: Joerg Roedel <[email protected]>
> Signed-off-by: Joerg Roedel <[email protected]>

Not very familiar with inside of IGVM format. Overall patch looks good 
to me.

Reviewed-by: Pankaj Gupta <[email protected]>

> ---
>   backends/igvm.c                | 44 ++++++++++++++++++++++++++++++++--
>   include/system/igvm-internal.h |  1 +
>   target/i386/sev.c              | 10 +++++++-
>   3 files changed, 52 insertions(+), 3 deletions(-)
>
> diff --git a/backends/igvm.c b/backends/igvm.c
> index c347d0c17e..07e6db69e2 100644
> --- a/backends/igvm.c
> +++ b/backends/igvm.c
> @@ -425,6 +425,8 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
>       const IGVM_VHS_VP_CONTEXT *vp_context =
>           (const IGVM_VHS_VP_CONTEXT *)header_data;
>       IgvmHandle data_handle;
> +    uint32_t data_size;
> +    uint8_t *region;
>       uint8_t *data;
>       int result;
>   
> @@ -432,6 +434,16 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
>           return 0;
>       }
>   
> +    /*
> +     * Complete any other page processing first to ensure measurements
> +     * are correct.
> +     */
> +    if (ctx->machine_state->cgs) {
> +        if (qigvm_process_mem_page(ctx, NULL, errp)) {
> +            return -1;
> +        }
> +    }
> +
>       data_handle = igvm_get_header_data(ctx->file, IGVM_HEADER_SECTION_DIRECTIVE,
>                                          ctx->current_header_index);
>       if (data_handle < 0) {
> @@ -440,6 +452,21 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
>           return -1;
>       }
>   
> +    data_size = igvm_get_buffer_size(ctx->file, data_handle);
> +    if (data_size != IGVM_PAGE_SIZE_4K) {
> +        error_setg(errp, "IGVM: VP context data size %u not equal to page size",
> +                   data_size);
> +        result = -1;
> +        goto exit;
> +    }
> +
> +    if (vp_context->vp_index != 0) {
> +        error_setg(errp, "IGVM: VP context vp_index set to %u - must be zero",
> +                   vp_context->vp_index);
> +        result = -1;
> +        goto exit;
> +    }
> +
>       data = (uint8_t *)igvm_get_buffer(ctx->file, data_handle);
>       if (data == NULL) {
>           error_setg(errp, "IGVM: No buffer for handle %d", data_handle);
> @@ -448,9 +475,21 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
>       }
>   
>       if (ctx->machine_state->cgs) {
> +        if (!ctx->only_vp_context) {
> +            region = qigvm_prepare_memory(ctx, vp_context->gpa, IGVM_PAGE_SIZE_4K,
> +                    ctx->current_header_index, errp);
> +            if (!region) {
> +                result = -1;
> +                goto exit;
> +            }
> +            memset(region, 0, IGVM_PAGE_SIZE_4K);
> +            memcpy(region, data, data_size);
> +        } else {
> +            region = data;
> +        }
>           result = ctx->cgsc->set_guest_state(
> -            vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle),
> -            CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp);
> +            vp_context->gpa, region, IGVM_PAGE_SIZE_4K,
> +            CGS_PAGE_TYPE_VMSA, 0, errp);
>       } else if (target_arch() == SYS_EMU_TARGET_X86_64) {
>           result = qigvm_x86_set_vp_context(data, vp_context->vp_index, errp);
>       } else {
> @@ -911,6 +950,7 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state,
>           return -1;
>       }
>       ctx.file = cfg->file;
> +    ctx.only_vp_context = onlyVpContext;
>       trace_igvm_process_file(cfg->file, onlyVpContext);
>   
>       ctx.machine_state = machine_state;
> diff --git a/include/system/igvm-internal.h b/include/system/igvm-internal.h
> index 7f131c4d03..3ac0447e4d 100644
> --- a/include/system/igvm-internal.h
> +++ b/include/system/igvm-internal.h
> @@ -67,6 +67,7 @@ struct QIgvm {
>       unsigned region_start_index;
>       unsigned region_last_index;
>       unsigned region_page_count;
> +    bool only_vp_context;
>   };
>   
>   IgvmHandle qigvm_file_init(char *filename, Error **errp);
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 9dde972c11..af4c0156f6 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -1171,6 +1171,7 @@ snp_page_type_to_str(int type)
>   {
>       switch (type) {
>       case KVM_SEV_SNP_PAGE_TYPE_NORMAL: return "Normal";
> +    case KVM_SEV_SNP_PAGE_TYPE_VMSA: return "VMSA";
>       case KVM_SEV_SNP_PAGE_TYPE_ZERO: return "Zero";
>       case KVM_SEV_SNP_PAGE_TYPE_UNMEASURED: return "Unmeasured";
>       case KVM_SEV_SNP_PAGE_TYPE_SECRETS: return "Secrets";
> @@ -2597,8 +2598,15 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len,
>                                    errp) < 0) {
>               return -1;
>           }
> -        return sev_set_cpu_context(cpu_index, ptr, len, gpa, errp);
>   
> +        if (sev_snp_enabled() &&
> +            kvm_vm_check_extension(kvm_state, KVM_CAP_SNP_DIRECT_VMSA)) {
> +            return snp_launch_update_data(
> +                    gpa, ptr, len, KVM_SEV_SNP_PAGE_TYPE_VMSA, errp);
> +        } else {
> +            return sev_set_cpu_context(cpu_index, ptr, len, gpa, errp);
> +        }
> +	break;
>       case CGS_PAGE_TYPE_UNMEASURED:
>           if (sev_snp_enabled()) {
>               return snp_launch_update_data(