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