From: Brijesh Singh <brijesh.singh@xxxxxxx> OVMF reserves various pages so they can be pre-initialized/validated prior to launching the guest. Add support for populating these pages with the expected content. Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx> Signed-off-by: Michael Roth <michael.roth@xxxxxxx> Co-developed-by: Pankaj Gupta <pankaj.gupta@xxxxxxx> Signed-off-by: Pankaj Gupta <pankaj.gupta@xxxxxxx> --- target/i386/sev.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c index d9d1d97f0c..504f641038 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1016,15 +1016,89 @@ sev_launch_finish(SevCommonState *sev_common) migrate_add_blocker(&sev_mig_blocker, &error_fatal); } +static int +snp_launch_update_data(uint64_t gpa, void *hva, uint32_t len, int type) +{ + SevLaunchUpdateData *data; + + data = g_new0(SevLaunchUpdateData, 1); + data->gpa = gpa; + data->hva = hva; + data->len = len; + data->type = type; + + QTAILQ_INSERT_TAIL(&launch_update, data, next); + + return 0; +} + +static int +snp_metadata_desc_to_page_type(int desc_type) +{ + switch (desc_type) { + /* Add the umeasured prevalidated pages as a zero page */ + case SEV_DESC_TYPE_SNP_SEC_MEM: return KVM_SEV_SNP_PAGE_TYPE_ZERO; + case SEV_DESC_TYPE_SNP_SECRETS: return KVM_SEV_SNP_PAGE_TYPE_SECRETS; + case SEV_DESC_TYPE_CPUID: return KVM_SEV_SNP_PAGE_TYPE_CPUID; + default: + return KVM_SEV_SNP_PAGE_TYPE_ZERO; + } +} + +static void +snp_populate_metadata_pages(SevSnpGuestState *sev_snp, + OvmfSevMetadata *metadata) +{ + OvmfSevMetadataDesc *desc; + int type, ret, i; + void *hva; + MemoryRegion *mr = NULL; + + for (i = 0; i < metadata->num_desc; i++) { + desc = &metadata->descs[i]; + + type = snp_metadata_desc_to_page_type(desc->type); + + hva = gpa2hva(&mr, desc->base, desc->len, NULL); + if (!hva) { + error_report("%s: Failed to get HVA for GPA 0x%x sz 0x%x", + __func__, desc->base, desc->len); + exit(1); + } + + ret = snp_launch_update_data(desc->base, hva, desc->len, type); + if (ret) { + error_report("%s: Failed to add metadata page gpa 0x%x+%x type %d", + __func__, desc->base, desc->len, desc->type); + exit(1); + } + } +} + static void sev_snp_launch_finish(SevCommonState *sev_common) { int ret, error; Error *local_err = NULL; + OvmfSevMetadata *metadata; SevLaunchUpdateData *data; SevSnpGuestState *sev_snp = SEV_SNP_GUEST(sev_common); struct kvm_sev_snp_launch_finish *finish = &sev_snp->kvm_finish_conf; + /* + * To boot the SNP guest, the hypervisor is required to populate the CPUID + * and Secrets page before finalizing the launch flow. The location of + * the secrets and CPUID page is available through the OVMF metadata GUID. + */ + metadata = pc_system_get_ovmf_sev_metadata_ptr(); + if (metadata == NULL) { + error_report("%s: Failed to locate SEV metadata header", __func__); + exit(1); + } + + /* Populate all the metadata pages */ + snp_populate_metadata_pages(sev_snp, metadata); + QTAILQ_FOREACH(data, &launch_update, next) { ret = sev_snp_launch_update(sev_snp, data); if (ret) { -- 2.34.1