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