]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PeilessStartupLib/IntelTdx.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / PeilessStartupLib / IntelTdx.c
1 /** @file
2 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
3 SPDX-License-Identifier: BSD-2-Clause-Patent
4 **/
5
6 #include <PiPei.h>
7 #include <Library/BaseLib.h>
8 #include <Library/BaseMemoryLib.h>
9 #include <Library/DebugLib.h>
10 #include <Guid/VariableFormat.h>
11 #include <Guid/SystemNvDataGuid.h>
12 #include <IndustryStandard/Tpm20.h>
13 #include <IndustryStandard/UefiTcgPlatform.h>
14 #include <Library/HobLib.h>
15 #include <Library/PrintLib.h>
16 #include <Library/TpmMeasurementLib.h>
17
18 #include "PeilessStartupInternal.h"
19
20 #pragma pack(1)
21
22 #define HANDOFF_TABLE_DESC "TdxTable"
23 typedef struct {
24 UINT8 TableDescriptionSize;
25 UINT8 TableDescription[sizeof (HANDOFF_TABLE_DESC)];
26 UINT64 NumberOfTables;
27 EFI_CONFIGURATION_TABLE TableEntry[1];
28 } TDX_HANDOFF_TABLE_POINTERS2;
29
30 #define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)"
31 typedef struct {
32 UINT8 BlobDescriptionSize;
33 UINT8 BlobDescription[sizeof (FV_HANDOFF_TABLE_DESC)];
34 EFI_PHYSICAL_ADDRESS BlobBase;
35 UINT64 BlobLength;
36 } FV_HANDOFF_TABLE_POINTERS2;
37
38 #pragma pack()
39
40 /**
41 Check padding data all bit should be 1.
42
43 @param[in] Buffer - A pointer to buffer header
44 @param[in] BufferSize - Buffer size
45
46 @retval TRUE - The padding data is valid.
47 @retval TRUE - The padding data is invalid.
48
49 **/
50 BOOLEAN
51 CheckPaddingData (
52 IN UINT8 *Buffer,
53 IN UINT32 BufferSize
54 )
55 {
56 UINT32 index;
57
58 for (index = 0; index < BufferSize; index++) {
59 if (Buffer[index] != 0xFF) {
60 return FALSE;
61 }
62 }
63
64 return TRUE;
65 }
66
67 /**
68 Check the integrity of CFV data.
69
70 @param[in] TdxCfvBase - A pointer to CFV header
71 @param[in] TdxCfvSize - CFV data size
72
73 @retval TRUE - The CFV data is valid.
74 @retval FALSE - The CFV data is invalid.
75
76 **/
77 BOOLEAN
78 EFIAPI
79 TdxValidateCfv (
80 IN UINT8 *TdxCfvBase,
81 IN UINT32 TdxCfvSize
82 )
83 {
84 UINT16 Checksum;
85 UINTN VariableBase;
86 UINT32 VariableOffset;
87 UINT32 VariableOffsetBeforeAlign;
88 EFI_FIRMWARE_VOLUME_HEADER *CfvFvHeader;
89 VARIABLE_STORE_HEADER *CfvVariableStoreHeader;
90 AUTHENTICATED_VARIABLE_HEADER *VariableHeader;
91
92 static EFI_GUID FvHdrGUID = EFI_SYSTEM_NV_DATA_FV_GUID;
93 static EFI_GUID VarStoreHdrGUID = EFI_AUTHENTICATED_VARIABLE_GUID;
94
95 VariableOffset = 0;
96
97 if (TdxCfvBase == NULL) {
98 DEBUG ((DEBUG_ERROR, "TDX CFV: CFV pointer is NULL\n"));
99 return FALSE;
100 }
101
102 //
103 // Verify the header zerovetor, filesystemguid,
104 // revision, signature, attributes, fvlength, checksum
105 // HeaderLength cannot be an odd number
106 //
107 CfvFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)TdxCfvBase;
108
109 if ((!IsZeroBuffer (CfvFvHeader->ZeroVector, 16)) ||
110 (!CompareGuid (&FvHdrGUID, &CfvFvHeader->FileSystemGuid)) ||
111 (CfvFvHeader->Signature != EFI_FVH_SIGNATURE) ||
112 (CfvFvHeader->Attributes != 0x4feff) ||
113 (CfvFvHeader->Revision != EFI_FVH_REVISION) ||
114 (CfvFvHeader->FvLength != TdxCfvSize)
115 )
116 {
117 DEBUG ((DEBUG_ERROR, "TDX CFV: Basic FV headers were invalid\n"));
118 return FALSE;
119 }
120
121 //
122 // Verify the header checksum
123 //
124 Checksum = CalculateSum16 ((VOID *)CfvFvHeader, CfvFvHeader->HeaderLength);
125
126 if (Checksum != 0) {
127 DEBUG ((DEBUG_ERROR, "TDX CFV: FV checksum was invalid\n"));
128 return FALSE;
129 }
130
131 //
132 // Verify the header signature, size, format, state
133 //
134 CfvVariableStoreHeader = (VARIABLE_STORE_HEADER *)(TdxCfvBase + CfvFvHeader->HeaderLength);
135 if ((!CompareGuid (&VarStoreHdrGUID, &CfvVariableStoreHeader->Signature)) ||
136 (CfvVariableStoreHeader->Format != VARIABLE_STORE_FORMATTED) ||
137 (CfvVariableStoreHeader->State != VARIABLE_STORE_HEALTHY) ||
138 (CfvVariableStoreHeader->Size > (CfvFvHeader->FvLength - CfvFvHeader->HeaderLength)) ||
139 (CfvVariableStoreHeader->Size < sizeof (VARIABLE_STORE_HEADER))
140 )
141 {
142 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable Store header was invalid\n"));
143 return FALSE;
144 }
145
146 //
147 // Verify the header startId, state
148 // Verify data to the end
149 //
150 VariableBase = (UINTN)TdxCfvBase + CfvFvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER);
151 while (VariableOffset < (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {
152 VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)(VariableBase + VariableOffset);
153 if (VariableHeader->StartId != VARIABLE_DATA) {
154 if (!CheckPaddingData ((UINT8 *)VariableHeader, CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - VariableOffset)) {
155 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
156 return FALSE;
157 }
158
159 VariableOffset = CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
160 } else {
161 if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
162 (VariableHeader->State == VAR_DELETED) ||
163 (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
164 (VariableHeader->State == VAR_ADDED)))
165 {
166 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
167 return FALSE;
168 }
169
170 VariableOffset += sizeof (AUTHENTICATED_VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize;
171 // Verify VariableOffset should be less than or equal CfvVariableStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER)
172 if (VariableOffset > (CfvVariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {
173 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
174 return FALSE;
175 }
176
177 VariableOffsetBeforeAlign = VariableOffset;
178 // 4 byte align
179 VariableOffset = (VariableOffset + 3) & (UINTN)(~3);
180
181 if (!CheckPaddingData ((UINT8 *)(VariableBase + VariableOffsetBeforeAlign), VariableOffset - VariableOffsetBeforeAlign)) {
182 DEBUG ((DEBUG_ERROR, "TDX CFV: Variable header was invalid\n"));
183 return FALSE;
184 }
185 }
186 }
187
188 return TRUE;
189 }
190
191 /**
192 Measure the Hoblist passed from the VMM.
193
194 @param[in] VmmHobList The Hoblist pass the firmware
195
196 @retval EFI_SUCCESS Fv image is measured successfully
197 or it has been already measured.
198 @retval Others Other errors as indicated
199 **/
200 EFI_STATUS
201 EFIAPI
202 MeasureHobList (
203 IN CONST VOID *VmmHobList
204 )
205 {
206 EFI_PEI_HOB_POINTERS Hob;
207 TDX_HANDOFF_TABLE_POINTERS2 HandoffTables;
208 EFI_STATUS Status;
209
210 if (!TdIsEnabled ()) {
211 ASSERT (FALSE);
212 return EFI_UNSUPPORTED;
213 }
214
215 Hob.Raw = (UINT8 *)VmmHobList;
216
217 //
218 // Parse the HOB list until end of list.
219 //
220 while (!END_OF_HOB_LIST (Hob)) {
221 Hob.Raw = GET_NEXT_HOB (Hob);
222 }
223
224 //
225 // Init the log event for HOB measurement
226 //
227
228 HandoffTables.TableDescriptionSize = sizeof (HandoffTables.TableDescription);
229 CopyMem (HandoffTables.TableDescription, HANDOFF_TABLE_DESC, sizeof (HandoffTables.TableDescription));
230 HandoffTables.NumberOfTables = 1;
231 CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), &gUefiOvmfPkgTokenSpaceGuid);
232 HandoffTables.TableEntry[0].VendorTable = (VOID *)VmmHobList;
233
234 Status = TpmMeasureAndLogData (
235 1, // PCRIndex
236 EV_EFI_HANDOFF_TABLES2, // EventType
237 (VOID *)&HandoffTables, // EventData
238 sizeof (HandoffTables), // EventSize
239 (UINT8 *)(UINTN)VmmHobList, // HashData
240 (UINTN)((UINT8 *)Hob.Raw - (UINT8 *)VmmHobList) // HashDataLen
241 );
242
243 if (EFI_ERROR (Status)) {
244 ASSERT (FALSE);
245 }
246
247 return Status;
248 }
249
250 /**
251 Get the FvName from the FV header.
252
253 Causion: The FV is untrusted input.
254
255 @param[in] FvBase Base address of FV image.
256 @param[in] FvLength Length of FV image.
257
258 @return FvName pointer
259 @retval NULL FvName is NOT found
260 **/
261 VOID *
262 GetFvName (
263 IN EFI_PHYSICAL_ADDRESS FvBase,
264 IN UINT64 FvLength
265 )
266 {
267 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
268 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
269
270 if (FvBase >= MAX_ADDRESS) {
271 return NULL;
272 }
273
274 if (FvLength >= MAX_ADDRESS - FvBase) {
275 return NULL;
276 }
277
278 if (FvLength < sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {
279 return NULL;
280 }
281
282 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
283 if (FvHeader->ExtHeaderOffset < sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {
284 return NULL;
285 }
286
287 if (FvHeader->ExtHeaderOffset + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) {
288 return NULL;
289 }
290
291 FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset);
292
293 return &FvExtHeader->FvName;
294 }
295
296 /**
297 Measure FV image.
298
299 @param[in] FvBase Base address of FV image.
300 @param[in] FvLength Length of FV image.
301 @param[in] PcrIndex Index of PCR
302
303 @retval EFI_SUCCESS Fv image is measured successfully
304 or it has been already measured.
305 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
306 @retval EFI_DEVICE_ERROR The command was unsuccessful.
307
308 **/
309 EFI_STATUS
310 EFIAPI
311 MeasureFvImage (
312 IN EFI_PHYSICAL_ADDRESS FvBase,
313 IN UINT64 FvLength,
314 IN UINT8 PcrIndex
315 )
316 {
317 EFI_STATUS Status;
318 FV_HANDOFF_TABLE_POINTERS2 FvBlob2;
319 VOID *FvName;
320
321 //
322 // Init the log event for FV measurement
323 //
324 FvBlob2.BlobDescriptionSize = sizeof (FvBlob2.BlobDescription);
325 CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof (FvBlob2.BlobDescription));
326 FvName = GetFvName (FvBase, FvLength);
327 if (FvName != NULL) {
328 AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof (FvBlob2.BlobDescription), "Fv(%g)", FvName);
329 }
330
331 FvBlob2.BlobBase = FvBase;
332 FvBlob2.BlobLength = FvLength;
333
334 Status = TpmMeasureAndLogData (
335 1, // PCRIndex
336 EV_EFI_PLATFORM_FIRMWARE_BLOB2, // EventType
337 (VOID *)&FvBlob2, // EventData
338 sizeof (FvBlob2), // EventSize
339 (UINT8 *)(UINTN)FvBase, // HashData
340 (UINTN)(FvLength) // HashDataLen
341 );
342
343 if (EFI_ERROR (Status)) {
344 DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));
345 ASSERT (FALSE);
346 }
347
348 return Status;
349 }