On Fri, 2025-06-27 at 15:41 +0530, Ani Sinha wrote:
> On Fri, Jun 13, 2025 at 7:24 PM Roy Hopkins <roy.hopk...@randomman.co.uk> 
> wrote:
> > 
> > Adds an IGVM loader to QEMU which processes a given IGVM file and
> > applies the directives within the file to the current guest
> > configuration.
> > 
> > The IGVM loader can be used to configure both confidential and
> > non-confidential guests. For confidential guests, the
> > ConfidentialGuestSupport object for the system is used to encrypt
> > memory, apply the initial CPU state and perform other confidential guest
> > operations.
> > 
> > The loader is configured via a new IgvmCfg QOM object which allows the
> > user to provide a path to the IGVM file to process.
> > 
> > Signed-off-by: Roy Hopkins <roy.hopk...@randomman.co.uk>
> > Acked-by: Michael S. Tsirkin <m...@redhat.com>
> > Acked-by: Gerd Hoffman <kra...@redhat.com>
> > Reviewed-by: Stefano Garzarella <sgarz...@redhat.com>
> > ---
> >  backends/igvm-cfg.c       |  51 +++
> >  backends/igvm.c           | 807 ++++++++++++++++++++++++++++++++++++++
> >  backends/igvm.h           |  22 ++
> >  backends/meson.build      |   2 +
> >  include/system/igvm-cfg.h |  46 +++
> >  qapi/qom.json             |  17 +
> >  6 files changed, 945 insertions(+)
> >  create mode 100644 backends/igvm-cfg.c
> >  create mode 100644 backends/igvm.c
> >  create mode 100644 backends/igvm.h
> >  create mode 100644 include/system/igvm-cfg.h
> > 
> 
> <snip>
> 
> > +
> > +static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index,
> > +                                    uint64_t gpa_start, unsigned 
> > page_count,
> > +                                    const IgvmPageDataFlags *flags,
> > +                                    const IgvmPageDataType page_type,
> > +                                    Error **errp)
> > +{
> > +    uint8_t *region;
> > +    IgvmHandle data_handle;
> > +    const void *data;
> > +    uint32_t data_size;
> > +    unsigned page_index;
> > +    bool zero = true;
> > +    const uint64_t page_size = flags->is_2mb_page ? 0x200000 : 0x1000;
> > +    int result;
> > +    int cgs_page_type;
> > +
> > +    region = qigvm_prepare_memory(ctx, gpa_start, page_count * page_size,
> > +                                  start_index, errp);
> > +    if (!region) {
> > +        return -1;
> > +    }
> > +
> > +    for (page_index = 0; page_index < page_count; page_index++) {
> > +        data_handle = igvm_get_header_data(
> > +            ctx->file, IGVM_HEADER_SECTION_DIRECTIVE, page_index + 
> > start_index);
> > +        if (data_handle == IGVMAPI_NO_DATA) {
> > +            /* No data indicates a zero page */
> > +            memset(&region[page_index * page_size], 0, page_size);
> > +        } else if (data_handle < 0) {
> > +            error_setg(
> > +                errp,
> > +                "IGVM file contains invalid page data for directive with "
> > +                "index %d",
> > +                page_index + start_index);
> > +            return -1;
> > +        } else {
> > +            zero = false;
> > +            data_size = igvm_get_buffer_size(ctx->file, data_handle);
> > +            if (data_size < page_size) {
> > +                memset(&region[page_index * page_size], 0, page_size);
> > +            } else if (data_size > page_size) {
> > +                error_setg(errp,
> > +                           "IGVM file contains page data with invalid size 
> > for "
> > +                           "directive with index %d",
> > +                           page_index + start_index);
> > +                return -1;
> > +            }
> > +            data = igvm_get_buffer(ctx->file, data_handle);
> > +            memcpy(&region[page_index * page_size], data, data_size);
> > +            igvm_free_buffer(ctx->file, data_handle);
> > +        }
> > +    }
> > +
> > +    /*
> > +     * If a confidential guest support object is provided then use it to 
> > set the
> > +     * guest state.
> > +     */
> > +    if (ctx->cgs) {
> > +        cgs_page_type =
> > +            qigvm_type_to_cgs_type(page_type, flags->unmeasured, zero);
> > +        if (cgs_page_type < 0) {
> > +            error_setg(errp,
> > +                       "Invalid page type in IGVM file. Directives: %d to 
> > %d, "
> > +                       "page type: %d",
> > +                       start_index, start_index + page_count, page_type);
> > +            return -1;
> > +        }
> > +
> > +        result = ctx->cgsc->set_guest_state(
> > +            gpa_start, region, page_size * page_count, cgs_page_type, 0, 
> > errp);
> > +        if (result < 0) {
> > +            return result;
> > +        }
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int qigvm_process_mem_page(QIgvm *ctx,
> > +                                  const IGVM_VHS_PAGE_DATA *page_data,
> > +                                  Error **errp)
> > +{
> > +    if (page_data) {
> > +        if (ctx->region_page_count == 0) {
> > +            ctx->region_start = page_data->gpa;
> > +            ctx->region_start_index = ctx->current_header_index;
> > +        } else {
> > +            if (!qigvm_page_attrs_equal(ctx->file, 
> > ctx->current_header_index,
> > +                                        page_data,
> > +                                        &ctx->region_prev_page_data) ||
> > +                ((ctx->region_prev_page_data.gpa +
> > +                  (ctx->region_prev_page_data.flags.is_2mb_page ? 0x200000 
> > :
> > +                                                                  0x1000)) 
> > !=
> > +                 page_data->gpa) ||
> > +                (ctx->region_last_index != (ctx->current_header_index - 
> > 1))) {
> > +                /* End of current region */
> > +                if (qigvm_process_mem_region(
> > +                        ctx, ctx->region_start_index, ctx->region_start,
> > +                        ctx->region_page_count,
> > +                        &ctx->region_prev_page_data.flags,
> > +                        ctx->region_prev_page_data.data_type, errp) < 0) {
> > +                    return -1;
> > +                }
> > +                ctx->region_page_count = 0;
> > +                ctx->region_start = page_data->gpa;
> > +                ctx->region_start_index = ctx->current_header_index;
> 
> Should we return here? Is there any need for the memcpy() below?
> 

No. In this case the new region is not contiguous with the previous region so 
the
previous region is completed and the current region variables initialized (using
the same values as the case where no previous region existed above). The code 
then
falls through to populate the new region with the first page, hence the memcpy.

> > +            }
> > +        }
> > +        memcpy(&ctx->region_prev_page_data, page_data,
> > +               sizeof(ctx->region_prev_page_data));
> > +        ctx->region_last_index = ctx->current_header_index;
> > +        ctx->region_page_count++;
> > +    } else {
> > +        if (ctx->region_page_count > 0) {
> > +            if (qigvm_process_mem_region(
> > +                    ctx, ctx->region_start_index, ctx->region_start,
> > +                    ctx->region_page_count, 
> > &ctx->region_prev_page_data.flags,
> > +                    ctx->region_prev_page_data.data_type, errp) < 0) {
> > +                return -1;
> > +            }
> > +            ctx->region_page_count = 0;
> > +        }
> > +    }
> > +    return 0;
> > +}
> > +
> 

Reply via email to