1 /* 2 * Copyright (c) 2025 Intel Corporation 3 * Author: Isaku Yamahata <isaku.yamahata at gmail.com> 4 * <isaku.yamahata at intel.com> 5 * Xiaoyao Li <xiaoyao.li@intel.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #include "qemu/osdep.h" 11 #include "qemu/error-report.h" 12 13 #include "hw/i386/pc.h" 14 #include "hw/i386/tdvf.h" 15 #include "system/kvm.h" 16 17 #define TDX_METADATA_OFFSET_GUID "e47a6535-984a-4798-865e-4685a7bf8ec2" 18 #define TDX_METADATA_VERSION 1 19 #define TDVF_SIGNATURE 0x46564454 /* TDVF as little endian */ 20 #define TDVF_ALIGNMENT 4096 21 22 /* 23 * the raw structs read from TDVF keeps the name convention in 24 * TDVF Design Guide spec. 25 */ 26 typedef struct { 27 uint32_t DataOffset; 28 uint32_t RawDataSize; 29 uint64_t MemoryAddress; 30 uint64_t MemoryDataSize; 31 uint32_t Type; 32 uint32_t Attributes; 33 } TdvfSectionEntry; 34 35 typedef struct { 36 uint32_t Signature; 37 uint32_t Length; 38 uint32_t Version; 39 uint32_t NumberOfSectionEntries; 40 TdvfSectionEntry SectionEntries[]; 41 } TdvfMetadata; 42 43 struct tdx_metadata_offset { 44 uint32_t offset; 45 }; 46 47 static TdvfMetadata *tdvf_get_metadata(void *flash_ptr, int size) 48 { 49 TdvfMetadata *metadata; 50 uint32_t offset = 0; 51 uint8_t *data; 52 53 if ((uint32_t) size != size) { 54 return NULL; 55 } 56 57 if (pc_system_ovmf_table_find(TDX_METADATA_OFFSET_GUID, &data, NULL)) { 58 offset = size - le32_to_cpu(((struct tdx_metadata_offset *)data)->offset); 59 60 if (offset + sizeof(*metadata) > size) { 61 return NULL; 62 } 63 } else { 64 error_report("Cannot find TDX_METADATA_OFFSET_GUID"); 65 return NULL; 66 } 67 68 metadata = flash_ptr + offset; 69 70 /* Finally, verify the signature to determine if this is a TDVF image. */ 71 metadata->Signature = le32_to_cpu(metadata->Signature); 72 if (metadata->Signature != TDVF_SIGNATURE) { 73 error_report("Invalid TDVF signature in metadata!"); 74 return NULL; 75 } 76 77 /* Sanity check that the TDVF doesn't overlap its own metadata. */ 78 metadata->Length = le32_to_cpu(metadata->Length); 79 if (offset + metadata->Length > size) { 80 return NULL; 81 } 82 83 /* Only version 1 is supported/defined. */ 84 metadata->Version = le32_to_cpu(metadata->Version); 85 if (metadata->Version != TDX_METADATA_VERSION) { 86 return NULL; 87 } 88 89 return metadata; 90 } 91 92 static int tdvf_parse_and_check_section_entry(const TdvfSectionEntry *src, 93 TdxFirmwareEntry *entry) 94 { 95 entry->data_offset = le32_to_cpu(src->DataOffset); 96 entry->data_len = le32_to_cpu(src->RawDataSize); 97 entry->address = le64_to_cpu(src->MemoryAddress); 98 entry->size = le64_to_cpu(src->MemoryDataSize); 99 entry->type = le32_to_cpu(src->Type); 100 entry->attributes = le32_to_cpu(src->Attributes); 101 102 /* sanity check */ 103 if (entry->size < entry->data_len) { 104 error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%"PRIx64, 105 entry->data_len, entry->size); 106 return -1; 107 } 108 if (!QEMU_IS_ALIGNED(entry->address, TDVF_ALIGNMENT)) { 109 error_report("MemoryAddress 0x%"PRIx64" not page aligned", entry->address); 110 return -1; 111 } 112 if (!QEMU_IS_ALIGNED(entry->size, TDVF_ALIGNMENT)) { 113 error_report("MemoryDataSize 0x%"PRIx64" not page aligned", entry->size); 114 return -1; 115 } 116 117 switch (entry->type) { 118 case TDVF_SECTION_TYPE_BFV: 119 case TDVF_SECTION_TYPE_CFV: 120 /* The sections that must be copied from firmware image to TD memory */ 121 if (entry->data_len == 0) { 122 error_report("%d section with RawDataSize == 0", entry->type); 123 return -1; 124 } 125 break; 126 case TDVF_SECTION_TYPE_TD_HOB: 127 case TDVF_SECTION_TYPE_TEMP_MEM: 128 /* The sections that no need to be copied from firmware image */ 129 if (entry->data_len != 0) { 130 error_report("%d section with RawDataSize 0x%x != 0", 131 entry->type, entry->data_len); 132 return -1; 133 } 134 break; 135 default: 136 error_report("TDVF contains unsupported section type %d", entry->type); 137 return -1; 138 } 139 140 return 0; 141 } 142 143 int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size) 144 { 145 g_autofree TdvfSectionEntry *sections = NULL; 146 TdvfMetadata *metadata; 147 ssize_t entries_size; 148 int i; 149 150 metadata = tdvf_get_metadata(flash_ptr, size); 151 if (!metadata) { 152 return -EINVAL; 153 } 154 155 /* load and parse metadata entries */ 156 fw->nr_entries = le32_to_cpu(metadata->NumberOfSectionEntries); 157 if (fw->nr_entries < 2) { 158 error_report("Invalid number of fw entries (%u) in TDVF Metadata", 159 fw->nr_entries); 160 return -EINVAL; 161 } 162 163 entries_size = fw->nr_entries * sizeof(TdvfSectionEntry); 164 if (metadata->Length != sizeof(*metadata) + entries_size) { 165 error_report("TDVF metadata len (0x%x) mismatch, expected (0x%x)", 166 metadata->Length, 167 (uint32_t)(sizeof(*metadata) + entries_size)); 168 return -EINVAL; 169 } 170 171 fw->entries = g_new(TdxFirmwareEntry, fw->nr_entries); 172 sections = g_new(TdvfSectionEntry, fw->nr_entries); 173 174 memcpy(sections, (void *)metadata + sizeof(*metadata), entries_size); 175 176 for (i = 0; i < fw->nr_entries; i++) { 177 if (tdvf_parse_and_check_section_entry(§ions[i], &fw->entries[i])) { 178 goto err; 179 } 180 } 181 182 fw->mem_ptr = flash_ptr; 183 return 0; 184 185 err: 186 fw->entries = 0; 187 g_free(fw->entries); 188 return -EINVAL; 189 } 190