xref: /openbmc/qemu/backends/igvm.c (revision b92b39af4219df4250f121f64d215506909c7404)
1c1d466d2SRoy Hopkins /*
2c1d466d2SRoy Hopkins  * QEMU IGVM configuration backend for guests
3c1d466d2SRoy Hopkins  *
4c1d466d2SRoy Hopkins  * Copyright (C) 2023-2024 SUSE
5c1d466d2SRoy Hopkins  *
6c1d466d2SRoy Hopkins  * Authors:
7c1d466d2SRoy Hopkins  *  Roy Hopkins <roy.hopkins@randomman.co.uk>
8c1d466d2SRoy Hopkins  *
9c1d466d2SRoy Hopkins  * SPDX-License-Identifier: GPL-2.0-or-later
10c1d466d2SRoy Hopkins  */
11c1d466d2SRoy Hopkins 
12c1d466d2SRoy Hopkins #include "qemu/osdep.h"
13c1d466d2SRoy Hopkins 
14c1d466d2SRoy Hopkins #include "igvm.h"
15c1d466d2SRoy Hopkins #include "qapi/error.h"
16c1d466d2SRoy Hopkins #include "system/memory.h"
17c1d466d2SRoy Hopkins #include "system/address-spaces.h"
18c1d466d2SRoy Hopkins #include "hw/core/cpu.h"
19c1d466d2SRoy Hopkins 
20c1d466d2SRoy Hopkins #include <igvm/igvm.h>
21c1d466d2SRoy Hopkins #include <igvm/igvm_defs.h>
22c1d466d2SRoy Hopkins 
23c1d466d2SRoy Hopkins typedef struct QIgvmParameterData {
24c1d466d2SRoy Hopkins     QTAILQ_ENTRY(QIgvmParameterData) next;
25c1d466d2SRoy Hopkins     uint8_t *data;
26c1d466d2SRoy Hopkins     uint32_t size;
27c1d466d2SRoy Hopkins     uint32_t index;
28c1d466d2SRoy Hopkins } QIgvmParameterData;
29c1d466d2SRoy Hopkins 
30c1d466d2SRoy Hopkins /*
31915b4707SRoy Hopkins  * Some directives are specific to particular confidential computing platforms.
32915b4707SRoy Hopkins  * Define required types for each of those platforms here.
33915b4707SRoy Hopkins  */
34915b4707SRoy Hopkins 
35915b4707SRoy Hopkins /* SEV/SEV-ES/SEV-SNP */
36915b4707SRoy Hopkins 
37915b4707SRoy Hopkins /*
38915b4707SRoy Hopkins  * These structures are defined in "SEV Secure Nested Paging Firmware ABI
39915b4707SRoy Hopkins  * Specification" Rev 1.58, section 8.18.
40915b4707SRoy Hopkins  */
41915b4707SRoy Hopkins struct QEMU_PACKED sev_id_block {
42915b4707SRoy Hopkins     uint8_t ld[48];
43915b4707SRoy Hopkins     uint8_t family_id[16];
44915b4707SRoy Hopkins     uint8_t image_id[16];
45915b4707SRoy Hopkins     uint32_t version;
46915b4707SRoy Hopkins     uint32_t guest_svn;
47915b4707SRoy Hopkins     uint64_t policy;
48915b4707SRoy Hopkins };
49915b4707SRoy Hopkins 
50915b4707SRoy Hopkins struct QEMU_PACKED sev_id_authentication {
51915b4707SRoy Hopkins     uint32_t id_key_alg;
52915b4707SRoy Hopkins     uint32_t auth_key_algo;
53915b4707SRoy Hopkins     uint8_t reserved[56];
54915b4707SRoy Hopkins     uint8_t id_block_sig[512];
55915b4707SRoy Hopkins     uint8_t id_key[1028];
56915b4707SRoy Hopkins     uint8_t reserved2[60];
57915b4707SRoy Hopkins     uint8_t id_key_sig[512];
58915b4707SRoy Hopkins     uint8_t author_key[1028];
59915b4707SRoy Hopkins     uint8_t reserved3[892];
60915b4707SRoy Hopkins };
61915b4707SRoy Hopkins 
62915b4707SRoy Hopkins #define IGVM_SEV_ID_BLOCK_VERSION 1
63915b4707SRoy Hopkins 
64915b4707SRoy Hopkins /*
65c1d466d2SRoy Hopkins  * QIgvm contains the information required during processing
66c1d466d2SRoy Hopkins  * of a single IGVM file.
67c1d466d2SRoy Hopkins  */
68c1d466d2SRoy Hopkins typedef struct QIgvm {
69c1d466d2SRoy Hopkins     IgvmHandle file;
70c1d466d2SRoy Hopkins     ConfidentialGuestSupport *cgs;
71c1d466d2SRoy Hopkins     ConfidentialGuestSupportClass *cgsc;
72c1d466d2SRoy Hopkins     uint32_t compatibility_mask;
73c1d466d2SRoy Hopkins     unsigned current_header_index;
74c1d466d2SRoy Hopkins     QTAILQ_HEAD(, QIgvmParameterData) parameter_data;
75915b4707SRoy Hopkins     IgvmPlatformType platform_type;
76915b4707SRoy Hopkins 
77915b4707SRoy Hopkins     /*
78915b4707SRoy Hopkins      * SEV-SNP platforms can contain an ID block and authentication
79915b4707SRoy Hopkins      * that should be verified by the guest.
80915b4707SRoy Hopkins      */
81915b4707SRoy Hopkins     struct sev_id_block *id_block;
82915b4707SRoy Hopkins     struct sev_id_authentication *id_auth;
83915b4707SRoy Hopkins 
84915b4707SRoy Hopkins     /* Define the guest policy for SEV guests */
85915b4707SRoy Hopkins     uint64_t sev_policy;
86c1d466d2SRoy Hopkins 
87c1d466d2SRoy Hopkins     /* These variables keep track of contiguous page regions */
88c1d466d2SRoy Hopkins     IGVM_VHS_PAGE_DATA region_prev_page_data;
89c1d466d2SRoy Hopkins     uint64_t region_start;
90c1d466d2SRoy Hopkins     unsigned region_start_index;
91c1d466d2SRoy Hopkins     unsigned region_last_index;
92c1d466d2SRoy Hopkins     unsigned region_page_count;
93c1d466d2SRoy Hopkins } QIgvm;
94c1d466d2SRoy Hopkins 
95c1d466d2SRoy Hopkins static int qigvm_directive_page_data(QIgvm *ctx, const uint8_t *header_data,
96c1d466d2SRoy Hopkins                                      Error **errp);
97c1d466d2SRoy Hopkins static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
98c1d466d2SRoy Hopkins                                       Error **errp);
99c1d466d2SRoy Hopkins static int qigvm_directive_parameter_area(QIgvm *ctx,
100c1d466d2SRoy Hopkins                                           const uint8_t *header_data,
101c1d466d2SRoy Hopkins                                           Error **errp);
102c1d466d2SRoy Hopkins static int qigvm_directive_parameter_insert(QIgvm *ctx,
103c1d466d2SRoy Hopkins                                             const uint8_t *header_data,
104c1d466d2SRoy Hopkins                                             Error **errp);
105c1d466d2SRoy Hopkins static int qigvm_directive_memory_map(QIgvm *ctx, const uint8_t *header_data,
106c1d466d2SRoy Hopkins                                       Error **errp);
107c1d466d2SRoy Hopkins static int qigvm_directive_vp_count(QIgvm *ctx, const uint8_t *header_data,
108c1d466d2SRoy Hopkins                                     Error **errp);
109c1d466d2SRoy Hopkins static int qigvm_directive_environment_info(QIgvm *ctx,
110c1d466d2SRoy Hopkins                                             const uint8_t *header_data,
111c1d466d2SRoy Hopkins                                             Error **errp);
112c1d466d2SRoy Hopkins static int qigvm_directive_required_memory(QIgvm *ctx,
113c1d466d2SRoy Hopkins                                            const uint8_t *header_data,
114c1d466d2SRoy Hopkins                                            Error **errp);
115915b4707SRoy Hopkins static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
116915b4707SRoy Hopkins                                   Error **errp);
117915b4707SRoy Hopkins static int qigvm_initialization_guest_policy(QIgvm *ctx,
118915b4707SRoy Hopkins                                        const uint8_t *header_data,
119915b4707SRoy Hopkins                                        Error **errp);
120c1d466d2SRoy Hopkins 
121c1d466d2SRoy Hopkins struct QIGVMHandler {
122c1d466d2SRoy Hopkins     uint32_t type;
123c1d466d2SRoy Hopkins     uint32_t section;
124c1d466d2SRoy Hopkins     int (*handler)(QIgvm *ctx, const uint8_t *header_data, Error **errp);
125c1d466d2SRoy Hopkins };
126c1d466d2SRoy Hopkins 
127c1d466d2SRoy Hopkins static struct QIGVMHandler handlers[] = {
128c1d466d2SRoy Hopkins     { IGVM_VHT_PAGE_DATA, IGVM_HEADER_SECTION_DIRECTIVE,
129c1d466d2SRoy Hopkins       qigvm_directive_page_data },
130c1d466d2SRoy Hopkins     { IGVM_VHT_VP_CONTEXT, IGVM_HEADER_SECTION_DIRECTIVE,
131c1d466d2SRoy Hopkins       qigvm_directive_vp_context },
132c1d466d2SRoy Hopkins     { IGVM_VHT_PARAMETER_AREA, IGVM_HEADER_SECTION_DIRECTIVE,
133c1d466d2SRoy Hopkins       qigvm_directive_parameter_area },
134c1d466d2SRoy Hopkins     { IGVM_VHT_PARAMETER_INSERT, IGVM_HEADER_SECTION_DIRECTIVE,
135c1d466d2SRoy Hopkins       qigvm_directive_parameter_insert },
136c1d466d2SRoy Hopkins     { IGVM_VHT_MEMORY_MAP, IGVM_HEADER_SECTION_DIRECTIVE,
137c1d466d2SRoy Hopkins       qigvm_directive_memory_map },
138c1d466d2SRoy Hopkins     { IGVM_VHT_VP_COUNT_PARAMETER, IGVM_HEADER_SECTION_DIRECTIVE,
139c1d466d2SRoy Hopkins       qigvm_directive_vp_count },
140c1d466d2SRoy Hopkins     { IGVM_VHT_ENVIRONMENT_INFO_PARAMETER, IGVM_HEADER_SECTION_DIRECTIVE,
141c1d466d2SRoy Hopkins       qigvm_directive_environment_info },
142c1d466d2SRoy Hopkins     { IGVM_VHT_REQUIRED_MEMORY, IGVM_HEADER_SECTION_DIRECTIVE,
143c1d466d2SRoy Hopkins       qigvm_directive_required_memory },
144915b4707SRoy Hopkins     { IGVM_VHT_SNP_ID_BLOCK, IGVM_HEADER_SECTION_DIRECTIVE,
145915b4707SRoy Hopkins       qigvm_directive_snp_id_block },
146915b4707SRoy Hopkins     { IGVM_VHT_GUEST_POLICY, IGVM_HEADER_SECTION_INITIALIZATION,
147915b4707SRoy Hopkins       qigvm_initialization_guest_policy },
148c1d466d2SRoy Hopkins };
149c1d466d2SRoy Hopkins 
qigvm_handler(QIgvm * ctx,uint32_t type,Error ** errp)150c1d466d2SRoy Hopkins static int qigvm_handler(QIgvm *ctx, uint32_t type, Error **errp)
151c1d466d2SRoy Hopkins {
152c1d466d2SRoy Hopkins     size_t handler;
153c1d466d2SRoy Hopkins     IgvmHandle header_handle;
154c1d466d2SRoy Hopkins     const uint8_t *header_data;
155c1d466d2SRoy Hopkins     int result;
156c1d466d2SRoy Hopkins 
157c1d466d2SRoy Hopkins     for (handler = 0; handler < G_N_ELEMENTS(handlers); handler++) {
158c1d466d2SRoy Hopkins         if (handlers[handler].type != type) {
159c1d466d2SRoy Hopkins             continue;
160c1d466d2SRoy Hopkins         }
161c1d466d2SRoy Hopkins         header_handle = igvm_get_header(ctx->file, handlers[handler].section,
162c1d466d2SRoy Hopkins                                         ctx->current_header_index);
163c1d466d2SRoy Hopkins         if (header_handle < 0) {
164c1d466d2SRoy Hopkins             error_setg(
165c1d466d2SRoy Hopkins                 errp,
166c1d466d2SRoy Hopkins                 "IGVM file is invalid: Failed to read directive header (code: %d)",
167c1d466d2SRoy Hopkins                 (int)header_handle);
168c1d466d2SRoy Hopkins             return -1;
169c1d466d2SRoy Hopkins         }
170c1d466d2SRoy Hopkins         header_data = igvm_get_buffer(ctx->file, header_handle) +
171c1d466d2SRoy Hopkins                       sizeof(IGVM_VHS_VARIABLE_HEADER);
172c1d466d2SRoy Hopkins         result = handlers[handler].handler(ctx, header_data, errp);
173c1d466d2SRoy Hopkins         igvm_free_buffer(ctx->file, header_handle);
174c1d466d2SRoy Hopkins         return result;
175c1d466d2SRoy Hopkins     }
176c1d466d2SRoy Hopkins     error_setg(errp,
177c1d466d2SRoy Hopkins                "IGVM: Unknown header type encountered when processing file: "
178c1d466d2SRoy Hopkins                "(type 0x%X)",
179c1d466d2SRoy Hopkins                type);
180c1d466d2SRoy Hopkins     return -1;
181c1d466d2SRoy Hopkins }
182c1d466d2SRoy Hopkins 
qigvm_prepare_memory(QIgvm * ctx,uint64_t addr,uint64_t size,int region_identifier,Error ** errp)183c1d466d2SRoy Hopkins static void *qigvm_prepare_memory(QIgvm *ctx, uint64_t addr, uint64_t size,
184c1d466d2SRoy Hopkins                                   int region_identifier, Error **errp)
185c1d466d2SRoy Hopkins {
186c1d466d2SRoy Hopkins     ERRP_GUARD();
187c1d466d2SRoy Hopkins     MemoryRegion *igvm_pages = NULL;
188c1d466d2SRoy Hopkins     Int128 gpa_region_size;
189c1d466d2SRoy Hopkins     MemoryRegionSection mrs =
190c1d466d2SRoy Hopkins         memory_region_find(get_system_memory(), addr, size);
191c1d466d2SRoy Hopkins     if (mrs.mr) {
192c1d466d2SRoy Hopkins         if (!memory_region_is_ram(mrs.mr)) {
193c1d466d2SRoy Hopkins             memory_region_unref(mrs.mr);
194c1d466d2SRoy Hopkins             error_setg(
195c1d466d2SRoy Hopkins                 errp,
196c1d466d2SRoy Hopkins                 "Processing of IGVM file failed: Could not prepare memory "
197c1d466d2SRoy Hopkins                 "at address 0x%lX due to existing non-RAM region",
198c1d466d2SRoy Hopkins                 addr);
199c1d466d2SRoy Hopkins             return NULL;
200c1d466d2SRoy Hopkins         }
201c1d466d2SRoy Hopkins 
202c1d466d2SRoy Hopkins         gpa_region_size = int128_make64(size);
203c1d466d2SRoy Hopkins         if (int128_lt(mrs.size, gpa_region_size)) {
204c1d466d2SRoy Hopkins             memory_region_unref(mrs.mr);
205c1d466d2SRoy Hopkins             error_setg(
206c1d466d2SRoy Hopkins                 errp,
207c1d466d2SRoy Hopkins                 "Processing of IGVM file failed: Could not prepare memory "
208c1d466d2SRoy Hopkins                 "at address 0x%lX: region size exceeded",
209c1d466d2SRoy Hopkins                 addr);
210c1d466d2SRoy Hopkins             return NULL;
211c1d466d2SRoy Hopkins         }
212c1d466d2SRoy Hopkins         return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
213c1d466d2SRoy Hopkins     } else {
214c1d466d2SRoy Hopkins         /*
215c1d466d2SRoy Hopkins          * The region_identifier is the is the index of the IGVM directive that
216c1d466d2SRoy Hopkins          * contains the page with the lowest GPA in the region. This will
217c1d466d2SRoy Hopkins          * generate a unique region name.
218c1d466d2SRoy Hopkins          */
219c1d466d2SRoy Hopkins         g_autofree char *region_name =
220c1d466d2SRoy Hopkins             g_strdup_printf("igvm.%X", region_identifier);
221c1d466d2SRoy Hopkins         igvm_pages = g_new0(MemoryRegion, 1);
222c1d466d2SRoy Hopkins         if (ctx->cgs && ctx->cgs->require_guest_memfd) {
223c1d466d2SRoy Hopkins             if (!memory_region_init_ram_guest_memfd(igvm_pages, NULL,
224c1d466d2SRoy Hopkins                                                     region_name, size, errp)) {
225c1d466d2SRoy Hopkins                 return NULL;
226c1d466d2SRoy Hopkins             }
227c1d466d2SRoy Hopkins         } else {
228c1d466d2SRoy Hopkins             if (!memory_region_init_ram(igvm_pages, NULL, region_name, size,
229c1d466d2SRoy Hopkins                                         errp)) {
230c1d466d2SRoy Hopkins                 return NULL;
231c1d466d2SRoy Hopkins             }
232c1d466d2SRoy Hopkins         }
233c1d466d2SRoy Hopkins         memory_region_add_subregion(get_system_memory(), addr, igvm_pages);
234c1d466d2SRoy Hopkins         return memory_region_get_ram_ptr(igvm_pages);
235c1d466d2SRoy Hopkins     }
236c1d466d2SRoy Hopkins }
237c1d466d2SRoy Hopkins 
qigvm_type_to_cgs_type(IgvmPageDataType memory_type,bool unmeasured,bool zero)238c1d466d2SRoy Hopkins static int qigvm_type_to_cgs_type(IgvmPageDataType memory_type, bool unmeasured,
239c1d466d2SRoy Hopkins                                   bool zero)
240c1d466d2SRoy Hopkins {
241c1d466d2SRoy Hopkins     switch (memory_type) {
242c1d466d2SRoy Hopkins     case IGVM_PAGE_DATA_TYPE_NORMAL: {
243c1d466d2SRoy Hopkins         if (unmeasured) {
244c1d466d2SRoy Hopkins             return CGS_PAGE_TYPE_UNMEASURED;
245c1d466d2SRoy Hopkins         } else {
246c1d466d2SRoy Hopkins             return zero ? CGS_PAGE_TYPE_ZERO : CGS_PAGE_TYPE_NORMAL;
247c1d466d2SRoy Hopkins         }
248c1d466d2SRoy Hopkins     }
249c1d466d2SRoy Hopkins     case IGVM_PAGE_DATA_TYPE_SECRETS:
250c1d466d2SRoy Hopkins         return CGS_PAGE_TYPE_SECRETS;
251c1d466d2SRoy Hopkins     case IGVM_PAGE_DATA_TYPE_CPUID_DATA:
252c1d466d2SRoy Hopkins         return CGS_PAGE_TYPE_CPUID;
253c1d466d2SRoy Hopkins     case IGVM_PAGE_DATA_TYPE_CPUID_XF:
254c1d466d2SRoy Hopkins         return CGS_PAGE_TYPE_CPUID;
255c1d466d2SRoy Hopkins     default:
256c1d466d2SRoy Hopkins         return -1;
257c1d466d2SRoy Hopkins     }
258c1d466d2SRoy Hopkins }
259c1d466d2SRoy Hopkins 
qigvm_page_attrs_equal(IgvmHandle igvm,unsigned header_index,const IGVM_VHS_PAGE_DATA * page_1,const IGVM_VHS_PAGE_DATA * page_2)260c1d466d2SRoy Hopkins static bool qigvm_page_attrs_equal(IgvmHandle igvm, unsigned header_index,
261c1d466d2SRoy Hopkins                                    const IGVM_VHS_PAGE_DATA *page_1,
262c1d466d2SRoy Hopkins                                    const IGVM_VHS_PAGE_DATA *page_2)
263c1d466d2SRoy Hopkins {
264c1d466d2SRoy Hopkins     IgvmHandle data_handle1, data_handle2;
265c1d466d2SRoy Hopkins 
266c1d466d2SRoy Hopkins     /*
267c1d466d2SRoy Hopkins      * If one page has data and the other doesn't then this results in different
268c1d466d2SRoy Hopkins      * page types: NORMAL vs ZERO.
269c1d466d2SRoy Hopkins      */
270c1d466d2SRoy Hopkins     data_handle1 = igvm_get_header_data(igvm, IGVM_HEADER_SECTION_DIRECTIVE,
271c1d466d2SRoy Hopkins                                         header_index - 1);
272c1d466d2SRoy Hopkins     data_handle2 =
273c1d466d2SRoy Hopkins         igvm_get_header_data(igvm, IGVM_HEADER_SECTION_DIRECTIVE, header_index);
274c1d466d2SRoy Hopkins     if ((data_handle1 == IGVMAPI_NO_DATA ||
275c1d466d2SRoy Hopkins          data_handle2 == IGVMAPI_NO_DATA) &&
276c1d466d2SRoy Hopkins          data_handle1 != data_handle2) {
277c1d466d2SRoy Hopkins         return false;
278c1d466d2SRoy Hopkins     }
279c1d466d2SRoy Hopkins     return ((*(const uint32_t *)&page_1->flags ==
280c1d466d2SRoy Hopkins              *(const uint32_t *)&page_2->flags) &&
281c1d466d2SRoy Hopkins             (page_1->data_type == page_2->data_type) &&
282c1d466d2SRoy Hopkins             (page_1->compatibility_mask == page_2->compatibility_mask));
283c1d466d2SRoy Hopkins }
284c1d466d2SRoy Hopkins 
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)285c1d466d2SRoy Hopkins static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index,
286c1d466d2SRoy Hopkins                                     uint64_t gpa_start, unsigned page_count,
287c1d466d2SRoy Hopkins                                     const IgvmPageDataFlags *flags,
288c1d466d2SRoy Hopkins                                     const IgvmPageDataType page_type,
289c1d466d2SRoy Hopkins                                     Error **errp)
290c1d466d2SRoy Hopkins {
291c1d466d2SRoy Hopkins     uint8_t *region;
292c1d466d2SRoy Hopkins     IgvmHandle data_handle;
293c1d466d2SRoy Hopkins     const void *data;
294c1d466d2SRoy Hopkins     uint32_t data_size;
295c1d466d2SRoy Hopkins     unsigned page_index;
296c1d466d2SRoy Hopkins     bool zero = true;
297c1d466d2SRoy Hopkins     const uint64_t page_size = flags->is_2mb_page ? 0x200000 : 0x1000;
298c1d466d2SRoy Hopkins     int result;
299c1d466d2SRoy Hopkins     int cgs_page_type;
300c1d466d2SRoy Hopkins 
301c1d466d2SRoy Hopkins     region = qigvm_prepare_memory(ctx, gpa_start, page_count * page_size,
302c1d466d2SRoy Hopkins                                   start_index, errp);
303c1d466d2SRoy Hopkins     if (!region) {
304c1d466d2SRoy Hopkins         return -1;
305c1d466d2SRoy Hopkins     }
306c1d466d2SRoy Hopkins 
307c1d466d2SRoy Hopkins     for (page_index = 0; page_index < page_count; page_index++) {
308c1d466d2SRoy Hopkins         data_handle = igvm_get_header_data(
309c1d466d2SRoy Hopkins             ctx->file, IGVM_HEADER_SECTION_DIRECTIVE, page_index + start_index);
310c1d466d2SRoy Hopkins         if (data_handle == IGVMAPI_NO_DATA) {
311c1d466d2SRoy Hopkins             /* No data indicates a zero page */
312c1d466d2SRoy Hopkins             memset(&region[page_index * page_size], 0, page_size);
313c1d466d2SRoy Hopkins         } else if (data_handle < 0) {
314c1d466d2SRoy Hopkins             error_setg(
315c1d466d2SRoy Hopkins                 errp,
316c1d466d2SRoy Hopkins                 "IGVM file contains invalid page data for directive with "
317c1d466d2SRoy Hopkins                 "index %d",
318c1d466d2SRoy Hopkins                 page_index + start_index);
319c1d466d2SRoy Hopkins             return -1;
320c1d466d2SRoy Hopkins         } else {
321c1d466d2SRoy Hopkins             zero = false;
322c1d466d2SRoy Hopkins             data_size = igvm_get_buffer_size(ctx->file, data_handle);
323c1d466d2SRoy Hopkins             if (data_size < page_size) {
324c1d466d2SRoy Hopkins                 memset(&region[page_index * page_size], 0, page_size);
325c1d466d2SRoy Hopkins             } else if (data_size > page_size) {
326c1d466d2SRoy Hopkins                 error_setg(errp,
327c1d466d2SRoy Hopkins                            "IGVM file contains page data with invalid size for "
328c1d466d2SRoy Hopkins                            "directive with index %d",
329c1d466d2SRoy Hopkins                            page_index + start_index);
330c1d466d2SRoy Hopkins                 return -1;
331c1d466d2SRoy Hopkins             }
332c1d466d2SRoy Hopkins             data = igvm_get_buffer(ctx->file, data_handle);
333c1d466d2SRoy Hopkins             memcpy(&region[page_index * page_size], data, data_size);
334c1d466d2SRoy Hopkins             igvm_free_buffer(ctx->file, data_handle);
335c1d466d2SRoy Hopkins         }
336c1d466d2SRoy Hopkins     }
337c1d466d2SRoy Hopkins 
338c1d466d2SRoy Hopkins     /*
339c1d466d2SRoy Hopkins      * If a confidential guest support object is provided then use it to set the
340c1d466d2SRoy Hopkins      * guest state.
341c1d466d2SRoy Hopkins      */
342c1d466d2SRoy Hopkins     if (ctx->cgs) {
343c1d466d2SRoy Hopkins         cgs_page_type =
344c1d466d2SRoy Hopkins             qigvm_type_to_cgs_type(page_type, flags->unmeasured, zero);
345c1d466d2SRoy Hopkins         if (cgs_page_type < 0) {
346c1d466d2SRoy Hopkins             error_setg(errp,
347c1d466d2SRoy Hopkins                        "Invalid page type in IGVM file. Directives: %d to %d, "
348c1d466d2SRoy Hopkins                        "page type: %d",
349c1d466d2SRoy Hopkins                        start_index, start_index + page_count, page_type);
350c1d466d2SRoy Hopkins             return -1;
351c1d466d2SRoy Hopkins         }
352c1d466d2SRoy Hopkins 
353c1d466d2SRoy Hopkins         result = ctx->cgsc->set_guest_state(
354c1d466d2SRoy Hopkins             gpa_start, region, page_size * page_count, cgs_page_type, 0, errp);
355c1d466d2SRoy Hopkins         if (result < 0) {
356c1d466d2SRoy Hopkins             return result;
357c1d466d2SRoy Hopkins         }
358c1d466d2SRoy Hopkins     }
359c1d466d2SRoy Hopkins     return 0;
360c1d466d2SRoy Hopkins }
361c1d466d2SRoy Hopkins 
qigvm_process_mem_page(QIgvm * ctx,const IGVM_VHS_PAGE_DATA * page_data,Error ** errp)362c1d466d2SRoy Hopkins static int qigvm_process_mem_page(QIgvm *ctx,
363c1d466d2SRoy Hopkins                                   const IGVM_VHS_PAGE_DATA *page_data,
364c1d466d2SRoy Hopkins                                   Error **errp)
365c1d466d2SRoy Hopkins {
366c1d466d2SRoy Hopkins     if (page_data) {
367c1d466d2SRoy Hopkins         if (ctx->region_page_count == 0) {
368c1d466d2SRoy Hopkins             ctx->region_start = page_data->gpa;
369c1d466d2SRoy Hopkins             ctx->region_start_index = ctx->current_header_index;
370c1d466d2SRoy Hopkins         } else {
371c1d466d2SRoy Hopkins             if (!qigvm_page_attrs_equal(ctx->file, ctx->current_header_index,
372c1d466d2SRoy Hopkins                                         page_data,
373c1d466d2SRoy Hopkins                                         &ctx->region_prev_page_data) ||
374c1d466d2SRoy Hopkins                 ((ctx->region_prev_page_data.gpa +
375c1d466d2SRoy Hopkins                   (ctx->region_prev_page_data.flags.is_2mb_page ? 0x200000 :
376c1d466d2SRoy Hopkins                                                                   0x1000)) !=
377c1d466d2SRoy Hopkins                  page_data->gpa) ||
378c1d466d2SRoy Hopkins                 (ctx->region_last_index != (ctx->current_header_index - 1))) {
379c1d466d2SRoy Hopkins                 /* End of current region */
380c1d466d2SRoy Hopkins                 if (qigvm_process_mem_region(
381c1d466d2SRoy Hopkins                         ctx, ctx->region_start_index, ctx->region_start,
382c1d466d2SRoy Hopkins                         ctx->region_page_count,
383c1d466d2SRoy Hopkins                         &ctx->region_prev_page_data.flags,
384c1d466d2SRoy Hopkins                         ctx->region_prev_page_data.data_type, errp) < 0) {
385c1d466d2SRoy Hopkins                     return -1;
386c1d466d2SRoy Hopkins                 }
387c1d466d2SRoy Hopkins                 ctx->region_page_count = 0;
388c1d466d2SRoy Hopkins                 ctx->region_start = page_data->gpa;
389c1d466d2SRoy Hopkins                 ctx->region_start_index = ctx->current_header_index;
390c1d466d2SRoy Hopkins             }
391c1d466d2SRoy Hopkins         }
392c1d466d2SRoy Hopkins         memcpy(&ctx->region_prev_page_data, page_data,
393c1d466d2SRoy Hopkins                sizeof(ctx->region_prev_page_data));
394c1d466d2SRoy Hopkins         ctx->region_last_index = ctx->current_header_index;
395c1d466d2SRoy Hopkins         ctx->region_page_count++;
396c1d466d2SRoy Hopkins     } else {
397c1d466d2SRoy Hopkins         if (ctx->region_page_count > 0) {
398c1d466d2SRoy Hopkins             if (qigvm_process_mem_region(
399c1d466d2SRoy Hopkins                     ctx, ctx->region_start_index, ctx->region_start,
400c1d466d2SRoy Hopkins                     ctx->region_page_count, &ctx->region_prev_page_data.flags,
401c1d466d2SRoy Hopkins                     ctx->region_prev_page_data.data_type, errp) < 0) {
402c1d466d2SRoy Hopkins                 return -1;
403c1d466d2SRoy Hopkins             }
404c1d466d2SRoy Hopkins             ctx->region_page_count = 0;
405c1d466d2SRoy Hopkins         }
406c1d466d2SRoy Hopkins     }
407c1d466d2SRoy Hopkins     return 0;
408c1d466d2SRoy Hopkins }
409c1d466d2SRoy Hopkins 
qigvm_directive_page_data(QIgvm * ctx,const uint8_t * header_data,Error ** errp)410c1d466d2SRoy Hopkins static int qigvm_directive_page_data(QIgvm *ctx, const uint8_t *header_data,
411c1d466d2SRoy Hopkins                                      Error **errp)
412c1d466d2SRoy Hopkins {
413c1d466d2SRoy Hopkins     const IGVM_VHS_PAGE_DATA *page_data =
414c1d466d2SRoy Hopkins         (const IGVM_VHS_PAGE_DATA *)header_data;
415c1d466d2SRoy Hopkins     if (page_data->compatibility_mask & ctx->compatibility_mask) {
416c1d466d2SRoy Hopkins         return qigvm_process_mem_page(ctx, page_data, errp);
417c1d466d2SRoy Hopkins     }
418c1d466d2SRoy Hopkins     return 0;
419c1d466d2SRoy Hopkins }
420c1d466d2SRoy Hopkins 
qigvm_directive_vp_context(QIgvm * ctx,const uint8_t * header_data,Error ** errp)421c1d466d2SRoy Hopkins static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
422c1d466d2SRoy Hopkins                                       Error **errp)
423c1d466d2SRoy Hopkins {
424c1d466d2SRoy Hopkins     const IGVM_VHS_VP_CONTEXT *vp_context =
425c1d466d2SRoy Hopkins         (const IGVM_VHS_VP_CONTEXT *)header_data;
426c1d466d2SRoy Hopkins     IgvmHandle data_handle;
427c1d466d2SRoy Hopkins     uint8_t *data;
428c1d466d2SRoy Hopkins     int result;
429c1d466d2SRoy Hopkins 
430c1d466d2SRoy Hopkins     if (!(vp_context->compatibility_mask & ctx->compatibility_mask)) {
431c1d466d2SRoy Hopkins         return 0;
432c1d466d2SRoy Hopkins     }
433c1d466d2SRoy Hopkins 
434c1d466d2SRoy Hopkins     /*
435c1d466d2SRoy Hopkins      * A confidential guest support object must be provided for setting
436c1d466d2SRoy Hopkins      * a VP context.
437c1d466d2SRoy Hopkins      */
438c1d466d2SRoy Hopkins     if (!ctx->cgs) {
439c1d466d2SRoy Hopkins         error_setg(
440c1d466d2SRoy Hopkins             errp,
441c1d466d2SRoy Hopkins             "A VP context is present in the IGVM file but is not supported "
442c1d466d2SRoy Hopkins             "by the current system.");
443c1d466d2SRoy Hopkins         return -1;
444c1d466d2SRoy Hopkins     }
445c1d466d2SRoy Hopkins 
446c1d466d2SRoy Hopkins     data_handle = igvm_get_header_data(ctx->file, IGVM_HEADER_SECTION_DIRECTIVE,
447c1d466d2SRoy Hopkins                                        ctx->current_header_index);
448c1d466d2SRoy Hopkins     if (data_handle < 0) {
449c1d466d2SRoy Hopkins         error_setg(errp, "Invalid VP context in IGVM file. Error code: %X",
450c1d466d2SRoy Hopkins                    data_handle);
451c1d466d2SRoy Hopkins         return -1;
452c1d466d2SRoy Hopkins     }
453c1d466d2SRoy Hopkins 
454c1d466d2SRoy Hopkins     data = (uint8_t *)igvm_get_buffer(ctx->file, data_handle);
455c1d466d2SRoy Hopkins     result = ctx->cgsc->set_guest_state(
456c1d466d2SRoy Hopkins         vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle),
457c1d466d2SRoy Hopkins         CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp);
458c1d466d2SRoy Hopkins     igvm_free_buffer(ctx->file, data_handle);
459c1d466d2SRoy Hopkins     if (result < 0) {
460c1d466d2SRoy Hopkins         return result;
461c1d466d2SRoy Hopkins     }
462c1d466d2SRoy Hopkins     return 0;
463c1d466d2SRoy Hopkins }
464c1d466d2SRoy Hopkins 
qigvm_directive_parameter_area(QIgvm * ctx,const uint8_t * header_data,Error ** errp)465c1d466d2SRoy Hopkins static int qigvm_directive_parameter_area(QIgvm *ctx,
466c1d466d2SRoy Hopkins                                           const uint8_t *header_data,
467c1d466d2SRoy Hopkins                                           Error **errp)
468c1d466d2SRoy Hopkins {
469c1d466d2SRoy Hopkins     const IGVM_VHS_PARAMETER_AREA *param_area =
470c1d466d2SRoy Hopkins         (const IGVM_VHS_PARAMETER_AREA *)header_data;
471c1d466d2SRoy Hopkins     QIgvmParameterData *param_entry;
472c1d466d2SRoy Hopkins 
473c1d466d2SRoy Hopkins     param_entry = g_new0(QIgvmParameterData, 1);
474c1d466d2SRoy Hopkins     param_entry->size = param_area->number_of_bytes;
475c1d466d2SRoy Hopkins     param_entry->index = param_area->parameter_area_index;
476c1d466d2SRoy Hopkins     param_entry->data = g_malloc0(param_entry->size);
477c1d466d2SRoy Hopkins 
478c1d466d2SRoy Hopkins     QTAILQ_INSERT_TAIL(&ctx->parameter_data, param_entry, next);
479c1d466d2SRoy Hopkins     return 0;
480c1d466d2SRoy Hopkins }
481c1d466d2SRoy Hopkins 
qigvm_directive_parameter_insert(QIgvm * ctx,const uint8_t * header_data,Error ** errp)482c1d466d2SRoy Hopkins static int qigvm_directive_parameter_insert(QIgvm *ctx,
483c1d466d2SRoy Hopkins                                             const uint8_t *header_data,
484c1d466d2SRoy Hopkins                                             Error **errp)
485c1d466d2SRoy Hopkins {
486c1d466d2SRoy Hopkins     const IGVM_VHS_PARAMETER_INSERT *param =
487c1d466d2SRoy Hopkins         (const IGVM_VHS_PARAMETER_INSERT *)header_data;
488c1d466d2SRoy Hopkins     QIgvmParameterData *param_entry;
489c1d466d2SRoy Hopkins     int result;
490c1d466d2SRoy Hopkins     void *region;
491c1d466d2SRoy Hopkins 
492c1d466d2SRoy Hopkins     if (!(param->compatibility_mask & ctx->compatibility_mask)) {
493c1d466d2SRoy Hopkins         return 0;
494c1d466d2SRoy Hopkins     }
495c1d466d2SRoy Hopkins 
496c1d466d2SRoy Hopkins     QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
497c1d466d2SRoy Hopkins     {
498c1d466d2SRoy Hopkins         if (param_entry->index == param->parameter_area_index) {
499c1d466d2SRoy Hopkins             region = qigvm_prepare_memory(ctx, param->gpa, param_entry->size,
500c1d466d2SRoy Hopkins                                           ctx->current_header_index, errp);
501c1d466d2SRoy Hopkins             if (!region) {
502c1d466d2SRoy Hopkins                 return -1;
503c1d466d2SRoy Hopkins             }
504c1d466d2SRoy Hopkins             memcpy(region, param_entry->data, param_entry->size);
505c1d466d2SRoy Hopkins             g_free(param_entry->data);
506c1d466d2SRoy Hopkins             param_entry->data = NULL;
507c1d466d2SRoy Hopkins 
508c1d466d2SRoy Hopkins             /*
509c1d466d2SRoy Hopkins              * If a confidential guest support object is provided then use it to
510c1d466d2SRoy Hopkins              * set the guest state.
511c1d466d2SRoy Hopkins              */
512c1d466d2SRoy Hopkins             if (ctx->cgs) {
513c1d466d2SRoy Hopkins                 result = ctx->cgsc->set_guest_state(param->gpa, region,
514c1d466d2SRoy Hopkins                                                     param_entry->size,
515c1d466d2SRoy Hopkins                                                     CGS_PAGE_TYPE_UNMEASURED, 0,
516c1d466d2SRoy Hopkins                                                     errp);
517c1d466d2SRoy Hopkins                 if (result < 0) {
518c1d466d2SRoy Hopkins                     return -1;
519c1d466d2SRoy Hopkins                 }
520c1d466d2SRoy Hopkins             }
521c1d466d2SRoy Hopkins         }
522c1d466d2SRoy Hopkins     }
523c1d466d2SRoy Hopkins     return 0;
524c1d466d2SRoy Hopkins }
525c1d466d2SRoy Hopkins 
qigvm_cmp_mm_entry(const void * a,const void * b)526c1d466d2SRoy Hopkins static int qigvm_cmp_mm_entry(const void *a, const void *b)
527c1d466d2SRoy Hopkins {
528c1d466d2SRoy Hopkins     const IGVM_VHS_MEMORY_MAP_ENTRY *entry_a =
529c1d466d2SRoy Hopkins         (const IGVM_VHS_MEMORY_MAP_ENTRY *)a;
530c1d466d2SRoy Hopkins     const IGVM_VHS_MEMORY_MAP_ENTRY *entry_b =
531c1d466d2SRoy Hopkins         (const IGVM_VHS_MEMORY_MAP_ENTRY *)b;
532c1d466d2SRoy Hopkins     if (entry_a->starting_gpa_page_number < entry_b->starting_gpa_page_number) {
533c1d466d2SRoy Hopkins         return -1;
534c1d466d2SRoy Hopkins     } else if (entry_a->starting_gpa_page_number >
535c1d466d2SRoy Hopkins                entry_b->starting_gpa_page_number) {
536c1d466d2SRoy Hopkins         return 1;
537c1d466d2SRoy Hopkins     } else {
538c1d466d2SRoy Hopkins         return 0;
539c1d466d2SRoy Hopkins     }
540c1d466d2SRoy Hopkins }
541c1d466d2SRoy Hopkins 
qigvm_directive_memory_map(QIgvm * ctx,const uint8_t * header_data,Error ** errp)542c1d466d2SRoy Hopkins static int qigvm_directive_memory_map(QIgvm *ctx, const uint8_t *header_data,
543c1d466d2SRoy Hopkins                                       Error **errp)
544c1d466d2SRoy Hopkins {
545c1d466d2SRoy Hopkins     const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
546c1d466d2SRoy Hopkins     QIgvmParameterData *param_entry;
547c1d466d2SRoy Hopkins     int max_entry_count;
548c1d466d2SRoy Hopkins     int entry = 0;
549c1d466d2SRoy Hopkins     IGVM_VHS_MEMORY_MAP_ENTRY *mm_entry;
550c1d466d2SRoy Hopkins     ConfidentialGuestMemoryMapEntry cgmm_entry;
551c1d466d2SRoy Hopkins     int retval = 0;
552c1d466d2SRoy Hopkins 
553c1d466d2SRoy Hopkins     if (!ctx->cgs) {
554c1d466d2SRoy Hopkins         error_setg(errp,
555c1d466d2SRoy Hopkins                    "IGVM file contains a memory map but this is not supported "
556c1d466d2SRoy Hopkins                    "by the current system.");
557c1d466d2SRoy Hopkins         return -1;
558c1d466d2SRoy Hopkins     }
559c1d466d2SRoy Hopkins 
560c1d466d2SRoy Hopkins     /* Find the parameter area that should hold the memory map */
561c1d466d2SRoy Hopkins     QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
562c1d466d2SRoy Hopkins     {
563c1d466d2SRoy Hopkins         if (param_entry->index == param->parameter_area_index) {
564c1d466d2SRoy Hopkins             max_entry_count =
565c1d466d2SRoy Hopkins                 param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY);
566c1d466d2SRoy Hopkins             mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data;
567c1d466d2SRoy Hopkins 
568c1d466d2SRoy Hopkins             retval = ctx->cgsc->get_mem_map_entry(entry, &cgmm_entry, errp);
569c1d466d2SRoy Hopkins             while (retval == 0) {
570c1d466d2SRoy Hopkins                 if (entry > max_entry_count) {
571c1d466d2SRoy Hopkins                     error_setg(
572c1d466d2SRoy Hopkins                         errp,
573c1d466d2SRoy Hopkins                         "IGVM: guest memory map size exceeds parameter area defined in IGVM file");
574c1d466d2SRoy Hopkins                     return -1;
575c1d466d2SRoy Hopkins                 }
576c1d466d2SRoy Hopkins                 mm_entry[entry].starting_gpa_page_number = cgmm_entry.gpa >> 12;
577c1d466d2SRoy Hopkins                 mm_entry[entry].number_of_pages = cgmm_entry.size >> 12;
578c1d466d2SRoy Hopkins 
579c1d466d2SRoy Hopkins                 switch (cgmm_entry.type) {
580c1d466d2SRoy Hopkins                 case CGS_MEM_RAM:
581c1d466d2SRoy Hopkins                     mm_entry[entry].entry_type =
582c1d466d2SRoy Hopkins                         IGVM_MEMORY_MAP_ENTRY_TYPE_MEMORY;
583c1d466d2SRoy Hopkins                     break;
584c1d466d2SRoy Hopkins                 case CGS_MEM_RESERVED:
585c1d466d2SRoy Hopkins                     mm_entry[entry].entry_type =
586c1d466d2SRoy Hopkins                         IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
587c1d466d2SRoy Hopkins                     break;
588c1d466d2SRoy Hopkins                 case CGS_MEM_ACPI:
589c1d466d2SRoy Hopkins                     mm_entry[entry].entry_type =
590c1d466d2SRoy Hopkins                         IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
591c1d466d2SRoy Hopkins                     break;
592c1d466d2SRoy Hopkins                 case CGS_MEM_NVS:
593c1d466d2SRoy Hopkins                     mm_entry[entry].entry_type =
594c1d466d2SRoy Hopkins                         IGVM_MEMORY_MAP_ENTRY_TYPE_PERSISTENT;
595c1d466d2SRoy Hopkins                     break;
596c1d466d2SRoy Hopkins                 case CGS_MEM_UNUSABLE:
597c1d466d2SRoy Hopkins                     mm_entry[entry].entry_type =
598c1d466d2SRoy Hopkins                         IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
599c1d466d2SRoy Hopkins                     break;
600c1d466d2SRoy Hopkins                 }
601c1d466d2SRoy Hopkins                 retval =
602c1d466d2SRoy Hopkins                     ctx->cgsc->get_mem_map_entry(++entry, &cgmm_entry, errp);
603c1d466d2SRoy Hopkins             }
604c1d466d2SRoy Hopkins             if (retval < 0) {
605c1d466d2SRoy Hopkins                 return retval;
606c1d466d2SRoy Hopkins             }
607c1d466d2SRoy Hopkins             /* The entries need to be sorted */
608c1d466d2SRoy Hopkins             qsort(mm_entry, entry, sizeof(IGVM_VHS_MEMORY_MAP_ENTRY),
609c1d466d2SRoy Hopkins                   qigvm_cmp_mm_entry);
610c1d466d2SRoy Hopkins 
611c1d466d2SRoy Hopkins             break;
612c1d466d2SRoy Hopkins         }
613c1d466d2SRoy Hopkins     }
614c1d466d2SRoy Hopkins     return 0;
615c1d466d2SRoy Hopkins }
616c1d466d2SRoy Hopkins 
qigvm_directive_vp_count(QIgvm * ctx,const uint8_t * header_data,Error ** errp)617c1d466d2SRoy Hopkins static int qigvm_directive_vp_count(QIgvm *ctx, const uint8_t *header_data,
618c1d466d2SRoy Hopkins                                     Error **errp)
619c1d466d2SRoy Hopkins {
620c1d466d2SRoy Hopkins     const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
621c1d466d2SRoy Hopkins     QIgvmParameterData *param_entry;
622c1d466d2SRoy Hopkins     uint32_t *vp_count;
623c1d466d2SRoy Hopkins     CPUState *cpu;
624c1d466d2SRoy Hopkins 
625c1d466d2SRoy Hopkins     QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
626c1d466d2SRoy Hopkins     {
627c1d466d2SRoy Hopkins         if (param_entry->index == param->parameter_area_index) {
628c1d466d2SRoy Hopkins             vp_count = (uint32_t *)(param_entry->data + param->byte_offset);
629c1d466d2SRoy Hopkins             *vp_count = 0;
630c1d466d2SRoy Hopkins             CPU_FOREACH(cpu)
631c1d466d2SRoy Hopkins             {
632c1d466d2SRoy Hopkins                 (*vp_count)++;
633c1d466d2SRoy Hopkins             }
634c1d466d2SRoy Hopkins             break;
635c1d466d2SRoy Hopkins         }
636c1d466d2SRoy Hopkins     }
637c1d466d2SRoy Hopkins     return 0;
638c1d466d2SRoy Hopkins }
639c1d466d2SRoy Hopkins 
qigvm_directive_environment_info(QIgvm * ctx,const uint8_t * header_data,Error ** errp)640c1d466d2SRoy Hopkins static int qigvm_directive_environment_info(QIgvm *ctx,
641c1d466d2SRoy Hopkins                                             const uint8_t *header_data,
642c1d466d2SRoy Hopkins                                             Error **errp)
643c1d466d2SRoy Hopkins {
644c1d466d2SRoy Hopkins     const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
645c1d466d2SRoy Hopkins     QIgvmParameterData *param_entry;
646c1d466d2SRoy Hopkins     IgvmEnvironmentInfo *environmental_state;
647c1d466d2SRoy Hopkins 
648c1d466d2SRoy Hopkins     QTAILQ_FOREACH(param_entry, &ctx->parameter_data, next)
649c1d466d2SRoy Hopkins     {
650c1d466d2SRoy Hopkins         if (param_entry->index == param->parameter_area_index) {
651c1d466d2SRoy Hopkins             environmental_state =
652c1d466d2SRoy Hopkins                 (IgvmEnvironmentInfo *)(param_entry->data + param->byte_offset);
653c1d466d2SRoy Hopkins             environmental_state->memory_is_shared = 1;
654c1d466d2SRoy Hopkins             break;
655c1d466d2SRoy Hopkins         }
656c1d466d2SRoy Hopkins     }
657c1d466d2SRoy Hopkins     return 0;
658c1d466d2SRoy Hopkins }
659c1d466d2SRoy Hopkins 
qigvm_directive_required_memory(QIgvm * ctx,const uint8_t * header_data,Error ** errp)660c1d466d2SRoy Hopkins static int qigvm_directive_required_memory(QIgvm *ctx,
661c1d466d2SRoy Hopkins                                            const uint8_t *header_data,
662c1d466d2SRoy Hopkins                                            Error **errp)
663c1d466d2SRoy Hopkins {
664c1d466d2SRoy Hopkins     const IGVM_VHS_REQUIRED_MEMORY *mem =
665c1d466d2SRoy Hopkins         (const IGVM_VHS_REQUIRED_MEMORY *)header_data;
666c1d466d2SRoy Hopkins     uint8_t *region;
667c1d466d2SRoy Hopkins     int result;
668c1d466d2SRoy Hopkins 
669c1d466d2SRoy Hopkins     if (!(mem->compatibility_mask & ctx->compatibility_mask)) {
670c1d466d2SRoy Hopkins         return 0;
671c1d466d2SRoy Hopkins     }
672c1d466d2SRoy Hopkins 
673c1d466d2SRoy Hopkins     region = qigvm_prepare_memory(ctx, mem->gpa, mem->number_of_bytes,
674c1d466d2SRoy Hopkins                                   ctx->current_header_index, errp);
675c1d466d2SRoy Hopkins     if (!region) {
676c1d466d2SRoy Hopkins         return -1;
677c1d466d2SRoy Hopkins     }
678c1d466d2SRoy Hopkins     if (ctx->cgs) {
679c1d466d2SRoy Hopkins         result =
680c1d466d2SRoy Hopkins             ctx->cgsc->set_guest_state(mem->gpa, region, mem->number_of_bytes,
681c1d466d2SRoy Hopkins                                        CGS_PAGE_TYPE_REQUIRED_MEMORY, 0, errp);
682c1d466d2SRoy Hopkins         if (result < 0) {
683c1d466d2SRoy Hopkins             return result;
684c1d466d2SRoy Hopkins         }
685c1d466d2SRoy Hopkins     }
686c1d466d2SRoy Hopkins     return 0;
687c1d466d2SRoy Hopkins }
688c1d466d2SRoy Hopkins 
qigvm_directive_snp_id_block(QIgvm * ctx,const uint8_t * header_data,Error ** errp)689915b4707SRoy Hopkins static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
690915b4707SRoy Hopkins                                   Error **errp)
691915b4707SRoy Hopkins {
692915b4707SRoy Hopkins     const IGVM_VHS_SNP_ID_BLOCK *igvm_id =
693915b4707SRoy Hopkins         (const IGVM_VHS_SNP_ID_BLOCK *)header_data;
694915b4707SRoy Hopkins 
695915b4707SRoy Hopkins     if (!(igvm_id->compatibility_mask & ctx->compatibility_mask)) {
696915b4707SRoy Hopkins         return 0;
697915b4707SRoy Hopkins     }
698915b4707SRoy Hopkins 
699915b4707SRoy Hopkins     if (ctx->id_block) {
700915b4707SRoy Hopkins         error_setg(errp, "IGVM: Multiple ID blocks encountered "
701915b4707SRoy Hopkins                             "in IGVM file.");
702915b4707SRoy Hopkins         return -1;
703915b4707SRoy Hopkins     }
704915b4707SRoy Hopkins     ctx->id_block = g_new0(struct sev_id_block, 1);
705915b4707SRoy Hopkins     ctx->id_auth = g_new0(struct sev_id_authentication, 1);
706915b4707SRoy Hopkins 
707915b4707SRoy Hopkins     memcpy(ctx->id_block->family_id, igvm_id->family_id,
708915b4707SRoy Hopkins             sizeof(ctx->id_block->family_id));
709915b4707SRoy Hopkins     memcpy(ctx->id_block->image_id, igvm_id->image_id,
710915b4707SRoy Hopkins             sizeof(ctx->id_block->image_id));
711915b4707SRoy Hopkins     ctx->id_block->guest_svn = igvm_id->guest_svn;
712915b4707SRoy Hopkins     ctx->id_block->version = IGVM_SEV_ID_BLOCK_VERSION;
713915b4707SRoy Hopkins     memcpy(ctx->id_block->ld, igvm_id->ld, sizeof(ctx->id_block->ld));
714915b4707SRoy Hopkins 
715915b4707SRoy Hopkins     ctx->id_auth->id_key_alg = igvm_id->id_key_algorithm;
716915b4707SRoy Hopkins     assert(sizeof(igvm_id->id_key_signature) <=
717915b4707SRoy Hopkins            sizeof(ctx->id_auth->id_block_sig));
718915b4707SRoy Hopkins     memcpy(ctx->id_auth->id_block_sig, &igvm_id->id_key_signature,
719915b4707SRoy Hopkins            sizeof(igvm_id->id_key_signature));
720915b4707SRoy Hopkins 
721915b4707SRoy Hopkins     ctx->id_auth->auth_key_algo = igvm_id->author_key_algorithm;
722915b4707SRoy Hopkins     assert(sizeof(igvm_id->author_key_signature) <=
723915b4707SRoy Hopkins            sizeof(ctx->id_auth->id_key_sig));
724915b4707SRoy Hopkins     memcpy(ctx->id_auth->id_key_sig, &igvm_id->author_key_signature,
725915b4707SRoy Hopkins            sizeof(igvm_id->author_key_signature));
726915b4707SRoy Hopkins 
727915b4707SRoy Hopkins     /*
728915b4707SRoy Hopkins      * SEV and IGVM public key structure population are slightly different.
729915b4707SRoy Hopkins      * See SEV Secure Nested Paging Firmware ABI Specification, Chapter 10.
730915b4707SRoy Hopkins      */
731915b4707SRoy Hopkins     *((uint32_t *)ctx->id_auth->id_key) = igvm_id->id_public_key.curve;
732915b4707SRoy Hopkins     memcpy(&ctx->id_auth->id_key[4], &igvm_id->id_public_key.qx, 72);
733915b4707SRoy Hopkins     memcpy(&ctx->id_auth->id_key[76], &igvm_id->id_public_key.qy, 72);
734915b4707SRoy Hopkins 
735915b4707SRoy Hopkins     *((uint32_t *)ctx->id_auth->author_key) =
736915b4707SRoy Hopkins         igvm_id->author_public_key.curve;
737915b4707SRoy Hopkins     memcpy(&ctx->id_auth->author_key[4], &igvm_id->author_public_key.qx,
738915b4707SRoy Hopkins             72);
739915b4707SRoy Hopkins     memcpy(&ctx->id_auth->author_key[76], &igvm_id->author_public_key.qy,
740915b4707SRoy Hopkins             72);
741915b4707SRoy Hopkins 
742915b4707SRoy Hopkins     return 0;
743915b4707SRoy Hopkins }
744915b4707SRoy Hopkins 
qigvm_initialization_guest_policy(QIgvm * ctx,const uint8_t * header_data,Error ** errp)745915b4707SRoy Hopkins static int qigvm_initialization_guest_policy(QIgvm *ctx,
746915b4707SRoy Hopkins                                        const uint8_t *header_data, Error **errp)
747915b4707SRoy Hopkins {
748915b4707SRoy Hopkins     const IGVM_VHS_GUEST_POLICY *guest =
749915b4707SRoy Hopkins         (const IGVM_VHS_GUEST_POLICY *)header_data;
750915b4707SRoy Hopkins 
751915b4707SRoy Hopkins     if (guest->compatibility_mask & ctx->compatibility_mask) {
752915b4707SRoy Hopkins         ctx->sev_policy = guest->policy;
753915b4707SRoy Hopkins     }
754915b4707SRoy Hopkins     return 0;
755915b4707SRoy Hopkins }
756915b4707SRoy Hopkins 
qigvm_supported_platform_compat_mask(QIgvm * ctx,Error ** errp)757c1d466d2SRoy Hopkins static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
758c1d466d2SRoy Hopkins {
759c1d466d2SRoy Hopkins     int32_t header_count;
760c1d466d2SRoy Hopkins     unsigned header_index;
761c1d466d2SRoy Hopkins     IgvmHandle header_handle;
762c1d466d2SRoy Hopkins     IGVM_VHS_SUPPORTED_PLATFORM *platform;
763c1d466d2SRoy Hopkins     uint32_t compatibility_mask_sev = 0;
764c1d466d2SRoy Hopkins     uint32_t compatibility_mask_sev_es = 0;
765c1d466d2SRoy Hopkins     uint32_t compatibility_mask_sev_snp = 0;
766c1d466d2SRoy Hopkins     uint32_t compatibility_mask = 0;
767c1d466d2SRoy Hopkins 
768c1d466d2SRoy Hopkins     header_count = igvm_header_count(ctx->file, IGVM_HEADER_SECTION_PLATFORM);
769c1d466d2SRoy Hopkins     if (header_count < 0) {
770c1d466d2SRoy Hopkins         error_setg(errp,
771c1d466d2SRoy Hopkins                    "Invalid platform header count in IGVM file. Error code: %X",
772c1d466d2SRoy Hopkins                    header_count);
773c1d466d2SRoy Hopkins         return -1;
774c1d466d2SRoy Hopkins     }
775c1d466d2SRoy Hopkins 
776c1d466d2SRoy Hopkins     for (header_index = 0; header_index < (unsigned)header_count;
777c1d466d2SRoy Hopkins          header_index++) {
778c1d466d2SRoy Hopkins         IgvmVariableHeaderType typ = igvm_get_header_type(
779c1d466d2SRoy Hopkins             ctx->file, IGVM_HEADER_SECTION_PLATFORM, header_index);
780c1d466d2SRoy Hopkins         if (typ == IGVM_VHT_SUPPORTED_PLATFORM) {
781c1d466d2SRoy Hopkins             header_handle = igvm_get_header(
782c1d466d2SRoy Hopkins                 ctx->file, IGVM_HEADER_SECTION_PLATFORM, header_index);
783c1d466d2SRoy Hopkins             if (header_handle < 0) {
784c1d466d2SRoy Hopkins                 error_setg(errp,
785c1d466d2SRoy Hopkins                            "Invalid platform header in IGVM file. "
786c1d466d2SRoy Hopkins                            "Index: %d, Error code: %X",
787c1d466d2SRoy Hopkins                            header_index, header_handle);
788c1d466d2SRoy Hopkins                 return -1;
789c1d466d2SRoy Hopkins             }
790c1d466d2SRoy Hopkins             platform =
791c1d466d2SRoy Hopkins                 (IGVM_VHS_SUPPORTED_PLATFORM *)(igvm_get_buffer(ctx->file,
792c1d466d2SRoy Hopkins                                                                 header_handle) +
793c1d466d2SRoy Hopkins                                                 sizeof(
794c1d466d2SRoy Hopkins                                                     IGVM_VHS_VARIABLE_HEADER));
795c1d466d2SRoy Hopkins             if ((platform->platform_type == IGVM_PLATFORM_TYPE_SEV_ES) &&
796c1d466d2SRoy Hopkins                 ctx->cgs) {
797c1d466d2SRoy Hopkins                 if (ctx->cgsc->check_support(
798c1d466d2SRoy Hopkins                         CGS_PLATFORM_SEV_ES, platform->platform_version,
799c1d466d2SRoy Hopkins                         platform->highest_vtl, platform->shared_gpa_boundary)) {
800c1d466d2SRoy Hopkins                     compatibility_mask_sev_es = platform->compatibility_mask;
801c1d466d2SRoy Hopkins                 }
802c1d466d2SRoy Hopkins             } else if ((platform->platform_type == IGVM_PLATFORM_TYPE_SEV) &&
803c1d466d2SRoy Hopkins                        ctx->cgs) {
804c1d466d2SRoy Hopkins                 if (ctx->cgsc->check_support(
805c1d466d2SRoy Hopkins                         CGS_PLATFORM_SEV, platform->platform_version,
806c1d466d2SRoy Hopkins                         platform->highest_vtl, platform->shared_gpa_boundary)) {
807c1d466d2SRoy Hopkins                     compatibility_mask_sev = platform->compatibility_mask;
808c1d466d2SRoy Hopkins                 }
809c1d466d2SRoy Hopkins             } else if ((platform->platform_type ==
810c1d466d2SRoy Hopkins                         IGVM_PLATFORM_TYPE_SEV_SNP) &&
811c1d466d2SRoy Hopkins                        ctx->cgs) {
812c1d466d2SRoy Hopkins                 if (ctx->cgsc->check_support(
813c1d466d2SRoy Hopkins                         CGS_PLATFORM_SEV_SNP, platform->platform_version,
814c1d466d2SRoy Hopkins                         platform->highest_vtl, platform->shared_gpa_boundary)) {
815c1d466d2SRoy Hopkins                     compatibility_mask_sev_snp = platform->compatibility_mask;
816c1d466d2SRoy Hopkins                 }
817c1d466d2SRoy Hopkins             } else if (platform->platform_type == IGVM_PLATFORM_TYPE_NATIVE) {
818c1d466d2SRoy Hopkins                 compatibility_mask = platform->compatibility_mask;
819c1d466d2SRoy Hopkins             }
820c1d466d2SRoy Hopkins             igvm_free_buffer(ctx->file, header_handle);
821c1d466d2SRoy Hopkins         }
822c1d466d2SRoy Hopkins     }
823c1d466d2SRoy Hopkins     /* Choose the strongest supported isolation technology */
824c1d466d2SRoy Hopkins     if (compatibility_mask_sev_snp != 0) {
825c1d466d2SRoy Hopkins         ctx->compatibility_mask = compatibility_mask_sev_snp;
826915b4707SRoy Hopkins         ctx->platform_type = IGVM_PLATFORM_TYPE_SEV_SNP;
827c1d466d2SRoy Hopkins     } else if (compatibility_mask_sev_es != 0) {
828c1d466d2SRoy Hopkins         ctx->compatibility_mask = compatibility_mask_sev_es;
829915b4707SRoy Hopkins         ctx->platform_type = IGVM_PLATFORM_TYPE_SEV_ES;
830c1d466d2SRoy Hopkins     } else if (compatibility_mask_sev != 0) {
831c1d466d2SRoy Hopkins         ctx->compatibility_mask = compatibility_mask_sev;
832915b4707SRoy Hopkins         ctx->platform_type = IGVM_PLATFORM_TYPE_SEV;
833c1d466d2SRoy Hopkins     } else if (compatibility_mask != 0) {
834c1d466d2SRoy Hopkins         ctx->compatibility_mask = compatibility_mask;
835915b4707SRoy Hopkins         ctx->platform_type = IGVM_PLATFORM_TYPE_NATIVE;
836c1d466d2SRoy Hopkins     } else {
837c1d466d2SRoy Hopkins         error_setg(
838c1d466d2SRoy Hopkins             errp,
839c1d466d2SRoy Hopkins             "IGVM file does not describe a compatible supported platform");
840c1d466d2SRoy Hopkins         return -1;
841c1d466d2SRoy Hopkins     }
842c1d466d2SRoy Hopkins     return 0;
843c1d466d2SRoy Hopkins }
844c1d466d2SRoy Hopkins 
qigvm_handle_policy(QIgvm * ctx,Error ** errp)845915b4707SRoy Hopkins static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
846915b4707SRoy Hopkins {
847915b4707SRoy Hopkins     if (ctx->platform_type == IGVM_PLATFORM_TYPE_SEV_SNP) {
848915b4707SRoy Hopkins         int id_block_len = 0;
849915b4707SRoy Hopkins         int id_auth_len = 0;
850915b4707SRoy Hopkins         if (ctx->id_block) {
851915b4707SRoy Hopkins             ctx->id_block->policy = ctx->sev_policy;
852915b4707SRoy Hopkins             id_block_len = sizeof(struct sev_id_block);
853915b4707SRoy Hopkins             id_auth_len = sizeof(struct sev_id_authentication);
854915b4707SRoy Hopkins         }
855915b4707SRoy Hopkins         return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
856915b4707SRoy Hopkins                                           ctx->id_block, id_block_len,
857915b4707SRoy Hopkins                                           ctx->id_auth, id_auth_len, errp);
858915b4707SRoy Hopkins     }
859915b4707SRoy Hopkins     return 0;
860915b4707SRoy Hopkins }
861915b4707SRoy Hopkins 
qigvm_file_init(char * filename,Error ** errp)862c1d466d2SRoy Hopkins static IgvmHandle qigvm_file_init(char *filename, Error **errp)
863c1d466d2SRoy Hopkins {
864c1d466d2SRoy Hopkins     IgvmHandle igvm;
865c1d466d2SRoy Hopkins     g_autofree uint8_t *buf = NULL;
866c1d466d2SRoy Hopkins     unsigned long len;
867c1d466d2SRoy Hopkins     g_autoptr(GError) gerr = NULL;
868c1d466d2SRoy Hopkins 
869c1d466d2SRoy Hopkins     if (!g_file_get_contents(filename, (gchar **)&buf, &len, &gerr)) {
870c1d466d2SRoy Hopkins         error_setg(errp, "Unable to load %s: %s", filename, gerr->message);
871c1d466d2SRoy Hopkins         return -1;
872c1d466d2SRoy Hopkins     }
873c1d466d2SRoy Hopkins 
874c1d466d2SRoy Hopkins     igvm = igvm_new_from_binary(buf, len);
875c1d466d2SRoy Hopkins     if (igvm < 0) {
876c1d466d2SRoy Hopkins         error_setg(errp, "Unable to parse IGVM file %s: %d", filename, igvm);
877c1d466d2SRoy Hopkins         return -1;
878c1d466d2SRoy Hopkins     }
879c1d466d2SRoy Hopkins     return igvm;
880c1d466d2SRoy Hopkins }
881c1d466d2SRoy Hopkins 
qigvm_process_file(IgvmCfg * cfg,ConfidentialGuestSupport * cgs,bool onlyVpContext,Error ** errp)882c1d466d2SRoy Hopkins int qigvm_process_file(IgvmCfg *cfg, ConfidentialGuestSupport *cgs,
883*d60238b4SRoy Hopkins                        bool onlyVpContext, Error **errp)
884c1d466d2SRoy Hopkins {
885c1d466d2SRoy Hopkins     int32_t header_count;
886c1d466d2SRoy Hopkins     QIgvmParameterData *parameter;
887c1d466d2SRoy Hopkins     int retval = -1;
888c1d466d2SRoy Hopkins     QIgvm ctx;
889c1d466d2SRoy Hopkins 
890c1d466d2SRoy Hopkins     memset(&ctx, 0, sizeof(ctx));
891c1d466d2SRoy Hopkins     ctx.file = qigvm_file_init(cfg->filename, errp);
892c1d466d2SRoy Hopkins     if (ctx.file < 0) {
893c1d466d2SRoy Hopkins         return -1;
894c1d466d2SRoy Hopkins     }
895c1d466d2SRoy Hopkins 
896c1d466d2SRoy Hopkins     /*
897c1d466d2SRoy Hopkins      * The ConfidentialGuestSupport object is optional and allows a confidential
898c1d466d2SRoy Hopkins      * guest platform to perform extra processing, such as page measurement, on
899c1d466d2SRoy Hopkins      * IGVM directives.
900c1d466d2SRoy Hopkins      */
901c1d466d2SRoy Hopkins     ctx.cgs = cgs;
902c1d466d2SRoy Hopkins     ctx.cgsc = cgs ? CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs) : NULL;
903c1d466d2SRoy Hopkins 
904c1d466d2SRoy Hopkins     /*
905c1d466d2SRoy Hopkins      * Check that the IGVM file provides configuration for the current
906c1d466d2SRoy Hopkins      * platform
907c1d466d2SRoy Hopkins      */
908c1d466d2SRoy Hopkins     if (qigvm_supported_platform_compat_mask(&ctx, errp) < 0) {
909c1d466d2SRoy Hopkins         goto cleanup;
910c1d466d2SRoy Hopkins     }
911c1d466d2SRoy Hopkins 
912c1d466d2SRoy Hopkins     header_count = igvm_header_count(ctx.file, IGVM_HEADER_SECTION_DIRECTIVE);
913c1d466d2SRoy Hopkins     if (header_count <= 0) {
914c1d466d2SRoy Hopkins         error_setg(
915c1d466d2SRoy Hopkins             errp, "Invalid directive header count in IGVM file. Error code: %X",
916c1d466d2SRoy Hopkins             header_count);
917c1d466d2SRoy Hopkins         goto cleanup;
918c1d466d2SRoy Hopkins     }
919c1d466d2SRoy Hopkins 
920c1d466d2SRoy Hopkins     QTAILQ_INIT(&ctx.parameter_data);
921c1d466d2SRoy Hopkins 
922c1d466d2SRoy Hopkins     for (ctx.current_header_index = 0;
923c1d466d2SRoy Hopkins          ctx.current_header_index < (unsigned)header_count;
924c1d466d2SRoy Hopkins          ctx.current_header_index++) {
925c1d466d2SRoy Hopkins         IgvmVariableHeaderType type = igvm_get_header_type(
926c1d466d2SRoy Hopkins             ctx.file, IGVM_HEADER_SECTION_DIRECTIVE, ctx.current_header_index);
927*d60238b4SRoy Hopkins         if (!onlyVpContext || (type == IGVM_VHT_VP_CONTEXT)) {
928c1d466d2SRoy Hopkins             if (qigvm_handler(&ctx, type, errp) < 0) {
929c1d466d2SRoy Hopkins                 goto cleanup_parameters;
930c1d466d2SRoy Hopkins             }
931c1d466d2SRoy Hopkins         }
932*d60238b4SRoy Hopkins     }
933*d60238b4SRoy Hopkins 
934*d60238b4SRoy Hopkins     /*
935*d60238b4SRoy Hopkins      * If only processing the VP context then we don't need to process
936*d60238b4SRoy Hopkins      * any more of the file.
937*d60238b4SRoy Hopkins      */
938*d60238b4SRoy Hopkins     if (onlyVpContext) {
939*d60238b4SRoy Hopkins         retval = 0;
940*d60238b4SRoy Hopkins         goto cleanup_parameters;
941*d60238b4SRoy Hopkins     }
942c1d466d2SRoy Hopkins 
9439de40d7dSRoy Hopkins     header_count =
9449de40d7dSRoy Hopkins         igvm_header_count(ctx.file, IGVM_HEADER_SECTION_INITIALIZATION);
9459de40d7dSRoy Hopkins     if (header_count < 0) {
9469de40d7dSRoy Hopkins         error_setg(
9479de40d7dSRoy Hopkins             errp,
9489de40d7dSRoy Hopkins             "Invalid initialization header count in IGVM file. Error code: %X",
9499de40d7dSRoy Hopkins             header_count);
9509de40d7dSRoy Hopkins         goto cleanup_parameters;
9519de40d7dSRoy Hopkins     }
9529de40d7dSRoy Hopkins 
9539de40d7dSRoy Hopkins     for (ctx.current_header_index = 0;
9549de40d7dSRoy Hopkins          ctx.current_header_index < (unsigned)header_count;
9559de40d7dSRoy Hopkins          ctx.current_header_index++) {
9569de40d7dSRoy Hopkins         IgvmVariableHeaderType type =
9579de40d7dSRoy Hopkins             igvm_get_header_type(ctx.file, IGVM_HEADER_SECTION_INITIALIZATION,
9589de40d7dSRoy Hopkins                                  ctx.current_header_index);
9599de40d7dSRoy Hopkins         if (qigvm_handler(&ctx, type, errp) < 0) {
9609de40d7dSRoy Hopkins             goto cleanup_parameters;
9619de40d7dSRoy Hopkins         }
9629de40d7dSRoy Hopkins     }
9639de40d7dSRoy Hopkins 
964c1d466d2SRoy Hopkins     /*
965c1d466d2SRoy Hopkins      * Contiguous pages of data with compatible flags are grouped together in
966c1d466d2SRoy Hopkins      * order to reduce the number of memory regions we create. Make sure the
967c1d466d2SRoy Hopkins      * last group is processed with this call.
968c1d466d2SRoy Hopkins      */
969c1d466d2SRoy Hopkins     retval = qigvm_process_mem_page(&ctx, NULL, errp);
970c1d466d2SRoy Hopkins 
971915b4707SRoy Hopkins     if (retval == 0) {
972915b4707SRoy Hopkins         retval = qigvm_handle_policy(&ctx, errp);
973915b4707SRoy Hopkins     }
974915b4707SRoy Hopkins 
975c1d466d2SRoy Hopkins cleanup_parameters:
976c1d466d2SRoy Hopkins     QTAILQ_FOREACH(parameter, &ctx.parameter_data, next)
977c1d466d2SRoy Hopkins     {
978c1d466d2SRoy Hopkins         g_free(parameter->data);
979c1d466d2SRoy Hopkins         parameter->data = NULL;
980c1d466d2SRoy Hopkins     }
981915b4707SRoy Hopkins     g_free(ctx.id_block);
982915b4707SRoy Hopkins     g_free(ctx.id_auth);
983c1d466d2SRoy Hopkins 
984c1d466d2SRoy Hopkins cleanup:
985c1d466d2SRoy Hopkins     igvm_free(ctx.file);
986c1d466d2SRoy Hopkins 
987c1d466d2SRoy Hopkins     return retval;
988c1d466d2SRoy Hopkins }
989