VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette