2 TdxHelper Functions which are used in SEC phase
4 Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
24 #include <ConfidentialComputingGuestAttr.h>
25 #include <Library/TdxHelperLib.h>
27 #define ALIGNED_2MB_MASK 0x1fffff
28 #define MEGABYTE_SHIFT 20
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))
35 Build the GuidHob for tdx measurements which were done in SEC phase.
36 The measurement values are stored in WorkArea.
38 @retval EFI_SUCCESS The GuidHob is built successfully
39 @retval Others Other errors as indicated
42 InternalBuildGuidHobForTdxMeasurement (
47 This function will be called to accept pages. Only BSP accepts pages.
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
52 ----------------- <-- StartAddress1 (not 2M aligned)
53 | part 1 | Length1 < 2M
54 |---------------| <-- StartAddress2 (2M aligned)
55 | | Length2 = Integer multiples of 2M
58 |---------------| <-- StartAddress3
59 | part 3 | Length3 < 2M
62 @param[in] PhysicalAddress Start physical adress
63 @param[in] PhysicalEnd End physical address
65 @retval EFI_SUCCESS Accept memory successfully
66 @retval Others Other errors as indicated
71 BspAcceptMemoryResourceRange (
72 IN EFI_PHYSICAL_ADDRESS PhysicalAddress
,
73 IN EFI_PHYSICAL_ADDRESS PhysicalEnd
77 UINT32 AcceptPageSize
;
87 AcceptPageSize
= FixedPcdGet32 (PcdTdxAcceptPageSize
);
88 TotalLength
= PhysicalEnd
- PhysicalAddress
;
96 if (TotalLength
== 0) {
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
;
107 PhysicalAddress
+= Length1
;
108 TotalLength
-= Length1
;
111 if (TotalLength
> SIZE_2MB
) {
112 StartAddress2
= PhysicalAddress
;
113 Length2
= TotalLength
& ~(UINT64
)ALIGNED_2MB_MASK
;
114 PhysicalAddress
+= Length2
;
115 TotalLength
-= Length2
;
119 StartAddress3
= PhysicalAddress
;
120 Length3
= TotalLength
;
123 Status
= EFI_SUCCESS
;
125 Pages
= Length1
/ SIZE_4KB
;
126 Status
= TdAcceptPages (StartAddress1
, Pages
, SIZE_4KB
);
127 if (EFI_ERROR (Status
)) {
133 Pages
= Length2
/ AcceptPageSize
;
134 Status
= TdAcceptPages (StartAddress2
, Pages
, AcceptPageSize
);
135 if (EFI_ERROR (Status
)) {
141 Pages
= Length3
/ SIZE_4KB
;
142 Status
= TdAcceptPages (StartAddress3
, Pages
, SIZE_4KB
);
143 ASSERT (!EFI_ERROR (Status
));
144 if (EFI_ERROR (Status
)) {
153 * This function is called by BSP and APs to accept memory.
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.
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
163 * @retval EFI_SUCCESS Successfully accept the memory
164 * @retval Other Other errors as indicated
169 BspApAcceptMemoryResourceRange (
172 EFI_PHYSICAL_ADDRESS PhysicalStart
,
173 EFI_PHYSICAL_ADDRESS PhysicalEnd
179 UINT64 AcceptPageSize
;
180 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
182 AcceptPageSize
= (UINT64
)(UINTN
)FixedPcdGet32 (PcdTdxAcceptPageSize
);
184 Status
= EFI_SUCCESS
;
185 Stride
= (UINTN
)CpusNum
* ACCEPT_CHUNK_SIZE
;
186 PhysicalAddress
= PhysicalStart
+ ACCEPT_CHUNK_SIZE
* (UINTN
)CpuIndex
;
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
;
199 * This function is called by APs to accept memory.
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
205 * @retval EFI_SUCCESS Successfully accept the memory
206 * @retval Others Other errors as indicated
211 ApAcceptMemoryResourceRange (
213 EFI_PHYSICAL_ADDRESS PhysicalStart
,
214 EFI_PHYSICAL_ADDRESS PhysicalEnd
218 TD_RETURN_DATA TdReturnData
;
220 Status
= TdCall (TDCALL_TDINFO
, 0, 0, 0, &TdReturnData
);
221 if (Status
!= TDX_EXIT_REASON_SUCCESS
) {
226 if ((CpuIndex
== 0) || (CpuIndex
>= TdReturnData
.TdInfo
.NumVcpus
)) {
231 return BspApAcceptMemoryResourceRange (CpuIndex
, TdReturnData
.TdInfo
.NumVcpus
, PhysicalStart
, PhysicalEnd
);
235 * This function is called by BSP. It coordinates BSP/APs to accept memory together.
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
242 * @retval EFI_SUCCESS Successfully accept the memory
243 * @retval Others Other errors as indicated
248 MpAcceptMemoryResourceRange (
249 IN EFI_PHYSICAL_ADDRESS PhysicalStart
,
250 IN EFI_PHYSICAL_ADDRESS PhysicalEnd
,
251 IN OUT EFI_PHYSICAL_ADDRESS APsStackAddress
,
258 Length
= PhysicalEnd
- PhysicalStart
;
260 DEBUG ((DEBUG_INFO
, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalStart
, PhysicalEnd
, Length
));
267 // The start address is not 2M aligned. BSP first accept the part which is not 2M aligned.
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
);
274 PhysicalStart
+= Length
;
275 Length
= PhysicalEnd
- PhysicalStart
;
283 // BSP will accept the memory by itself if the memory is not big enough compared with a chunk.
285 if (Length
<= ACCEPT_CHUNK_SIZE
) {
286 return BspAcceptMemoryResourceRange (PhysicalStart
, PhysicalEnd
);
290 // Now APs are asked to accept the memory together.
294 MpSendWakeupCommand (
295 MpProtectedModeWakeupCommandAcceptPages
,
296 (UINT64
)(UINTN
)ApAcceptMemoryResourceRange
,
304 // Now BSP does its job.
306 BspApAcceptMemoryResourceRange (0, CpusNum
, PhysicalStart
, PhysicalEnd
);
314 BSP accept a small piece of memory which will be used as APs stack.
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
320 @retval EFI_SUCCESS Process the HobList successfully
321 @retval Others Other errors as indicated
326 AcceptMemoryForAPsStack (
327 IN CONST VOID
*VmmHobList
,
328 IN UINT32 APsStackSize
,
329 OUT EFI_PHYSICAL_ADDRESS
*PhysicalAddressEnd
333 EFI_PEI_HOB_POINTERS Hob
;
334 EFI_PHYSICAL_ADDRESS PhysicalEnd
;
335 EFI_PHYSICAL_ADDRESS PhysicalStart
;
336 UINT64 ResourceLength
;
337 BOOLEAN MemoryRegionFound
;
339 ASSERT (VmmHobList
!= NULL
);
341 Status
= EFI_SUCCESS
;
342 Hob
.Raw
= (UINT8
*)VmmHobList
;
343 MemoryRegionFound
= FALSE
;
345 DEBUG ((DEBUG_INFO
, "AcceptMemoryForAPsStack with APsStackSize=0x%x\n", APsStackSize
));
348 // Parse the HOB list until end of list or matching type is found.
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
));
354 if (Hob
.ResourceDescriptor
->ResourceType
== BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED
) {
355 ResourceLength
= Hob
.ResourceDescriptor
->ResourceLength
;
356 PhysicalStart
= Hob
.ResourceDescriptor
->PhysicalStart
;
357 PhysicalEnd
= PhysicalStart
+ ResourceLength
;
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
));
364 if (ResourceLength
>= APsStackSize
) {
365 MemoryRegionFound
= TRUE
;
366 if (ResourceLength
> ACCEPT_CHUNK_SIZE
) {
367 PhysicalEnd
= Hob
.ResourceDescriptor
->PhysicalStart
+ APsStackSize
;
371 Status
= BspAcceptMemoryResourceRange (
372 Hob
.ResourceDescriptor
->PhysicalStart
,
375 if (EFI_ERROR (Status
)) {
381 Hob
.Raw
= GET_NEXT_HOB (Hob
);
384 ASSERT (MemoryRegionFound
);
385 *PhysicalAddressEnd
= PhysicalEnd
;
391 BSP and APs work togeter to accept memory which is under the address of 4G.
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
398 @retval EFI_SUCCESS Process the HobList successfully
399 @retval Others Other errors as indicated
405 IN CONST VOID
*VmmHobList
,
407 IN EFI_PHYSICAL_ADDRESS APsStackStartAddress
,
408 IN EFI_PHYSICAL_ADDRESS PhysicalAddressStart
412 EFI_PEI_HOB_POINTERS Hob
;
413 EFI_PHYSICAL_ADDRESS PhysicalStart
;
414 EFI_PHYSICAL_ADDRESS PhysicalEnd
;
415 EFI_PHYSICAL_ADDRESS AcceptMemoryEndAddress
;
417 Status
= EFI_SUCCESS
;
418 AcceptMemoryEndAddress
= BASE_4GB
;
420 ASSERT (VmmHobList
!= NULL
);
421 Hob
.Raw
= (UINT8
*)VmmHobList
;
423 DEBUG ((DEBUG_INFO
, "AcceptMemory under address of 4G\n"));
426 // Parse the HOB list until end of list or matching type is found.
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
;
434 if (PhysicalEnd
<= PhysicalAddressStart
) {
435 // this memory region has been accepted. Skipped it.
436 Hob
.Raw
= GET_NEXT_HOB (Hob
);
440 if (PhysicalStart
>= AcceptMemoryEndAddress
) {
441 // this memory region is not to be accepted. And we're done.
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
;
452 // then compare the PhysicalEnd with AcceptMemoryEndAddress
453 if (PhysicalEnd
>= AcceptMemoryEndAddress
) {
454 PhysicalEnd
= AcceptMemoryEndAddress
;
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
));
462 // Now we're ready to accept memory [PhysicalStart, PhysicalEnd)
464 Status
= BspAcceptMemoryResourceRange (PhysicalStart
, PhysicalEnd
);
466 Status
= MpAcceptMemoryResourceRange (
469 APsStackStartAddress
,
474 if (EFI_ERROR (Status
)) {
479 if (PhysicalEnd
== AcceptMemoryEndAddress
) {
485 Hob
.Raw
= GET_NEXT_HOB (Hob
);
492 Check the value whether in the valid list.
494 @param[in] Value A value
495 @param[in] ValidList A pointer to valid list
496 @param[in] ValidListLength Length of valid list
498 @retval TRUE The value is in valid list.
499 @retval FALSE The value is not in valid list.
507 IN UINT32
*ValidList
,
508 IN UINT32 ValidListLength
513 if (ValidList
== NULL
) {
517 for (index
= 0; index
< ValidListLength
; index
++) {
518 if (ValidList
[index
] == Value
) {
527 Check the integrity of VMM Hob List.
529 @param[in] VmmHobList A pointer to Hob List
531 @retval TRUE The Hob List is valid.
532 @retval FALSE The Hob List is invalid.
539 IN CONST VOID
*VmmHobList
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
,
551 BOOT_WITH_MFG_MODE_SETTINGS
,
554 BOOT_ON_FLASH_UPDATE
,
555 BOOT_IN_RECOVERY_MODE
558 UINT32 EFI_RESOURCE_TYPE_LIST
[] = {
559 EFI_RESOURCE_SYSTEM_MEMORY
,
560 EFI_RESOURCE_MEMORY_MAPPED_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
569 if (VmmHobList
== NULL
) {
570 DEBUG ((DEBUG_ERROR
, "HOB: HOB data pointer is NULL\n"));
574 Hob
.Raw
= (UINT8
*)VmmHobList
;
577 // Parse the HOB list until end of list or matching type is found.
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"));
585 if (Hob
.Header
->HobLength
== 0) {
586 DEBUG ((DEBUG_ERROR
, "HOB: Hob header LEANGTH should not be zero\n"));
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
));
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
));
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
));
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
));
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
));
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)
648 DEBUG ((DEBUG_ERROR
, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob
.ResourceDescriptor
->ResourceAttribute
));
654 // EFI_HOB_GUID_TYPE is variable length data, so skip check
655 case EFI_HOB_TYPE_GUID_EXTENSION
:
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
));
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
));
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
));
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
));
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"));
698 DEBUG ((DEBUG_ERROR
, "HOB: Hob type is not know. Type: 0x%04x\n", Hob
.Header
->HobType
));
703 Hob
.Raw
= (UINT8
*)(Hob
.Raw
+ Hob
.Header
->HobLength
);
710 Processing the incoming HobList for the TDX
712 Firmware must parse list, and accept the pages of memory before their can be
715 @param[in] VmmHobList The Hoblist pass the firmware
717 @retval EFI_SUCCESS Process the HobList successfully
718 @retval Others Other errors as indicated
725 IN CONST VOID
*VmmHobList
730 EFI_PHYSICAL_ADDRESS PhysicalEnd
;
731 EFI_PHYSICAL_ADDRESS APsStackStartAddress
;
733 CpusNum
= GetCpusNum ();
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.
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.
746 Status
= AcceptMemoryForAPsStack (VmmHobList
, APS_STACK_SIZE (CpusNum
), &PhysicalEnd
);
747 ASSERT (Status
== EFI_SUCCESS
);
748 APsStackStartAddress
= PhysicalEnd
- APS_STACK_SIZE (CpusNum
);
751 APsStackStartAddress
= 0;
754 Status
= AcceptMemory (VmmHobList
, CpusNum
, APsStackStartAddress
, PhysicalEnd
);
755 ASSERT (Status
== EFI_SUCCESS
);
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.
766 @retval EFI_SUCCESS Successfully process the TdHob
767 @retval Others Other error as indicated
771 TdxHelperProcessTdHob (
777 TD_RETURN_DATA TdReturnData
;
779 TdHob
= (VOID
*)(UINTN
)FixedPcdGet32 (PcdOvmfSecGhcbBase
);
780 Status
= TdCall (TDCALL_TDINFO
, 0, 0, 0, &TdReturnData
);
781 if (EFI_ERROR (Status
)) {
787 "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
788 TdReturnData
.TdInfo
.Gpaw
,
789 TdReturnData
.TdInfo
.NumVcpus
795 if (ValidateHobList (TdHob
) == FALSE
) {
796 return EFI_INVALID_PARAMETER
;
800 // Process Hoblist to accept memory
802 Status
= ProcessHobList (TdHob
);
808 * Calculate the sha384 of input Data and extend it to RTMR register.
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
816 * @retval EFI_SUCCESS Successfully hash and extend to RTMR
817 * @retval Others Other errors as indicated
821 HashAndExtendToRtmr (
824 IN UINTN DataToHashLen
,
831 if ((DataToHash
== NULL
) || (DataToHashLen
== 0)) {
832 return EFI_INVALID_PARAMETER
;
835 if ((Digest
== NULL
) || (DigestLen
!= SHA384_DIGEST_SIZE
)) {
836 return EFI_INVALID_PARAMETER
;
840 // Calculate the sha384 of the data
842 if (!Sha384HashAll (DataToHash
, DataToHashLen
, Digest
)) {
849 Status
= TdExtendRtmr (
855 ASSERT (!EFI_ERROR (Status
));
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.
864 * @retval EFI_SUCCESS Successfully measure the TdHob
865 * @retval Others Other error as indicated
869 TdxHelperMeasureTdHob (
873 EFI_PEI_HOB_POINTERS Hob
;
875 UINT8 Digest
[SHA384_DIGEST_SIZE
];
876 OVMF_WORK_AREA
*WorkArea
;
879 TdHob
= (VOID
*)(UINTN
)FixedPcdGet32 (PcdOvmfSecGhcbBase
);
880 Hob
.Raw
= (UINT8
*)TdHob
;
883 // Walk thru the TdHob list until end of list.
885 while (!END_OF_HOB_LIST (Hob
)) {
886 Hob
.Raw
= GET_NEXT_HOB (Hob
);
889 Status
= HashAndExtendToRtmr (
892 (UINTN
)((UINT8
*)Hob
.Raw
- (UINT8
*)TdHob
),
897 if (EFI_ERROR (Status
)) {
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.
905 WorkArea
= (OVMF_WORK_AREA
*)FixedPcdGet32 (PcdOvmfWorkAreaBase
);
906 if (WorkArea
== NULL
) {
907 return EFI_DEVICE_ERROR
;
910 WorkArea
->TdxWorkArea
.SecTdxWorkArea
.TdxMeasurementsData
.MeasurementsBitmap
|= TDX_MEASUREMENT_TDHOB_BITMASK
;
911 CopyMem (WorkArea
->TdxWorkArea
.SecTdxWorkArea
.TdxMeasurementsData
.TdHobHashValue
, Digest
, SHA384_DIGEST_SIZE
);
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.
921 * @retval EFI_SUCCESS Successfully measure the CFV image
922 * @retval Others Other error as indicated
926 TdxHelperMeasureCfvImage (
931 UINT8 Digest
[SHA384_DIGEST_SIZE
];
932 OVMF_WORK_AREA
*WorkArea
;
934 Status
= HashAndExtendToRtmr (
936 (UINT8
*)(UINTN
)PcdGet32 (PcdOvmfFlashNvStorageVariableBase
),
937 (UINT64
)PcdGet32 (PcdCfvRawDataSize
),
942 if (EFI_ERROR (Status
)) {
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.
950 WorkArea
= (OVMF_WORK_AREA
*)FixedPcdGet32 (PcdOvmfWorkAreaBase
);
951 if (WorkArea
== NULL
) {
952 return EFI_DEVICE_ERROR
;
955 WorkArea
->TdxWorkArea
.SecTdxWorkArea
.TdxMeasurementsData
.MeasurementsBitmap
|= TDX_MEASUREMENT_CFVIMG_BITMASK
;
956 CopyMem (WorkArea
->TdxWorkArea
.SecTdxWorkArea
.TdxMeasurementsData
.CfvImgHashValue
, Digest
, SHA384_DIGEST_SIZE
);
962 Build the GuidHob for tdx measurements which were done in SEC phase.
963 The measurement values are stored in WorkArea.
965 @retval EFI_SUCCESS The GuidHob is built successfully
966 @retval Others Other errors as indicated
970 TdxHelperBuildGuidHobForTdxMeasurement (
974 #ifdef TDX_PEI_LESS_BOOT
975 return InternalBuildGuidHobForTdxMeasurement ();
977 return EFI_UNSUPPORTED
;