]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c
OvmfPkg: Refactor ProcessHobList
[mirror_edk2.git] / OvmfPkg / IntelTdx / TdxHelperLib / SecTdxHelper.c
1 /** @file
2 TdxHelper Functions which are used in SEC phase
3
4 Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <PiPei.h>
11 #include <Library/BaseLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/HobLib.h>
14 #include <Library/BaseCryptLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <IndustryStandard/Tdx.h>
17 #include <IndustryStandard/IntelTdx.h>
18 #include <IndustryStandard/Tpm20.h>
19 #include <Library/TdxLib.h>
20 #include <Library/TdxMailboxLib.h>
21 #include <Library/SynchronizationLib.h>
22 #include <Pi/PrePiHob.h>
23 #include <WorkArea.h>
24 #include <ConfidentialComputingGuestAttr.h>
25 #include <Library/TdxHelperLib.h>
26
27 #define ALIGNED_2MB_MASK 0x1fffff
28 #define MEGABYTE_SHIFT 20
29
30 #define ACCEPT_CHUNK_SIZE SIZE_32MB
31 #define AP_STACK_SIZE SIZE_16KB
32 #define APS_STACK_SIZE(CpusNum) (ALIGN_VALUE(CpusNum*AP_STACK_SIZE, SIZE_2MB))
33
34 /**
35 Build the GuidHob for tdx measurements which were done in SEC phase.
36 The measurement values are stored in WorkArea.
37
38 @retval EFI_SUCCESS The GuidHob is built successfully
39 @retval Others Other errors as indicated
40 **/
41 EFI_STATUS
42 InternalBuildGuidHobForTdxMeasurement (
43 VOID
44 );
45
46 /**
47 This function will be called to accept pages. Only BSP accepts pages.
48
49 TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To
50 simplify the implementation, the Memory to be accpeted is splitted
51 into 3 parts:
52 ----------------- <-- StartAddress1 (not 2M aligned)
53 | part 1 | Length1 < 2M
54 |---------------| <-- StartAddress2 (2M aligned)
55 | | Length2 = Integer multiples of 2M
56 | part 2 |
57 | |
58 |---------------| <-- StartAddress3
59 | part 3 | Length3 < 2M
60 |---------------|
61
62 @param[in] PhysicalAddress Start physical adress
63 @param[in] PhysicalEnd End physical address
64
65 @retval EFI_SUCCESS Accept memory successfully
66 @retval Others Other errors as indicated
67 **/
68 STATIC
69 EFI_STATUS
70 EFIAPI
71 BspAcceptMemoryResourceRange (
72 IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
73 IN EFI_PHYSICAL_ADDRESS PhysicalEnd
74 )
75 {
76 EFI_STATUS Status;
77 UINT32 AcceptPageSize;
78 UINT64 StartAddress1;
79 UINT64 StartAddress2;
80 UINT64 StartAddress3;
81 UINT64 TotalLength;
82 UINT64 Length1;
83 UINT64 Length2;
84 UINT64 Length3;
85 UINT64 Pages;
86
87 AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
88 TotalLength = PhysicalEnd - PhysicalAddress;
89 StartAddress1 = 0;
90 StartAddress2 = 0;
91 StartAddress3 = 0;
92 Length1 = 0;
93 Length2 = 0;
94 Length3 = 0;
95
96 if (TotalLength == 0) {
97 return EFI_SUCCESS;
98 }
99
100 if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
101 StartAddress1 = PhysicalAddress;
102 Length1 = ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAddress;
103 if (Length1 >= TotalLength) {
104 Length1 = TotalLength;
105 }
106
107 PhysicalAddress += Length1;
108 TotalLength -= Length1;
109 }
110
111 if (TotalLength > SIZE_2MB) {
112 StartAddress2 = PhysicalAddress;
113 Length2 = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
114 PhysicalAddress += Length2;
115 TotalLength -= Length2;
116 }
117
118 if (TotalLength) {
119 StartAddress3 = PhysicalAddress;
120 Length3 = TotalLength;
121 }
122
123 Status = EFI_SUCCESS;
124 if (Length1 > 0) {
125 Pages = Length1 / SIZE_4KB;
126 Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
127 if (EFI_ERROR (Status)) {
128 return Status;
129 }
130 }
131
132 if (Length2 > 0) {
133 Pages = Length2 / AcceptPageSize;
134 Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
135 if (EFI_ERROR (Status)) {
136 return Status;
137 }
138 }
139
140 if (Length3 > 0) {
141 Pages = Length3 / SIZE_4KB;
142 Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
143 ASSERT (!EFI_ERROR (Status));
144 if (EFI_ERROR (Status)) {
145 return Status;
146 }
147 }
148
149 return Status;
150 }
151
152 /**
153 * This function is called by BSP and APs to accept memory.
154 * Note:
155 * The input PhysicalStart/PhysicalEnd indicates the whole memory region
156 * to be accepted. BSP or AP only accepts one piece in the whole memory region.
157 *
158 * @param CpuIndex vCPU index
159 * @param CpusNum Total vCPU number of a Tdx guest
160 * @param PhysicalStart Start address of a memory region which is to be accepted
161 * @param PhysicalEnd End address of a memory region which is to be accepted
162 *
163 * @retval EFI_SUCCESS Successfully accept the memory
164 * @retval Other Other errors as indicated
165 */
166 STATIC
167 EFI_STATUS
168 EFIAPI
169 BspApAcceptMemoryResourceRange (
170 UINT32 CpuIndex,
171 UINT32 CpusNum,
172 EFI_PHYSICAL_ADDRESS PhysicalStart,
173 EFI_PHYSICAL_ADDRESS PhysicalEnd
174 )
175 {
176 UINT64 Status;
177 UINT64 Pages;
178 UINT64 Stride;
179 UINT64 AcceptPageSize;
180 EFI_PHYSICAL_ADDRESS PhysicalAddress;
181
182 AcceptPageSize = (UINT64)(UINTN)FixedPcdGet32 (PcdTdxAcceptPageSize);
183
184 Status = EFI_SUCCESS;
185 Stride = (UINTN)CpusNum * ACCEPT_CHUNK_SIZE;
186 PhysicalAddress = PhysicalStart + ACCEPT_CHUNK_SIZE * (UINTN)CpuIndex;
187
188 while (!EFI_ERROR (Status) && PhysicalAddress < PhysicalEnd) {
189 Pages = MIN (ACCEPT_CHUNK_SIZE, PhysicalEnd - PhysicalAddress) / AcceptPageSize;
190 Status = TdAcceptPages (PhysicalAddress, Pages, (UINT32)(UINTN)AcceptPageSize);
191 ASSERT (!EFI_ERROR (Status));
192 PhysicalAddress += Stride;
193 }
194
195 return EFI_SUCCESS;
196 }
197
198 /**
199 * This function is called by APs to accept memory.
200 *
201 * @param CpuIndex vCPU index of an AP
202 * @param PhysicalStart Start address of a memory region which is to be accepted
203 * @param PhysicalEnd End address of a memory region which is to be accepted
204 *
205 * @retval EFI_SUCCESS Successfully accept the memory
206 * @retval Others Other errors as indicated
207 */
208 STATIC
209 EFI_STATUS
210 EFIAPI
211 ApAcceptMemoryResourceRange (
212 UINT32 CpuIndex,
213 EFI_PHYSICAL_ADDRESS PhysicalStart,
214 EFI_PHYSICAL_ADDRESS PhysicalEnd
215 )
216 {
217 UINT64 Status;
218 TD_RETURN_DATA TdReturnData;
219
220 Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
221 if (Status != TDX_EXIT_REASON_SUCCESS) {
222 ASSERT (FALSE);
223 return EFI_ABORTED;
224 }
225
226 if ((CpuIndex == 0) || (CpuIndex >= TdReturnData.TdInfo.NumVcpus)) {
227 ASSERT (FALSE);
228 return EFI_ABORTED;
229 }
230
231 return BspApAcceptMemoryResourceRange (CpuIndex, TdReturnData.TdInfo.NumVcpus, PhysicalStart, PhysicalEnd);
232 }
233
234 /**
235 * This function is called by BSP. It coordinates BSP/APs to accept memory together.
236 *
237 * @param PhysicalStart Start address of a memory region which is to be accepted
238 * @param PhysicalEnd End address of a memory region which is to be accepted
239 * @param APsStackAddress APs stack address
240 * @param CpusNum Total vCPU number of the Tdx guest
241 *
242 * @retval EFI_SUCCESS Successfully accept the memory
243 * @retval Others Other errors as indicated
244 */
245 STATIC
246 EFI_STATUS
247 EFIAPI
248 MpAcceptMemoryResourceRange (
249 IN EFI_PHYSICAL_ADDRESS PhysicalStart,
250 IN EFI_PHYSICAL_ADDRESS PhysicalEnd,
251 IN OUT EFI_PHYSICAL_ADDRESS APsStackAddress,
252 IN UINT32 CpusNum
253 )
254 {
255 UINT64 Length;
256 EFI_STATUS Status;
257
258 Length = PhysicalEnd - PhysicalStart;
259
260 DEBUG ((DEBUG_INFO, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalStart, PhysicalEnd, Length));
261
262 if (Length == 0) {
263 return EFI_SUCCESS;
264 }
265
266 //
267 // The start address is not 2M aligned. BSP first accept the part which is not 2M aligned.
268 //
269 if (ALIGN_VALUE (PhysicalStart, SIZE_2MB) != PhysicalStart) {
270 Length = MIN (ALIGN_VALUE (PhysicalStart, SIZE_2MB) - PhysicalStart, Length);
271 Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalStart + Length);
272 ASSERT (Status == EFI_SUCCESS);
273
274 PhysicalStart += Length;
275 Length = PhysicalEnd - PhysicalStart;
276 }
277
278 if (Length == 0) {
279 return EFI_SUCCESS;
280 }
281
282 //
283 // BSP will accept the memory by itself if the memory is not big enough compared with a chunk.
284 //
285 if (Length <= ACCEPT_CHUNK_SIZE) {
286 return BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
287 }
288
289 //
290 // Now APs are asked to accept the memory together.
291 //
292 MpSerializeStart ();
293
294 MpSendWakeupCommand (
295 MpProtectedModeWakeupCommandAcceptPages,
296 (UINT64)(UINTN)ApAcceptMemoryResourceRange,
297 PhysicalStart,
298 PhysicalEnd,
299 APsStackAddress,
300 AP_STACK_SIZE
301 );
302
303 //
304 // Now BSP does its job.
305 //
306 BspApAcceptMemoryResourceRange (0, CpusNum, PhysicalStart, PhysicalEnd);
307
308 MpSerializeEnd ();
309
310 return EFI_SUCCESS;
311 }
312
313 /**
314 BSP accept a small piece of memory which will be used as APs stack.
315
316 @param[in] VmmHobList The Hoblist pass the firmware
317 @param[in] APsStackSize APs stack size
318 @param[out] PhysicalAddressEnd The physical end address of accepted memory in phase-1
319
320 @retval EFI_SUCCESS Process the HobList successfully
321 @retval Others Other errors as indicated
322 **/
323 STATIC
324 EFI_STATUS
325 EFIAPI
326 AcceptMemoryForAPsStack (
327 IN CONST VOID *VmmHobList,
328 IN UINT32 APsStackSize,
329 OUT EFI_PHYSICAL_ADDRESS *PhysicalAddressEnd
330 )
331 {
332 EFI_STATUS Status;
333 EFI_PEI_HOB_POINTERS Hob;
334 EFI_PHYSICAL_ADDRESS PhysicalEnd;
335 EFI_PHYSICAL_ADDRESS PhysicalStart;
336 UINT64 ResourceLength;
337 BOOLEAN MemoryRegionFound;
338
339 ASSERT (VmmHobList != NULL);
340
341 Status = EFI_SUCCESS;
342 Hob.Raw = (UINT8 *)VmmHobList;
343 MemoryRegionFound = FALSE;
344
345 DEBUG ((DEBUG_INFO, "AcceptMemoryForAPsStack with APsStackSize=0x%x\n", APsStackSize));
346
347 //
348 // Parse the HOB list until end of list or matching type is found.
349 //
350 while (!END_OF_HOB_LIST (Hob) && !MemoryRegionFound) {
351 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
352 DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
353
354 if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
355 ResourceLength = Hob.ResourceDescriptor->ResourceLength;
356 PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
357 PhysicalEnd = PhysicalStart + ResourceLength;
358
359 DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
360 DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", PhysicalStart));
361 DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", ResourceLength));
362 DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
363
364 if (ResourceLength >= APsStackSize) {
365 MemoryRegionFound = TRUE;
366 if (ResourceLength > ACCEPT_CHUNK_SIZE) {
367 PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + APsStackSize;
368 }
369 }
370
371 Status = BspAcceptMemoryResourceRange (
372 Hob.ResourceDescriptor->PhysicalStart,
373 PhysicalEnd
374 );
375 if (EFI_ERROR (Status)) {
376 break;
377 }
378 }
379 }
380
381 Hob.Raw = GET_NEXT_HOB (Hob);
382 }
383
384 ASSERT (MemoryRegionFound);
385 *PhysicalAddressEnd = PhysicalEnd;
386
387 return Status;
388 }
389
390 /**
391 BSP and APs work togeter to accept memory which is under the address of 4G.
392
393 @param[in] VmmHobList The Hoblist pass the firmware
394 @param[in] CpusNum Number of vCPUs
395 @param[in] APsStackStartAddres Start address of APs stack
396 @param[in] PhysicalAddressStart Start physical address which to be accepted
397
398 @retval EFI_SUCCESS Process the HobList successfully
399 @retval Others Other errors as indicated
400 **/
401 STATIC
402 EFI_STATUS
403 EFIAPI
404 AcceptMemory (
405 IN CONST VOID *VmmHobList,
406 IN UINT32 CpusNum,
407 IN EFI_PHYSICAL_ADDRESS APsStackStartAddress,
408 IN EFI_PHYSICAL_ADDRESS PhysicalAddressStart
409 )
410 {
411 EFI_STATUS Status;
412 EFI_PEI_HOB_POINTERS Hob;
413 EFI_PHYSICAL_ADDRESS PhysicalStart;
414 EFI_PHYSICAL_ADDRESS PhysicalEnd;
415 EFI_PHYSICAL_ADDRESS AcceptMemoryEndAddress;
416
417 Status = EFI_SUCCESS;
418 AcceptMemoryEndAddress = BASE_4GB;
419
420 ASSERT (VmmHobList != NULL);
421 Hob.Raw = (UINT8 *)VmmHobList;
422
423 DEBUG ((DEBUG_INFO, "AcceptMemory under address of 4G\n"));
424
425 //
426 // Parse the HOB list until end of list or matching type is found.
427 //
428 while (!END_OF_HOB_LIST (Hob)) {
429 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
430 if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
431 PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
432 PhysicalEnd = PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
433
434 if (PhysicalEnd <= PhysicalAddressStart) {
435 // this memory region has been accepted. Skipped it.
436 Hob.Raw = GET_NEXT_HOB (Hob);
437 continue;
438 }
439
440 if (PhysicalStart >= AcceptMemoryEndAddress) {
441 // this memory region is not to be accepted. And we're done.
442 break;
443 }
444
445 if (PhysicalStart >= PhysicalAddressStart) {
446 // this memory region has not been acceted.
447 } else if ((PhysicalStart < PhysicalAddressStart) && (PhysicalEnd > PhysicalAddressStart)) {
448 // part of the memory region has been accepted.
449 PhysicalStart = PhysicalAddressStart;
450 }
451
452 // then compare the PhysicalEnd with AcceptMemoryEndAddress
453 if (PhysicalEnd >= AcceptMemoryEndAddress) {
454 PhysicalEnd = AcceptMemoryEndAddress;
455 }
456
457 DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
458 DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));
459 DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));
460 DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
461
462 // Now we're ready to accept memory [PhysicalStart, PhysicalEnd)
463 if (CpusNum == 1) {
464 Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
465 } else {
466 Status = MpAcceptMemoryResourceRange (
467 PhysicalStart,
468 PhysicalEnd,
469 APsStackStartAddress,
470 CpusNum
471 );
472 }
473
474 if (EFI_ERROR (Status)) {
475 ASSERT (FALSE);
476 break;
477 }
478
479 if (PhysicalEnd == AcceptMemoryEndAddress) {
480 break;
481 }
482 }
483 }
484
485 Hob.Raw = GET_NEXT_HOB (Hob);
486 }
487
488 return Status;
489 }
490
491 /**
492 Check the value whether in the valid list.
493
494 @param[in] Value A value
495 @param[in] ValidList A pointer to valid list
496 @param[in] ValidListLength Length of valid list
497
498 @retval TRUE The value is in valid list.
499 @retval FALSE The value is not in valid list.
500
501 **/
502 STATIC
503 BOOLEAN
504 EFIAPI
505 IsInValidList (
506 IN UINT32 Value,
507 IN UINT32 *ValidList,
508 IN UINT32 ValidListLength
509 )
510 {
511 UINT32 index;
512
513 if (ValidList == NULL) {
514 return FALSE;
515 }
516
517 for (index = 0; index < ValidListLength; index++) {
518 if (ValidList[index] == Value) {
519 return TRUE;
520 }
521 }
522
523 return FALSE;
524 }
525
526 /**
527 Check the integrity of VMM Hob List.
528
529 @param[in] VmmHobList A pointer to Hob List
530
531 @retval TRUE The Hob List is valid.
532 @retval FALSE The Hob List is invalid.
533
534 **/
535 STATIC
536 BOOLEAN
537 EFIAPI
538 ValidateHobList (
539 IN CONST VOID *VmmHobList
540 )
541 {
542 EFI_PEI_HOB_POINTERS Hob;
543 UINT32 EFI_BOOT_MODE_LIST[] = {
544 BOOT_WITH_FULL_CONFIGURATION,
545 BOOT_WITH_MINIMAL_CONFIGURATION,
546 BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
547 BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
548 BOOT_WITH_DEFAULT_SETTINGS,
549 BOOT_ON_S4_RESUME,
550 BOOT_ON_S5_RESUME,
551 BOOT_WITH_MFG_MODE_SETTINGS,
552 BOOT_ON_S2_RESUME,
553 BOOT_ON_S3_RESUME,
554 BOOT_ON_FLASH_UPDATE,
555 BOOT_IN_RECOVERY_MODE
556 };
557
558 UINT32 EFI_RESOURCE_TYPE_LIST[] = {
559 EFI_RESOURCE_SYSTEM_MEMORY,
560 EFI_RESOURCE_MEMORY_MAPPED_IO,
561 EFI_RESOURCE_IO,
562 EFI_RESOURCE_FIRMWARE_DEVICE,
563 EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
564 EFI_RESOURCE_MEMORY_RESERVED,
565 EFI_RESOURCE_IO_RESERVED,
566 BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED
567 };
568
569 if (VmmHobList == NULL) {
570 DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
571 return FALSE;
572 }
573
574 Hob.Raw = (UINT8 *)VmmHobList;
575
576 //
577 // Parse the HOB list until end of list or matching type is found.
578 //
579 while (!END_OF_HOB_LIST (Hob)) {
580 if (Hob.Header->Reserved != (UINT32)0) {
581 DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
582 return FALSE;
583 }
584
585 if (Hob.Header->HobLength == 0) {
586 DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
587 return FALSE;
588 }
589
590 switch (Hob.Header->HobType) {
591 case EFI_HOB_TYPE_HANDOFF:
592 if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
593 DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
594 return FALSE;
595 }
596
597 if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) == FALSE) {
598 DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
599 return FALSE;
600 }
601
602 if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
603 DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
604 Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
605 return FALSE;
606 }
607
608 break;
609
610 case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
611 if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
612 DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
613 return FALSE;
614 }
615
616 if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) == FALSE) {
617 DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
618 return FALSE;
619 }
620
621 if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
622 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
623 EFI_RESOURCE_ATTRIBUTE_TESTED |
624 EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
625 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
626 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
627 EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
628 EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
629 EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
630 EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
631 EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
632 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
633 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
634 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
635 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
636 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
637 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
638 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
639 EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
640 EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
641 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
642 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
643 EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
644 EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
645 EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
646 EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE))) != 0)
647 {
648 DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
649 return FALSE;
650 }
651
652 break;
653
654 // EFI_HOB_GUID_TYPE is variable length data, so skip check
655 case EFI_HOB_TYPE_GUID_EXTENSION:
656 break;
657
658 case EFI_HOB_TYPE_FV:
659 if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
660 DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
661 return FALSE;
662 }
663
664 break;
665
666 case EFI_HOB_TYPE_FV2:
667 if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
668 DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
669 return FALSE;
670 }
671
672 break;
673
674 case EFI_HOB_TYPE_FV3:
675 if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
676 DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
677 return FALSE;
678 }
679
680 break;
681
682 case EFI_HOB_TYPE_CPU:
683 if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
684 DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
685 return FALSE;
686 }
687
688 for (UINT32 index = 0; index < 6; index++) {
689 if (Hob.Cpu->Reserved[index] != 0) {
690 DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
691 return FALSE;
692 }
693 }
694
695 break;
696
697 default:
698 DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
699 return FALSE;
700 }
701
702 // Get next HOB
703 Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
704 }
705
706 return TRUE;
707 }
708
709 /**
710 Processing the incoming HobList for the TDX
711
712 Firmware must parse list, and accept the pages of memory before their can be
713 use by the guest.
714
715 @param[in] VmmHobList The Hoblist pass the firmware
716
717 @retval EFI_SUCCESS Process the HobList successfully
718 @retval Others Other errors as indicated
719
720 **/
721 STATIC
722 EFI_STATUS
723 EFIAPI
724 ProcessHobList (
725 IN CONST VOID *VmmHobList
726 )
727 {
728 EFI_STATUS Status;
729 UINT32 CpusNum;
730 EFI_PHYSICAL_ADDRESS PhysicalEnd;
731 EFI_PHYSICAL_ADDRESS APsStackStartAddress;
732
733 CpusNum = GetCpusNum ();
734
735 //
736 // If there are mutli-vCPU in a TDX guest, accept memory is split into 2 phases.
737 // Phase-1 accepts a small piece of memory by BSP. This piece of memory
738 // is used to setup AP's stack.
739 // After that phase-2 accepts a big piece of memory by BSP/APs.
740 //
741 // TDVF supports 4K and 2M accept-page-size. The memory which can be accpeted
742 // in 2M accept-page-size must be 2M aligned and multiple 2M. So we align
743 // APsStackSize to 2M size aligned.
744 //
745 if (CpusNum > 1) {
746 Status = AcceptMemoryForAPsStack (VmmHobList, APS_STACK_SIZE (CpusNum), &PhysicalEnd);
747 ASSERT (Status == EFI_SUCCESS);
748 APsStackStartAddress = PhysicalEnd - APS_STACK_SIZE (CpusNum);
749 } else {
750 PhysicalEnd = 0;
751 APsStackStartAddress = 0;
752 }
753
754 Status = AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, PhysicalEnd);
755 ASSERT (Status == EFI_SUCCESS);
756
757 return Status;
758 }
759
760 /**
761 In Tdx guest, some information need to be passed from host VMM to guest
762 firmware. For example, the memory resource, etc. These information are
763 prepared by host VMM and put in TdHob which is described in TdxMetadata.
764 TDVF processes the TdHob to accept memories.
765
766 @retval EFI_SUCCESS Successfully process the TdHob
767 @retval Others Other error as indicated
768 **/
769 EFI_STATUS
770 EFIAPI
771 TdxHelperProcessTdHob (
772 VOID
773 )
774 {
775 EFI_STATUS Status;
776 VOID *TdHob;
777 TD_RETURN_DATA TdReturnData;
778
779 TdHob = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
780 Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
781 if (EFI_ERROR (Status)) {
782 return Status;
783 }
784
785 DEBUG ((
786 DEBUG_INFO,
787 "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
788 TdReturnData.TdInfo.Gpaw,
789 TdReturnData.TdInfo.NumVcpus
790 ));
791
792 //
793 // Validate HobList
794 //
795 if (ValidateHobList (TdHob) == FALSE) {
796 return EFI_INVALID_PARAMETER;
797 }
798
799 //
800 // Process Hoblist to accept memory
801 //
802 Status = ProcessHobList (TdHob);
803
804 return Status;
805 }
806
807 /**
808 * Calculate the sha384 of input Data and extend it to RTMR register.
809 *
810 * @param RtmrIndex Index of the RTMR register
811 * @param DataToHash Data to be hashed
812 * @param DataToHashLen Length of the data
813 * @param Digest Hash value of the input data
814 * @param DigestLen Length of the hash value
815 *
816 * @retval EFI_SUCCESS Successfully hash and extend to RTMR
817 * @retval Others Other errors as indicated
818 */
819 STATIC
820 EFI_STATUS
821 HashAndExtendToRtmr (
822 IN UINT32 RtmrIndex,
823 IN VOID *DataToHash,
824 IN UINTN DataToHashLen,
825 OUT UINT8 *Digest,
826 IN UINTN DigestLen
827 )
828 {
829 EFI_STATUS Status;
830
831 if ((DataToHash == NULL) || (DataToHashLen == 0)) {
832 return EFI_INVALID_PARAMETER;
833 }
834
835 if ((Digest == NULL) || (DigestLen != SHA384_DIGEST_SIZE)) {
836 return EFI_INVALID_PARAMETER;
837 }
838
839 //
840 // Calculate the sha384 of the data
841 //
842 if (!Sha384HashAll (DataToHash, DataToHashLen, Digest)) {
843 return EFI_ABORTED;
844 }
845
846 //
847 // Extend to RTMR
848 //
849 Status = TdExtendRtmr (
850 (UINT32 *)Digest,
851 SHA384_DIGEST_SIZE,
852 (UINT8)RtmrIndex
853 );
854
855 ASSERT (!EFI_ERROR (Status));
856 return Status;
857 }
858
859 /**
860 In Tdx guest, TdHob is passed from host VMM to guest firmware and it contains
861 the information of the memory resource. From the security perspective before
862 it is consumed, it should be measured and extended.
863 *
864 * @retval EFI_SUCCESS Successfully measure the TdHob
865 * @retval Others Other error as indicated
866 */
867 EFI_STATUS
868 EFIAPI
869 TdxHelperMeasureTdHob (
870 VOID
871 )
872 {
873 EFI_PEI_HOB_POINTERS Hob;
874 EFI_STATUS Status;
875 UINT8 Digest[SHA384_DIGEST_SIZE];
876 OVMF_WORK_AREA *WorkArea;
877 VOID *TdHob;
878
879 TdHob = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
880 Hob.Raw = (UINT8 *)TdHob;
881
882 //
883 // Walk thru the TdHob list until end of list.
884 //
885 while (!END_OF_HOB_LIST (Hob)) {
886 Hob.Raw = GET_NEXT_HOB (Hob);
887 }
888
889 Status = HashAndExtendToRtmr (
890 0,
891 (UINT8 *)TdHob,
892 (UINTN)((UINT8 *)Hob.Raw - (UINT8 *)TdHob),
893 Digest,
894 SHA384_DIGEST_SIZE
895 );
896
897 if (EFI_ERROR (Status)) {
898 return Status;
899 }
900
901 //
902 // This function is called in SEC phase and at that moment the Hob service
903 // is not available. So the TdHob measurement value is stored in workarea.
904 //
905 WorkArea = (OVMF_WORK_AREA *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
906 if (WorkArea == NULL) {
907 return EFI_DEVICE_ERROR;
908 }
909
910 WorkArea->TdxWorkArea.SecTdxWorkArea.TdxMeasurementsData.MeasurementsBitmap |= TDX_MEASUREMENT_TDHOB_BITMASK;
911 CopyMem (WorkArea->TdxWorkArea.SecTdxWorkArea.TdxMeasurementsData.TdHobHashValue, Digest, SHA384_DIGEST_SIZE);
912
913 return EFI_SUCCESS;
914 }
915
916 /**
917 * In Tdx guest, Configuration FV (CFV) is treated as external input because it
918 * may contain the data provided by VMM. From the sucurity perspective Cfv image
919 * should be measured before it is consumed.
920 *
921 * @retval EFI_SUCCESS Successfully measure the CFV image
922 * @retval Others Other error as indicated
923 */
924 EFI_STATUS
925 EFIAPI
926 TdxHelperMeasureCfvImage (
927 VOID
928 )
929 {
930 EFI_STATUS Status;
931 UINT8 Digest[SHA384_DIGEST_SIZE];
932 OVMF_WORK_AREA *WorkArea;
933
934 Status = HashAndExtendToRtmr (
935 0,
936 (UINT8 *)(UINTN)PcdGet32 (PcdOvmfFlashNvStorageVariableBase),
937 (UINT64)PcdGet32 (PcdCfvRawDataSize),
938 Digest,
939 SHA384_DIGEST_SIZE
940 );
941
942 if (EFI_ERROR (Status)) {
943 return Status;
944 }
945
946 //
947 // This function is called in SEC phase and at that moment the Hob service
948 // is not available. So CfvImage measurement value is stored in workarea.
949 //
950 WorkArea = (OVMF_WORK_AREA *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
951 if (WorkArea == NULL) {
952 return EFI_DEVICE_ERROR;
953 }
954
955 WorkArea->TdxWorkArea.SecTdxWorkArea.TdxMeasurementsData.MeasurementsBitmap |= TDX_MEASUREMENT_CFVIMG_BITMASK;
956 CopyMem (WorkArea->TdxWorkArea.SecTdxWorkArea.TdxMeasurementsData.CfvImgHashValue, Digest, SHA384_DIGEST_SIZE);
957
958 return EFI_SUCCESS;
959 }
960
961 /**
962 Build the GuidHob for tdx measurements which were done in SEC phase.
963 The measurement values are stored in WorkArea.
964
965 @retval EFI_SUCCESS The GuidHob is built successfully
966 @retval Others Other errors as indicated
967 **/
968 EFI_STATUS
969 EFIAPI
970 TdxHelperBuildGuidHobForTdxMeasurement (
971 VOID
972 )
973 {
974 #ifdef TDX_PEI_LESS_BOOT
975 return InternalBuildGuidHobForTdxMeasurement ();
976 #else
977 return EFI_UNSUPPORTED;
978 #endif
979 }