Re: [PATCH v3 5/9] hw/misc/vmlaunchupdate: Introduce hypervisor fw-cfg interface support

Alexander Graf <[email protected]>
Newsgroups org.nongnu.qemu-devel
Message-ID <[email protected]>
On 30.07.26 09:12, Ani Sinha wrote:
> VM launch update is a mechanism where the virtual machines can use IGVM
> file bundle to boot into a trusted execution environment without
> having to depend on a untrusted party to provide the IGVM bundle or firmware
> image. This is particularly useful for confidential virtual machines that
> are deployed in the cloud where the tenant and the cloud provider are two
> different entities. In this scenario, virtual machines can bring their own
> trusted IGVM file containing a trusted firmware image
> bundled as a part of their filesystem and then use this hypervisor interface
> to update to a trusted and deterministic boot state.
> This also allows the guests to have a consistent measurements on the firmware
> image.
>
> Currently, this mechanism only works if the VM was started with IGVM in the
> first place.
>
> This change introduces support for the fw-cfg based hypervisor interface
> and the corresponding device. The interface is made generic
> enough so that guests are free to use their own ABI to pass required
> information between initial and trusted execution contexts (where they are
> running their own trusted boot state) without the hypervisor getting
> involved in between.
>
> Currently, this device is only supported for x86 machines. Presence of
> IGVM host libraries is also required for parsing IGVM files. Hence, the device
> cannot be initialized for other machine types or hosts where IGVM support
> is not present. Trying to initialize it for arm for example will lead to failure:
>
> $ ./qemu-system-arm -device vm-launch-update -machine virt
> qemu-system-arm: -device vmfwupdate: This machine does not support vm-launch-update device
>
> Functional and qtests will be added in a subsequent patch.
>
> CC: Alex Graf <[email protected]>
> CC: Gerd Hoffman <[email protected]>
>
> Reviewed-by: Gerd Hoffmann <[email protected]>
> Signed-off-by: Ani Sinha <[email protected]>
> ---
>   hw/misc/meson.build              |   3 +
>   hw/misc/trace-events             |   6 +
>   hw/misc/vmlaunchupdate.c         | 309 +++++++++++++++++++++++++++++++
>   include/hw/misc/vmlaunchupdate.h |  38 ++++
>   4 files changed, 356 insertions(+)
>   create mode 100644 hw/misc/vmlaunchupdate.c
>   create mode 100644 include/hw/misc/vmlaunchupdate.h
>
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 23265f6035..b8c7de295e 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -163,6 +163,9 @@ specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c'))
>   
>   specific_ss.add(when: 'CONFIG_RISCV_MIPS_CMGCR', if_true: files('riscv_cmgcr.c'))
>   specific_ss.add(when: 'CONFIG_RISCV_MIPS_CPC', if_true: files('riscv_cpc.c'))
> +if igvm.found()
> +   specific_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmlaunchupdate.c'))
> +endif
>   
>   system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c'))
>   
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index c9a868b3ef..2d6d2238c5 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -442,3 +442,9 @@ iommu_testdev_dma_read(uint64_t gva, uint32_t len) "gva=0x%" PRIx64 " len=%u"
>   iommu_testdev_dma_verify(uint32_t expected, uint32_t actual) "expected=0x%x actual=0x%x"
>   iommu_testdev_dma_result(uint32_t result) "DMA completed result=0x%x"
>   iommu_testdev_dma_armed(bool armed) "armed=%d"
> +
> +# vmlaunchupdate.c
> +launch_update_write(void) ""
> +vmlaunch_reset_enter(void) ""
> +vm_launchupdate_finalize(void) ""
> +restore_host_x86_igvm(void) ""
> diff --git a/hw/misc/vmlaunchupdate.c b/hw/misc/vmlaunchupdate.c
> new file mode 100644
> index 0000000000..5b0222310b
> --- /dev/null
> +++ b/hw/misc/vmlaunchupdate.c
> @@ -0,0 +1,309 @@
> +/*
> + * Guest driven VM launch component update (using IGVM) device
> + * For details and specification, please look at docs/specs/vmlaunchupdate.rst.
> + *
> + * Copyright (C) 2026 Red Hat, Inc.
> + *
> + * Authors: Ani Sinha <[email protected]>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/module.h"
> +#include "system/physmem.h"
> +#include "system/reset.h"
> +#include "qemu/target-info-qapi.h"
> +#include "hw/nvram/fw_cfg.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/i386/pc.h"
> +#include "exec/cpu-common.h"
> +#include "hw/misc/vmlaunchupdate.h"
> +#include "system/igvm.h"
> +#include "system/igvm-internal.h"
> +#include "qemu/error-report.h"
> +#include "trace.h"
> +
> +/* returns NULL unless there is exactly one device */
> +static VMLaunchUpdateState *vm_launchupdate_find(void)
> +{
> +    Object *o = object_resolve_path_type("", TYPE_VMLAUNCHUPDATE, NULL);
> +
> +    return o ? VMLAUNCHUPDATE(o) : NULL;
> +}
> +
> +static bool vmlaunchupdate_supported(void)
> +{
> +    return target_arch() == SYS_EMU_TARGET_X86_64;
> +}
> +
> +static void init_vm_launch_update(VMLaunchUpdateState *s)
> +{
> +    s->launch_update.capabilities = VM_LAUNCHUPDATE_FORMAT_IGVM;
> +    s->launch_update.control = 0;
> +
> +    if (s->disabled) {
> +        s->launch_update.control |= VM_LAUNCHUPDATE_CTL_DISABLE;
> +    }
> +
> +    s->launch_update.version = VM_LAUNCHUPDATE_VERSION;
> +    return;
> +}
> +
> +static void clear_init_vm_launch_update(VMLaunchUpdateState *s)
> +{
> +    memset(&s->launch_update, 0, sizeof(s->launch_update));
> +    init_vm_launch_update(s);
> +}
> +
> +static int process_x86_igvm(VMLaunchUpdateState *s,
> +                            uint64_t fw_image_addr, uint64_t fw_image_size)
> +{
> +    X86MachineState *x86machine = X86_MACHINE(qdev_get_machine());
> +    IgvmCfg *igvmc = x86machine->igvm;
> +    IgvmHandle igvm;
> +    void *image_addr_ptr;
> +    hwaddr len;
> +
> +    if (!igvmc) {
> +        /* The VM was not started with an IGVM, bail */
> +        info_report("guest was not initially started with IGVM, "
> +                    "not changing launch state.");
> +        return -2;
> +    }
> +
> +    if (!fw_image_addr || !fw_image_size) {
> +        return -1;
> +    }
> +
> +    len = (hwaddr) fw_image_size;
> +    image_addr_ptr = physical_memory_map((hwaddr) fw_image_addr,
> +                                         (hwaddr *) &len, 0);
> +
> +    if (!image_addr_ptr || (len < fw_image_size)) {
> +        warn_report("vmlaunchupdate: Invalid guest addresses.");
> +        physical_memory_unmap(image_addr_ptr, len, 0, 0);


On !image_addr_ptr, wouldn't this invoke unmap(NULL)?


> +        return -1;
> +    }
> +
> +    igvm = igvm_new_from_binary(image_addr_ptr, fw_image_size);
> +    if (igvm < 0) {
> +        warn_report("vmlaunchupdate: Unable to parse IGVM file %"
> +                    PRIx64 ": %" PRIx64, fw_image_addr, fw_image_size);


Don't we need to unmap here as well, like above?

I think the best way to make this code pretty is a goto err with 
conditional unmap.


> +        return -1;
> +    }
> +
> +    /* free previous file context */
> +    if (igvmc->file >= 0) {
> +        igvm_free(igvmc->file);
> +    }
> +    /* set new context */
> +    igvmc->file = igvm;
> +
> +    physical_memory_unmap(image_addr_ptr, len, 0, 0);
> +    info_report("vmlaunchupdate: new IGVM context set.");
> +
> +    return 0;
> +}
> +
> +static void restore_host_x86_igvm(void)
> +{
> +    X86MachineState *x86machine = X86_MACHINE(qdev_get_machine());
> +    IgvmCfg *igvmc = x86machine->igvm;


The igvm property can be NULL, if nobody set igvm-cfg. So if you launch 
QEMU with just "-device vm-launch-update", it will crash here. You check 
it above in process_x86_igvm(), but not here. Maybe create a generic 
function that does the info_report and bails out?


> +    Error *errp;


Please always preinitialize errp with NULL. Typically callers expects 
that it's NULL, so they can choose not to touch it on error.


Alex
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.