master
c 1,131 lines 38.6 KB
Raw
1 /*
2 * QEMU IGVM configuration backend for guests
3 *
4 * Copyright (C) 2023-2024 SUSE
5 *
6 * Authors:
7 * Roy Hopkins <roy.hopkins@randomman.co.uk>
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "qemu/osdep.h"
13
14 #include "qapi/error.h"
15 #include "qemu/error-report.h"
16 #include "qemu/target-info-qapi.h"
17 #include "migration/vmstate.h"
18 #include "system/igvm.h"
19 #include "system/igvm-cfg.h"
20 #include "system/igvm-internal.h"
21 #include "system/memory.h"
22 #include "system/address-spaces.h"
23 #include "hw/core/cpu.h"
24
25 #include "trace.h"
26
27 #include <igvm/igvm.h>
28 #include <igvm/igvm_defs.h>
29
30 #ifdef CONFIG_FDT
31 #include <libfdt.h>
32 #endif
33
34 #ifndef IGVM_VHT_OPTIONAL_BIT
35 #define IGVM_VHT_OPTIONAL_BIT (1U << 31)
36 #endif
37
38 /*
39 * Bit 31 of the variable header type indicates that the header is
40 * optional and can be safely ignored by a loader that does not
41 * support it. If the bit is clear, the file cannot be loaded.
42 * https://docs.rs/igvm_defs/0.4.0/igvm_defs/struct.IgvmVariableHeaderType.html
43 */
44 static IgvmVariableHeaderType igvm_vht_type(IgvmVariableHeaderType type)
45 {
46 return type & ~IGVM_VHT_OPTIONAL_BIT;
47 }
48
49 static bool igvm_vht_optional(IgvmVariableHeaderType type)
50 {
51 return !!(type & IGVM_VHT_OPTIONAL_BIT);
52 }
53
54 /*
55 * Some directives are specific to particular confidential computing platforms.
56 * Define required types for each of those platforms here.
57 */
58
59 /* SEV/SEV-ES/SEV-SNP */
60
61 /*
62 * These structures are defined in "SEV Secure Nested Paging Firmware ABI
63 * Specification" Rev 1.58, section 8.18.
64 */
65 struct QEMU_PACKED sev_id_block {
66 uint8_t ld[48];
67 uint8_t family_id[16];
68 uint8_t image_id[16];
69 uint32_t version;
70 uint32_t guest_svn;
71 uint64_t policy;
72 };
73
74 struct QEMU_PACKED sev_id_authentication {
75 uint32_t id_key_alg;
76 uint32_t auth_key_algo;
77 uint8_t reserved[56];
78 uint8_t id_block_sig[512];
79 uint8_t id_key[1028];
80 uint8_t reserved2[60];
81 uint8_t id_key_sig[512];
82 uint8_t author_key[1028];
83 uint8_t reserved3[892];
84 };
85
86 #define IGVM_SEV_ID_BLOCK_VERSION 1
87
88 QIgvmParameterData*
89 qigvm_find_param_entry(QIgvm *igvm, uint32_t parameter_area_index,
90 Error **errp)
91 {
92 QIgvmParameterData *param_entry;
93 QTAILQ_FOREACH(param_entry, &igvm->parameter_data, next)
94 {
95 if (param_entry->index == parameter_area_index) {
96 return param_entry;
97 }
98 }
99 error_setg(errp, "IGVM: parameter area index %u not found",
100 parameter_area_index);
101 return NULL;
102 }
103
104 static int qigvm_directive_page_data(QIgvm *ctx, const uint8_t *header_data,
105 Error **errp);
106 static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
107 Error **errp);
108 static int qigvm_directive_parameter_area(QIgvm *ctx,
109 const uint8_t *header_data,
110 Error **errp);
111 static int qigvm_directive_parameter_insert(QIgvm *ctx,
112 const uint8_t *header_data,
113 Error **errp);
114 static int qigvm_directive_memory_map(QIgvm *ctx, const uint8_t *header_data,
115 Error **errp);
116 static int qigvm_directive_vp_count(QIgvm *ctx, const uint8_t *header_data,
117 Error **errp);
118 static int qigvm_directive_environment_info(QIgvm *ctx,
119 const uint8_t *header_data,
120 Error **errp);
121 static int qigvm_directive_required_memory(QIgvm *ctx,
122 const uint8_t *header_data,
123 Error **errp);
124 static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
125 Error **errp);
126 static int qigvm_initialization_guest_policy(QIgvm *ctx,
127 const uint8_t *header_data,
128 Error **errp);
129 #ifdef CONFIG_FDT
130 static int qigvm_directive_device_tree(QIgvm *ctx, const uint8_t *header_data,
131 Error **errp);
132 #endif
133
134 struct QIGVMHandler {
135 IgvmVariableHeaderType type;
136 IgvmHeaderSection section;
137 int (*handler)(QIgvm *ctx, const uint8_t *header_data, Error **errp);
138 };
139
140 static struct QIGVMHandler handlers[] = {
141 { IGVM_VHT_PAGE_DATA, IGVM_HEADER_SECTION_DIRECTIVE,
142 qigvm_directive_page_data },
143 { IGVM_VHT_VP_CONTEXT, IGVM_HEADER_SECTION_DIRECTIVE,
144 qigvm_directive_vp_context },
145 { IGVM_VHT_PARAMETER_AREA, IGVM_HEADER_SECTION_DIRECTIVE,
146 qigvm_directive_parameter_area },
147 { IGVM_VHT_PARAMETER_INSERT, IGVM_HEADER_SECTION_DIRECTIVE,
148 qigvm_directive_parameter_insert },
149 { IGVM_VHT_MEMORY_MAP, IGVM_HEADER_SECTION_DIRECTIVE,
150 qigvm_directive_memory_map },
151 { IGVM_VHT_VP_COUNT_PARAMETER, IGVM_HEADER_SECTION_DIRECTIVE,
152 qigvm_directive_vp_count },
153 { IGVM_VHT_ENVIRONMENT_INFO_PARAMETER, IGVM_HEADER_SECTION_DIRECTIVE,
154 qigvm_directive_environment_info },
155 { IGVM_VHT_REQUIRED_MEMORY, IGVM_HEADER_SECTION_DIRECTIVE,
156 qigvm_directive_required_memory },
157 { IGVM_VHT_SNP_ID_BLOCK, IGVM_HEADER_SECTION_DIRECTIVE,
158 qigvm_directive_snp_id_block },
159 { IGVM_VHT_GUEST_POLICY, IGVM_HEADER_SECTION_INITIALIZATION,
160 qigvm_initialization_guest_policy },
161 { IGVM_VHT_MADT, IGVM_HEADER_SECTION_DIRECTIVE,
162 qigvm_directive_madt },
163 #ifdef CONFIG_FDT
164 { IGVM_VHT_DEVICE_TREE, IGVM_HEADER_SECTION_DIRECTIVE,
165 qigvm_directive_device_tree },
166 #endif
167 };
168
169 static int qigvm_handler(QIgvm *ctx, IgvmVariableHeaderType raw_type,
170 Error **errp)
171 {
172 size_t handler;
173 IgvmHandle header_handle;
174 const uint8_t *header_data;
175 int result;
176 IgvmVariableHeaderType type = igvm_vht_type(raw_type);
177
178 for (handler = 0; handler < G_N_ELEMENTS(handlers); handler++) {
179 if (handlers[handler].type != type) {
180 continue;
181 }
182 header_handle = igvm_get_header(ctx->cfg->file,
183 handlers[handler].section,
184 ctx->current_header_index);
185 if (header_handle < 0) {
186 error_setg(
187 errp,
188 "IGVM file is invalid: Failed to read directive header (code: %d)",
189 (int)header_handle);
190 return -1;
191 }
192 header_data = igvm_get_buffer(ctx->cfg->file, header_handle);
193 if (header_data != NULL) {
194 header_data += sizeof(IGVM_VHS_VARIABLE_HEADER);
195 result = handlers[handler].handler(ctx, header_data, errp);
196 } else {
197 error_setg(errp,
198 "IGVM: No buffer for handle %d: "
199 "(type 0x%X)",
200 header_handle, type);
201 result = -1;
202 }
203 igvm_free_buffer(ctx->cfg->file, header_handle);
204 return result;
205 }
206
207 if (igvm_vht_optional(raw_type)) {
208 warn_report("IGVM: Skipping unsupported optional header type 0x%"
209 PRIX32, type);
210 return 0;
211 }
212
213 error_setg(errp,
214 "IGVM: Unknown header type encountered when processing file: "
215 "(type 0x%X)",
216 type);
217 return -1;
218 }
219
220 static void *qigvm_prepare_memory(QIgvm *ctx, uint64_t addr, uint64_t size,
221 int region_identifier, Error **errp)
222 {
223 ERRP_GUARD();
224 IgvmMemoryRegion *imr = NULL;
225 Int128 gpa_region_size;
226 MemoryRegionSection mrs =
227 memory_region_find(get_system_memory(), addr, size);
228 if (mrs.mr) {
229 if (!memory_region_is_ram(mrs.mr)) {
230 memory_region_unref(mrs.mr);
231 error_setg(
232 errp,
233 "Processing of IGVM file failed: Could not prepare memory "
234 "at address 0x%" PRIx64 " due to existing non-RAM region",
235 addr);
236 return NULL;
237 }
238
239 gpa_region_size = int128_make64(size);
240 if (int128_lt(mrs.size, gpa_region_size)) {
241 memory_region_unref(mrs.mr);
242 error_setg(
243 errp,
244 "Processing of IGVM file failed: Could not prepare memory "
245 "at address 0x%" PRIx64 ": region size 0x%" PRIx64 " exceeded",
246 addr, size);
247 return NULL;
248 }
249 return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
250 } else {
251 /*
252 * The region_identifier is the is the index of the IGVM directive that
253 * contains the page with the lowest GPA in the region. This will
254 * generate a unique region name.
255 */
256 g_autofree char *region_name =
257 g_strdup_printf("igvm.%X", region_identifier);
258 imr = g_new0(IgvmMemoryRegion, 1);
259 imr->mr = g_new0(MemoryRegion, 1);
260 if (ctx->machine_state->cgs &&
261 ctx->machine_state->cgs->require_guest_memfd) {
262 if (!memory_region_init_ram_guest_memfd(imr->mr, NULL,
263 region_name, size, errp)) {
264 g_free(imr->mr);
265 g_free(imr);
266 return NULL;
267 }
268 } else {
269 if (!memory_region_init_ram(imr->mr, NULL, region_name, size,
270 errp)) {
271 g_free(imr->mr);
272 g_free(imr);
273 return NULL;
274 }
275 }
276 memory_region_add_subregion(get_system_memory(), addr, imr->mr);
277 QTAILQ_INSERT_TAIL(&ctx->cfg->memory_regions, imr, next);
278 return memory_region_get_ram_ptr(imr->mr);
279 }
280 }
281
282 static int qigvm_type_to_cgs_type(IgvmPageDataType memory_type, bool unmeasured,
283 bool zero)
284 {
285 switch (memory_type) {
286 case IGVM_PAGE_DATA_TYPE_NORMAL: {
287 if (unmeasured) {
288 return CGS_PAGE_TYPE_UNMEASURED;
289 } else {
290 return zero ? CGS_PAGE_TYPE_ZERO : CGS_PAGE_TYPE_NORMAL;
291 }
292 }
293 case IGVM_PAGE_DATA_TYPE_SECRETS:
294 return CGS_PAGE_TYPE_SECRETS;
295 case IGVM_PAGE_DATA_TYPE_CPUID_DATA:
296 return CGS_PAGE_TYPE_CPUID;
297 case IGVM_PAGE_DATA_TYPE_CPUID_XF:
298 return CGS_PAGE_TYPE_CPUID;
299 default:
300 return -1;
301 }
302 }
303
304 static bool qigvm_page_attrs_equal(IgvmHandle igvm, unsigned header_index,
305 const IGVM_VHS_PAGE_DATA *page_1,
306 const IGVM_VHS_PAGE_DATA *page_2)
307 {
308 IgvmHandle data_handle1, data_handle2;
309
310 /*
311 * If one page has data and the other doesn't then this results in different
312 * page types: NORMAL vs ZERO.
313 */
314 data_handle1 = igvm_get_header_data(igvm, IGVM_HEADER_SECTION_DIRECTIVE,
315 header_index - 1);
316 data_handle2 =
317 igvm_get_header_data(igvm, IGVM_HEADER_SECTION_DIRECTIVE, header_index);
318 if ((data_handle1 == IGVMAPI_NO_DATA ||
319 data_handle2 == IGVMAPI_NO_DATA) &&
320 data_handle1 != data_handle2) {
321 return false;
322 }
323 return ((*(const uint32_t *)&page_1->flags ==
324 *(const uint32_t *)&page_2->flags) &&
325 (page_1->data_type == page_2->data_type) &&
326 (page_1->compatibility_mask == page_2->compatibility_mask));
327 }
328
329 static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index,
330 uint64_t gpa_start, unsigned page_count,
331 const IgvmPageDataFlags *flags,
332 const IgvmPageDataType page_type,
333 Error **errp)
334 {
335 uint8_t *region;
336 IgvmHandle data_handle;
337 const void *data;
338 uint32_t data_size;
339 unsigned page_index;
340 bool zero = true;
341 const uint64_t page_size = flags->is_2mb_page ? 0x200000 : 0x1000;
342 int result;
343 int cgs_page_type;
344
345 region = qigvm_prepare_memory(ctx, gpa_start, page_count * page_size,
346 start_index, errp);
347 if (!region) {
348 return -1;
349 }
350
351 for (page_index = 0; page_index < page_count; page_index++) {
352 data_handle = igvm_get_header_data(
353 ctx->cfg->file, IGVM_HEADER_SECTION_DIRECTIVE,
354 page_index + start_index);
355 if (data_handle == IGVMAPI_NO_DATA) {
356 /* No data indicates a zero page */
357 memset(&region[page_index * page_size], 0, page_size);
358 } else if (data_handle < 0) {
359 error_setg(
360 errp,
361 "IGVM file contains invalid page data for directive with "
362 "index %d",
363 page_index + start_index);
364 return -1;
365 } else {
366 zero = false;
367 data_size = igvm_get_buffer_size(ctx->cfg->file, data_handle);
368 if (data_size < page_size) {
369 memset(&region[page_index * page_size], 0, page_size);
370 } else if (data_size > page_size) {
371 error_setg(errp,
372 "IGVM file contains page data with invalid size for "
373 "directive with index %d",
374 page_index + start_index);
375 return -1;
376 }
377 data = igvm_get_buffer(ctx->cfg->file, data_handle);
378 if (data == NULL) {
379 error_setg(errp, "IGVM: No buffer for handle %d", data_handle);
380 igvm_free_buffer(ctx->cfg->file, data_handle);
381 return -1;
382 }
383 memcpy(&region[page_index * page_size], data, data_size);
384 igvm_free_buffer(ctx->cfg->file, data_handle);
385 }
386 }
387
388 /*
389 * If a confidential guest support object is provided then use it to set the
390 * guest state.
391 */
392 if (ctx->machine_state->cgs) {
393 cgs_page_type =
394 qigvm_type_to_cgs_type(page_type, flags->unmeasured, zero);
395 if (cgs_page_type < 0) {
396 error_setg(errp,
397 "Invalid page type in IGVM file. Directives: %d to %d, "
398 "page type: %d",
399 start_index, start_index + page_count, page_type);
400 return -1;
401 }
402
403 result = ctx->cgsc->set_guest_state(
404 gpa_start, region, page_size * page_count, cgs_page_type, 0, errp);
405 if (result < 0) {
406 return result;
407 }
408 }
409 return 0;
410 }
411
412 static int qigvm_process_mem_page(QIgvm *ctx,
413 const IGVM_VHS_PAGE_DATA *page_data,
414 Error **errp)
415 {
416 if (page_data) {
417 if (ctx->region_page_count == 0) {
418 ctx->region_start = page_data->gpa;
419 ctx->region_start_index = ctx->current_header_index;
420 } else {
421 if (!qigvm_page_attrs_equal(ctx->cfg->file,
422 ctx->current_header_index,
423 page_data,
424 &ctx->region_prev_page_data) ||
425 ((ctx->region_prev_page_data.gpa +
426 (ctx->region_prev_page_data.flags.is_2mb_page ? 0x200000 :
427 0x1000)) !=
428 page_data->gpa) ||
429 (ctx->region_last_index != (ctx->current_header_index - 1))) {
430 /* End of current region */
431 if (qigvm_process_mem_region(
432 ctx, ctx->region_start_index, ctx->region_start,
433 ctx->region_page_count,
434 &ctx->region_prev_page_data.flags,
435 ctx->region_prev_page_data.data_type, errp) < 0) {
436 return -1;
437 }
438 ctx->region_page_count = 0;
439 ctx->region_start = page_data->gpa;
440 ctx->region_start_index = ctx->current_header_index;
441 }
442 }
443 memcpy(&ctx->region_prev_page_data, page_data,
444 sizeof(ctx->region_prev_page_data));
445 ctx->region_last_index = ctx->current_header_index;
446 ctx->region_page_count++;
447 } else {
448 if (ctx->region_page_count > 0) {
449 if (qigvm_process_mem_region(
450 ctx, ctx->region_start_index, ctx->region_start,
451 ctx->region_page_count, &ctx->region_prev_page_data.flags,
452 ctx->region_prev_page_data.data_type, errp) < 0) {
453 return -1;
454 }
455 ctx->region_page_count = 0;
456 }
457 }
458 return 0;
459 }
460
461 static int qigvm_directive_page_data(QIgvm *ctx, const uint8_t *header_data,
462 Error **errp)
463 {
464 const IGVM_VHS_PAGE_DATA *page_data =
465 (const IGVM_VHS_PAGE_DATA *)header_data;
466 if (page_data->compatibility_mask & ctx->compatibility_mask) {
467 return qigvm_process_mem_page(ctx, page_data, errp);
468 }
469 return 0;
470 }
471
472 static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data,
473 Error **errp)
474 {
475 const IGVM_VHS_VP_CONTEXT *vp_context =
476 (const IGVM_VHS_VP_CONTEXT *)header_data;
477 IgvmHandle data_handle;
478 uint8_t *data;
479 int result;
480
481 if (!(vp_context->compatibility_mask & ctx->compatibility_mask)) {
482 return 0;
483 }
484
485 data_handle = igvm_get_header_data(ctx->cfg->file,
486 IGVM_HEADER_SECTION_DIRECTIVE,
487 ctx->current_header_index);
488 if (data_handle < 0) {
489 error_setg(errp, "Invalid VP context in IGVM file. Error code: %X",
490 data_handle);
491 return -1;
492 }
493
494 data = (uint8_t *)igvm_get_buffer(ctx->cfg->file, data_handle);
495 if (data == NULL) {
496 error_setg(errp, "IGVM: No buffer for handle %d", data_handle);
497 result = -1;
498 goto exit;
499 }
500
501 if (ctx->machine_state->cgs) {
502 result = ctx->cgsc->set_guest_state(
503 vp_context->gpa, data,
504 igvm_get_buffer_size(ctx->cfg->file, data_handle),
505 CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp);
506 } else if (target_arch() == SYS_EMU_TARGET_X86_64) {
507 result = qigvm_x86_set_vp_context(data, vp_context->vp_index, errp);
508 } else {
509 error_setg(
510 errp,
511 "A VP context is present in the IGVM file but is not supported "
512 "by the current system.");
513 result = -1;
514 }
515
516 exit:
517 igvm_free_buffer(ctx->cfg->file, data_handle);
518 if (result < 0) {
519 return result;
520 }
521 return 0;
522 }
523
524 static int qigvm_directive_parameter_area(QIgvm *ctx,
525 const uint8_t *header_data,
526 Error **errp)
527 {
528 const IGVM_VHS_PARAMETER_AREA *param_area =
529 (const IGVM_VHS_PARAMETER_AREA *)header_data;
530 QIgvmParameterData *param_entry;
531
532 param_entry = g_new0(QIgvmParameterData, 1);
533 param_entry->size = param_area->number_of_bytes;
534 param_entry->index = param_area->parameter_area_index;
535 param_entry->data = g_malloc0(param_entry->size);
536
537 QTAILQ_INSERT_TAIL(&ctx->parameter_data, param_entry, next);
538 return 0;
539 }
540
541 static int qigvm_directive_parameter_insert(QIgvm *ctx,
542 const uint8_t *header_data,
543 Error **errp)
544 {
545 const IGVM_VHS_PARAMETER_INSERT *param =
546 (const IGVM_VHS_PARAMETER_INSERT *)header_data;
547 QIgvmParameterData *param_entry;
548 int result;
549 void *region;
550
551 if (!(param->compatibility_mask & ctx->compatibility_mask)) {
552 return 0;
553 }
554
555 param_entry = qigvm_find_param_entry(ctx,
556 param->parameter_area_index, errp);
557 if (param_entry == NULL) {
558 return -1;
559 }
560
561 region = qigvm_prepare_memory(ctx, param->gpa, param_entry->size,
562 ctx->current_header_index, errp);
563 if (!region) {
564 return -1;
565 }
566 memcpy(region, param_entry->data, param_entry->size);
567 g_free(param_entry->data);
568 param_entry->data = NULL;
569
570 /*
571 * If a confidential guest support object is provided then use it to
572 * set the guest state.
573 */
574 if (ctx->machine_state->cgs) {
575 result = ctx->cgsc->set_guest_state(param->gpa, region,
576 param_entry->size,
577 CGS_PAGE_TYPE_UNMEASURED, 0,
578 errp);
579 if (result < 0) {
580 return -1;
581 }
582 }
583 return 0;
584 }
585
586 static int qigvm_cmp_mm_entry(const void *a, const void *b)
587 {
588 const IGVM_VHS_MEMORY_MAP_ENTRY *entry_a =
589 (const IGVM_VHS_MEMORY_MAP_ENTRY *)a;
590 const IGVM_VHS_MEMORY_MAP_ENTRY *entry_b =
591 (const IGVM_VHS_MEMORY_MAP_ENTRY *)b;
592 if (entry_a->starting_gpa_page_number < entry_b->starting_gpa_page_number) {
593 return -1;
594 } else if (entry_a->starting_gpa_page_number >
595 entry_b->starting_gpa_page_number) {
596 return 1;
597 } else {
598 return 0;
599 }
600 }
601
602 static int qigvm_directive_memory_map(QIgvm *ctx, const uint8_t *header_data,
603 Error **errp)
604 {
605 const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
606 int (*get_mem_map_entry)(int index, ConfidentialGuestMemoryMapEntry *entry,
607 Error **errp) = NULL;
608 QIgvmParameterData *param_entry;
609 int max_entry_count;
610 int entry = 0;
611 IGVM_VHS_MEMORY_MAP_ENTRY *mm_entry;
612 ConfidentialGuestMemoryMapEntry cgmm_entry;
613 int retval = 0;
614
615 if (ctx->machine_state->cgs && ctx->cgsc->get_mem_map_entry) {
616 get_mem_map_entry = ctx->cgsc->get_mem_map_entry;
617
618 } else if (target_arch() == SYS_EMU_TARGET_X86_64) {
619 get_mem_map_entry = qigvm_x86_get_mem_map_entry;
620
621 } else {
622 error_setg(errp,
623 "IGVM file contains a memory map but this is not supported "
624 "by the current system.");
625 return -1;
626 }
627
628 /* Find the parameter area that should hold the memory map */
629 param_entry = qigvm_find_param_entry(ctx,
630 param->parameter_area_index, errp);
631 if (param_entry == NULL) {
632 return -1;
633 }
634
635 max_entry_count = param_entry->size / sizeof(IGVM_VHS_MEMORY_MAP_ENTRY);
636 mm_entry = (IGVM_VHS_MEMORY_MAP_ENTRY *)param_entry->data;
637
638 retval = get_mem_map_entry(entry, &cgmm_entry, errp);
639 while (retval == 0) {
640 if (entry >= max_entry_count) {
641 error_setg(
642 errp,
643 "IGVM: guest memory map size exceeds parameter area defined "
644 "in IGVM file");
645 return -1;
646 }
647 mm_entry[entry].starting_gpa_page_number = cgmm_entry.gpa >> 12;
648 mm_entry[entry].number_of_pages = cgmm_entry.size >> 12;
649
650 switch (cgmm_entry.type) {
651 case CGS_MEM_RAM:
652 mm_entry[entry].entry_type = IGVM_MEMORY_MAP_ENTRY_TYPE_MEMORY;
653 break;
654 case CGS_MEM_RESERVED:
655 mm_entry[entry].entry_type =
656 IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
657 break;
658 case CGS_MEM_ACPI:
659 mm_entry[entry].entry_type =
660 IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
661 break;
662 case CGS_MEM_NVS:
663 mm_entry[entry].entry_type = IGVM_MEMORY_MAP_ENTRY_TYPE_PERSISTENT;
664 break;
665 case CGS_MEM_UNUSABLE:
666 mm_entry[entry].entry_type =
667 IGVM_MEMORY_MAP_ENTRY_TYPE_PLATFORM_RESERVED;
668 break;
669 }
670 retval = get_mem_map_entry(++entry, &cgmm_entry, errp);
671 }
672 if (retval < 0) {
673 return retval;
674 }
675 /* The entries need to be sorted */
676 qsort(mm_entry, entry, sizeof(IGVM_VHS_MEMORY_MAP_ENTRY),
677 qigvm_cmp_mm_entry);
678 return 0;
679 }
680
681 static int qigvm_directive_vp_count(QIgvm *ctx, const uint8_t *header_data,
682 Error **errp)
683 {
684 const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
685 QIgvmParameterData *param_entry;
686 uint32_t *vp_count;
687 CPUState *cpu;
688
689 param_entry = qigvm_find_param_entry(ctx,
690 param->parameter_area_index, errp);
691 if (param_entry == NULL) {
692 return -1;
693 }
694
695 vp_count = (uint32_t *)(param_entry->data + param->byte_offset);
696 *vp_count = 0;
697 CPU_FOREACH(cpu)
698 {
699 (*vp_count)++;
700 }
701
702 return 0;
703 }
704
705 static int qigvm_directive_environment_info(QIgvm *ctx,
706 const uint8_t *header_data,
707 Error **errp)
708 {
709 const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
710 QIgvmParameterData *param_entry;
711 IgvmEnvironmentInfo *environmental_state;
712
713 param_entry = qigvm_find_param_entry(ctx,
714 param->parameter_area_index, errp);
715 if (param_entry == NULL) {
716 return -1;
717 }
718
719 environmental_state =
720 (IgvmEnvironmentInfo *)(param_entry->data + param->byte_offset);
721 environmental_state->memory_is_shared = 1;
722
723 return 0;
724 }
725
726 static int qigvm_directive_required_memory(QIgvm *ctx,
727 const uint8_t *header_data,
728 Error **errp)
729 {
730 const IGVM_VHS_REQUIRED_MEMORY *mem =
731 (const IGVM_VHS_REQUIRED_MEMORY *)header_data;
732 uint8_t *region;
733 int result;
734
735 if (!(mem->compatibility_mask & ctx->compatibility_mask)) {
736 return 0;
737 }
738
739 region = qigvm_prepare_memory(ctx, mem->gpa, mem->number_of_bytes,
740 ctx->current_header_index, errp);
741 if (!region) {
742 return -1;
743 }
744 if (ctx->machine_state->cgs) {
745 result =
746 ctx->cgsc->set_guest_state(mem->gpa, region, mem->number_of_bytes,
747 CGS_PAGE_TYPE_REQUIRED_MEMORY, 0, errp);
748 if (result < 0) {
749 return result;
750 }
751 }
752 return 0;
753 }
754
755 static int qigvm_directive_snp_id_block(QIgvm *ctx, const uint8_t *header_data,
756 Error **errp)
757 {
758 const IGVM_VHS_SNP_ID_BLOCK *igvm_id =
759 (const IGVM_VHS_SNP_ID_BLOCK *)header_data;
760
761 if (!(igvm_id->compatibility_mask & ctx->compatibility_mask)) {
762 return 0;
763 }
764
765 if (ctx->id_block) {
766 error_setg(errp, "IGVM: Multiple ID blocks encountered "
767 "in IGVM file.");
768 return -1;
769 }
770 ctx->id_block = g_new0(struct sev_id_block, 1);
771 ctx->id_auth = g_new0(struct sev_id_authentication, 1);
772
773 memcpy(ctx->id_block->family_id, igvm_id->family_id,
774 sizeof(ctx->id_block->family_id));
775 memcpy(ctx->id_block->image_id, igvm_id->image_id,
776 sizeof(ctx->id_block->image_id));
777 ctx->id_block->guest_svn = igvm_id->guest_svn;
778 ctx->id_block->version = IGVM_SEV_ID_BLOCK_VERSION;
779 memcpy(ctx->id_block->ld, igvm_id->ld, sizeof(ctx->id_block->ld));
780
781 ctx->id_auth->id_key_alg = igvm_id->id_key_algorithm;
782 assert(sizeof(igvm_id->id_key_signature) <=
783 sizeof(ctx->id_auth->id_block_sig));
784 memcpy(ctx->id_auth->id_block_sig, &igvm_id->id_key_signature,
785 sizeof(igvm_id->id_key_signature));
786
787 ctx->id_auth->auth_key_algo = igvm_id->author_key_algorithm;
788 assert(sizeof(igvm_id->author_key_signature) <=
789 sizeof(ctx->id_auth->id_key_sig));
790 memcpy(ctx->id_auth->id_key_sig, &igvm_id->author_key_signature,
791 sizeof(igvm_id->author_key_signature));
792
793 /*
794 * SEV and IGVM public key structure population are slightly different.
795 * See SEV Secure Nested Paging Firmware ABI Specification, Chapter 10.
796 */
797 *((uint32_t *)ctx->id_auth->id_key) = igvm_id->id_public_key.curve;
798 memcpy(&ctx->id_auth->id_key[4], &igvm_id->id_public_key.qx, 72);
799 memcpy(&ctx->id_auth->id_key[76], &igvm_id->id_public_key.qy, 72);
800
801 *((uint32_t *)ctx->id_auth->author_key) =
802 igvm_id->author_public_key.curve;
803 memcpy(&ctx->id_auth->author_key[4], &igvm_id->author_public_key.qx,
804 72);
805 memcpy(&ctx->id_auth->author_key[76], &igvm_id->author_public_key.qy,
806 72);
807
808 return 0;
809 }
810
811 #ifdef CONFIG_FDT
812 static int qigvm_directive_device_tree(QIgvm *ctx, const uint8_t *header_data,
813 Error **errp)
814 {
815 const IGVM_VHS_PARAMETER *param = (const IGVM_VHS_PARAMETER *)header_data;
816 g_autofree void *fdt_packed = NULL;
817 QIgvmParameterData *param_entry;
818 uint32_t fdt_size;
819
820 param_entry = qigvm_find_param_entry(ctx,
821 param->parameter_area_index, errp);
822 if (param_entry == NULL) {
823 return -1;
824 }
825
826 if (ctx->machine_state->fdt == NULL) {
827 error_setg(errp, "IGVM: device tree not available");
828 return -1;
829 }
830
831 fdt_size = fdt_totalsize(ctx->machine_state->fdt);
832 fdt_packed = g_memdup2(ctx->machine_state->fdt, fdt_size);
833
834 if (fdt_pack(fdt_packed)) {
835 error_setg(errp, "IGVM: failed to pack device tree");
836 return -1;
837 }
838
839 fdt_size = fdt_totalsize(fdt_packed);
840 if (fdt_size > param_entry->size) {
841 error_setg(errp,
842 "IGVM: device tree size exceeds parameter area"
843 " defined in IGVM file");
844 return -1;
845 }
846
847 memcpy(param_entry->data, fdt_packed, fdt_size);
848
849 return 0;
850 }
851 #endif
852
853 static int qigvm_initialization_guest_policy(QIgvm *ctx,
854 const uint8_t *header_data, Error **errp)
855 {
856 const IGVM_VHS_GUEST_POLICY *guest =
857 (const IGVM_VHS_GUEST_POLICY *)header_data;
858
859 if (guest->compatibility_mask & ctx->compatibility_mask) {
860 ctx->sev_policy = guest->policy;
861 }
862 return 0;
863 }
864
865 static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp)
866 {
867 int32_t header_count;
868 unsigned header_index;
869 IgvmHandle header_handle;
870 IGVM_VHS_SUPPORTED_PLATFORM *platform;
871 uint32_t compatibility_mask_sev = 0;
872 uint32_t compatibility_mask_sev_es = 0;
873 uint32_t compatibility_mask_sev_snp = 0;
874 uint32_t compatibility_mask = 0;
875
876 header_count = igvm_header_count(ctx->cfg->file,
877 IGVM_HEADER_SECTION_PLATFORM);
878 if (header_count < 0) {
879 error_setg(errp,
880 "Invalid platform header count in IGVM file. Error code: %X",
881 header_count);
882 return -1;
883 }
884
885 for (header_index = 0; header_index < (unsigned)header_count;
886 header_index++) {
887 IgvmVariableHeaderType typ = igvm_get_header_type(
888 ctx->cfg->file, IGVM_HEADER_SECTION_PLATFORM, header_index);
889 typ = igvm_vht_type(typ);
890 if (typ == IGVM_VHT_SUPPORTED_PLATFORM) {
891 header_handle = igvm_get_header(
892 ctx->cfg->file, IGVM_HEADER_SECTION_PLATFORM, header_index);
893 if (header_handle < 0) {
894 error_setg(errp,
895 "Invalid platform header in IGVM file. "
896 "Index: %d, Error code: %X",
897 header_index, header_handle);
898 return -1;
899 }
900 platform =
901 (IGVM_VHS_SUPPORTED_PLATFORM *)(igvm_get_buffer(ctx->cfg->file,
902 header_handle));
903 if (platform == NULL) {
904 error_setg(errp, "IGVM: No buffer for handle %d", header_handle);
905 igvm_free_buffer(ctx->cfg->file, header_handle);
906 return -1;
907 }
908
909 platform = (IGVM_VHS_SUPPORTED_PLATFORM *)((void *)platform
910 + sizeof(IGVM_VHS_VARIABLE_HEADER));
911 if ((platform->platform_type == IGVM_PLATFORM_TYPE_SEV_ES) &&
912 ctx->machine_state->cgs) {
913 if (ctx->cgsc->check_support(
914 CGS_PLATFORM_SEV_ES, platform->platform_version,
915 platform->highest_vtl, platform->shared_gpa_boundary)) {
916 compatibility_mask_sev_es = platform->compatibility_mask;
917 }
918 } else if ((platform->platform_type == IGVM_PLATFORM_TYPE_SEV) &&
919 ctx->machine_state->cgs) {
920 if (ctx->cgsc->check_support(
921 CGS_PLATFORM_SEV, platform->platform_version,
922 platform->highest_vtl, platform->shared_gpa_boundary)) {
923 compatibility_mask_sev = platform->compatibility_mask;
924 }
925 } else if ((platform->platform_type ==
926 IGVM_PLATFORM_TYPE_SEV_SNP) &&
927 ctx->machine_state->cgs) {
928 if (ctx->cgsc->check_support(
929 CGS_PLATFORM_SEV_SNP, platform->platform_version,
930 platform->highest_vtl, platform->shared_gpa_boundary)) {
931 compatibility_mask_sev_snp = platform->compatibility_mask;
932 }
933 } else if (platform->platform_type == IGVM_PLATFORM_TYPE_NATIVE) {
934 compatibility_mask = platform->compatibility_mask;
935 }
936 igvm_free_buffer(ctx->cfg->file, header_handle);
937 }
938 }
939 /* Choose the strongest supported isolation technology */
940 if (compatibility_mask_sev_snp != 0) {
941 ctx->compatibility_mask = compatibility_mask_sev_snp;
942 ctx->platform_type = IGVM_PLATFORM_TYPE_SEV_SNP;
943 } else if (compatibility_mask_sev_es != 0) {
944 ctx->compatibility_mask = compatibility_mask_sev_es;
945 ctx->platform_type = IGVM_PLATFORM_TYPE_SEV_ES;
946 } else if (compatibility_mask_sev != 0) {
947 ctx->compatibility_mask = compatibility_mask_sev;
948 ctx->platform_type = IGVM_PLATFORM_TYPE_SEV;
949 } else if (compatibility_mask != 0) {
950 ctx->compatibility_mask = compatibility_mask;
951 ctx->platform_type = IGVM_PLATFORM_TYPE_NATIVE;
952 } else {
953 error_setg(
954 errp,
955 "IGVM file does not describe a compatible supported platform");
956 return -1;
957 }
958 return 0;
959 }
960
961 static int qigvm_handle_policy(QIgvm *ctx, Error **errp)
962 {
963 if (ctx->platform_type == IGVM_PLATFORM_TYPE_SEV_SNP) {
964 int id_block_len = 0;
965 int id_auth_len = 0;
966 if (ctx->id_block) {
967 ctx->id_block->policy = ctx->sev_policy;
968 id_block_len = sizeof(struct sev_id_block);
969 id_auth_len = sizeof(struct sev_id_authentication);
970 }
971 return ctx->cgsc->set_guest_policy(GUEST_POLICY_SEV, ctx->sev_policy,
972 ctx->id_block, id_block_len,
973 ctx->id_auth, id_auth_len, errp);
974 }
975 return 0;
976 }
977
978 IgvmHandle qigvm_file_init(char *filename, Error **errp)
979 {
980 IgvmHandle igvm;
981 g_autofree uint8_t *buf = NULL;
982 unsigned long len;
983 g_autoptr(GError) gerr = NULL;
984
985 if (!g_file_get_contents(filename, (gchar **)&buf, &len, &gerr)) {
986 error_setg(errp, "Unable to load %s: %s", filename, gerr->message);
987 return -1;
988 }
989
990 igvm = igvm_new_from_binary(buf, len);
991 if (igvm < 0) {
992 error_setg(errp, "Unable to parse IGVM file %s: %d", filename, igvm);
993 return -1;
994 }
995
996 trace_igvm_file_loaded(filename, igvm);
997 return igvm;
998 }
999
1000 int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state,
1001 bool onlyVpContext, Error **errp)
1002 {
1003 int32_t header_count;
1004 QIgvmParameterData *parameter;
1005 int retval = -1;
1006 QIgvm ctx;
1007
1008 memset(&ctx, 0, sizeof(ctx));
1009 if (cfg->file < 0) {
1010 error_setg(errp, "No IGVM file loaded.");
1011 return -1;
1012 }
1013 ctx.cfg = cfg;
1014 trace_igvm_process_file(cfg->file, onlyVpContext);
1015
1016 ctx.machine_state = machine_state;
1017
1018 /*
1019 * The ConfidentialGuestSupport object is optional and allows a confidential
1020 * guest platform to perform extra processing, such as page measurement, on
1021 * IGVM directives.
1022 */
1023 ctx.cgsc = machine_state->cgs ?
1024 CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(machine_state->cgs) :
1025 NULL;
1026
1027 /*
1028 * Check that the IGVM file provides configuration for the current
1029 * platform
1030 */
1031 if (qigvm_supported_platform_compat_mask(&ctx, errp) < 0) {
1032 goto cleanup;
1033 }
1034
1035 header_count = igvm_header_count(ctx.cfg->file,
1036 IGVM_HEADER_SECTION_DIRECTIVE);
1037 if (header_count <= 0) {
1038 error_setg(
1039 errp, "Invalid directive header count in IGVM file. Error code: %X",
1040 header_count);
1041 goto cleanup;
1042 }
1043
1044 QTAILQ_INIT(&ctx.parameter_data);
1045
1046 for (ctx.current_header_index = 0;
1047 ctx.current_header_index < (unsigned)header_count;
1048 ctx.current_header_index++) {
1049 IgvmVariableHeaderType raw_type = igvm_get_header_type(
1050 ctx.cfg->file, IGVM_HEADER_SECTION_DIRECTIVE,
1051 ctx.current_header_index);
1052 if (!onlyVpContext || igvm_vht_type(raw_type) == IGVM_VHT_VP_CONTEXT) {
1053 if (qigvm_handler(&ctx, raw_type, errp) < 0) {
1054 goto cleanup_parameters;
1055 }
1056 }
1057 }
1058
1059 /*
1060 * If only processing the VP context then we don't need to process
1061 * any more of the file.
1062 */
1063 if (onlyVpContext) {
1064 retval = 0;
1065 goto cleanup_parameters;
1066 }
1067
1068 header_count =
1069 igvm_header_count(ctx.cfg->file, IGVM_HEADER_SECTION_INITIALIZATION);
1070 if (header_count < 0) {
1071 error_setg(
1072 errp,
1073 "Invalid initialization header count in IGVM file. Error code: %X",
1074 header_count);
1075 goto cleanup_parameters;
1076 }
1077
1078 for (ctx.current_header_index = 0;
1079 ctx.current_header_index < (unsigned)header_count;
1080 ctx.current_header_index++) {
1081 IgvmVariableHeaderType type =
1082 igvm_get_header_type(ctx.cfg->file,
1083 IGVM_HEADER_SECTION_INITIALIZATION,
1084 ctx.current_header_index);
1085 if (qigvm_handler(&ctx, type, errp) < 0) {
1086 goto cleanup_parameters;
1087 }
1088 }
1089
1090 /*
1091 * Contiguous pages of data with compatible flags are grouped together in
1092 * order to reduce the number of memory regions we create. Make sure the
1093 * last group is processed with this call.
1094 */
1095 retval = qigvm_process_mem_page(&ctx, NULL, errp);
1096
1097 if (retval == 0) {
1098 retval = qigvm_handle_policy(&ctx, errp);
1099 }
1100
1101 cleanup_parameters:
1102 QTAILQ_FOREACH(parameter, &ctx.parameter_data, next)
1103 {
1104 g_free(parameter->data);
1105 parameter->data = NULL;
1106 }
1107 g_free(ctx.id_block);
1108 g_free(ctx.id_auth);
1109
1110 cleanup:
1111 return retval;
1112 }
1113
1114 /*
1115 * cleanup any memory regions created by qigvm_prepare_memory()
1116 */
1117 void qigvm_cleanup_memory(IgvmCfg *cfg)
1118 {
1119 IgvmMemoryRegion *imr, *tmp;
1120
1121 QTAILQ_FOREACH_SAFE(imr, &cfg->memory_regions, next, tmp)
1122 {
1123 trace_qigvm_cleanup_memory(imr->mr->name);
1124 memory_region_del_subregion(get_system_memory(), imr->mr);
1125 vmstate_unregister_ram(imr->mr, NULL);
1126 QTAILQ_REMOVE(&cfg->memory_regions, imr, next);
1127 /* this triggers MemoryRegion cleanup */
1128 object_unparent(OBJECT(imr->mr));
1129 g_free(imr);
1130 }
1131 }