]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Sec/SecMain.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Sec / SecMain.c
1 /** @file
2 Main SEC phase code. Transitions to PEI.
3
4 Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <PiPei.h>
13
14 #include <Library/PeimEntryPoint.h>
15 #include <Library/BaseLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/PeiServicesLib.h>
19 #include <Library/PcdLib.h>
20 #include <Library/CpuLib.h>
21 #include <Library/UefiCpuLib.h>
22 #include <Library/DebugAgentLib.h>
23 #include <Library/IoLib.h>
24 #include <Library/PeCoffLib.h>
25 #include <Library/PeCoffGetEntryPointLib.h>
26 #include <Library/PeCoffExtraActionLib.h>
27 #include <Library/ExtractGuidedSectionLib.h>
28 #include <Library/LocalApicLib.h>
29 #include <Library/CpuExceptionHandlerLib.h>
30 #include <Ppi/TemporaryRamSupport.h>
31 #include <Ppi/MpInitLibDep.h>
32 #include <Library/TdxHelperLib.h>
33 #include <Library/CcProbeLib.h>
34 #include "AmdSev.h"
35
36 #define SEC_IDT_ENTRY_COUNT 34
37
38 typedef struct _SEC_IDT_TABLE {
39 EFI_PEI_SERVICES *PeiService;
40 IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT];
41 } SEC_IDT_TABLE;
42
43 VOID
44 EFIAPI
45 SecStartupPhase2 (
46 IN VOID *Context
47 );
48
49 EFI_STATUS
50 EFIAPI
51 TemporaryRamMigration (
52 IN CONST EFI_PEI_SERVICES **PeiServices,
53 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
54 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
55 IN UINTN CopySize
56 );
57
58 //
59 //
60 //
61 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
62 TemporaryRamMigration
63 };
64
65 EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTableMp[] = {
66 {
67 (EFI_PEI_PPI_DESCRIPTOR_PPI),
68 &gEfiTemporaryRamSupportPpiGuid,
69 &mTemporaryRamSupportPpi
70 },
71 {
72 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
73 &gEfiPeiMpInitLibMpDepPpiGuid,
74 NULL
75 },
76 };
77
78 EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTableUp[] = {
79 {
80 (EFI_PEI_PPI_DESCRIPTOR_PPI),
81 &gEfiTemporaryRamSupportPpiGuid,
82 &mTemporaryRamSupportPpi
83 },
84 {
85 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
86 &gEfiPeiMpInitLibUpDepPpiGuid,
87 NULL
88 },
89 };
90
91 //
92 // Template of an IDT entry pointing to 10:FFFFFFE4h.
93 //
94 IA32_IDT_GATE_DESCRIPTOR mIdtEntryTemplate = {
95 { // Bits
96 0xffe4, // OffsetLow
97 0x10, // Selector
98 0x0, // Reserved_0
99 IA32_IDT_GATE_TYPE_INTERRUPT_32, // GateType
100 0xffff // OffsetHigh
101 }
102 };
103
104 /**
105 Locates the main boot firmware volume.
106
107 @param[in,out] BootFv On input, the base of the BootFv
108 On output, the decompressed main firmware volume
109
110 @retval EFI_SUCCESS The main firmware volume was located and decompressed
111 @retval EFI_NOT_FOUND The main firmware volume was not found
112
113 **/
114 EFI_STATUS
115 FindMainFv (
116 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv
117 )
118 {
119 EFI_FIRMWARE_VOLUME_HEADER *Fv;
120 UINTN Distance;
121
122 ASSERT (((UINTN)*BootFv & EFI_PAGE_MASK) == 0);
123
124 Fv = *BootFv;
125 Distance = (UINTN)(*BootFv)->FvLength;
126 do {
127 Fv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)Fv - EFI_PAGE_SIZE);
128 Distance += EFI_PAGE_SIZE;
129 if (Distance > SIZE_32MB) {
130 return EFI_NOT_FOUND;
131 }
132
133 if (Fv->Signature != EFI_FVH_SIGNATURE) {
134 continue;
135 }
136
137 if ((UINTN)Fv->FvLength > Distance) {
138 continue;
139 }
140
141 *BootFv = Fv;
142 return EFI_SUCCESS;
143 } while (TRUE);
144 }
145
146 /**
147 Locates a section within a series of sections
148 with the specified section type.
149
150 The Instance parameter indicates which instance of the section
151 type to return. (0 is first instance, 1 is second...)
152
153 @param[in] Sections The sections to search
154 @param[in] SizeOfSections Total size of all sections
155 @param[in] SectionType The section type to locate
156 @param[in] Instance The section instance number
157 @param[out] FoundSection The FFS section if found
158
159 @retval EFI_SUCCESS The file and section was found
160 @retval EFI_NOT_FOUND The file and section was not found
161 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
162
163 **/
164 EFI_STATUS
165 FindFfsSectionInstance (
166 IN VOID *Sections,
167 IN UINTN SizeOfSections,
168 IN EFI_SECTION_TYPE SectionType,
169 IN UINTN Instance,
170 OUT EFI_COMMON_SECTION_HEADER **FoundSection
171 )
172 {
173 EFI_PHYSICAL_ADDRESS CurrentAddress;
174 UINT32 Size;
175 EFI_PHYSICAL_ADDRESS EndOfSections;
176 EFI_COMMON_SECTION_HEADER *Section;
177 EFI_PHYSICAL_ADDRESS EndOfSection;
178
179 //
180 // Loop through the FFS file sections within the PEI Core FFS file
181 //
182 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;
183 EndOfSections = EndOfSection + SizeOfSections;
184 for ( ; ;) {
185 if (EndOfSection == EndOfSections) {
186 break;
187 }
188
189 CurrentAddress = (EndOfSection + 3) & ~(3ULL);
190 if (CurrentAddress >= EndOfSections) {
191 return EFI_VOLUME_CORRUPTED;
192 }
193
194 Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
195
196 Size = SECTION_SIZE (Section);
197 if (Size < sizeof (*Section)) {
198 return EFI_VOLUME_CORRUPTED;
199 }
200
201 EndOfSection = CurrentAddress + Size;
202 if (EndOfSection > EndOfSections) {
203 return EFI_VOLUME_CORRUPTED;
204 }
205
206 //
207 // Look for the requested section type
208 //
209 if (Section->Type == SectionType) {
210 if (Instance == 0) {
211 *FoundSection = Section;
212 return EFI_SUCCESS;
213 } else {
214 Instance--;
215 }
216 }
217 }
218
219 return EFI_NOT_FOUND;
220 }
221
222 /**
223 Locates a section within a series of sections
224 with the specified section type.
225
226 @param[in] Sections The sections to search
227 @param[in] SizeOfSections Total size of all sections
228 @param[in] SectionType The section type to locate
229 @param[out] FoundSection The FFS section if found
230
231 @retval EFI_SUCCESS The file and section was found
232 @retval EFI_NOT_FOUND The file and section was not found
233 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
234
235 **/
236 EFI_STATUS
237 FindFfsSectionInSections (
238 IN VOID *Sections,
239 IN UINTN SizeOfSections,
240 IN EFI_SECTION_TYPE SectionType,
241 OUT EFI_COMMON_SECTION_HEADER **FoundSection
242 )
243 {
244 return FindFfsSectionInstance (
245 Sections,
246 SizeOfSections,
247 SectionType,
248 0,
249 FoundSection
250 );
251 }
252
253 /**
254 Locates a FFS file with the specified file type and a section
255 within that file with the specified section type.
256
257 @param[in] Fv The firmware volume to search
258 @param[in] FileType The file type to locate
259 @param[in] SectionType The section type to locate
260 @param[out] FoundSection The FFS section if found
261
262 @retval EFI_SUCCESS The file and section was found
263 @retval EFI_NOT_FOUND The file and section was not found
264 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
265
266 **/
267 EFI_STATUS
268 FindFfsFileAndSection (
269 IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
270 IN EFI_FV_FILETYPE FileType,
271 IN EFI_SECTION_TYPE SectionType,
272 OUT EFI_COMMON_SECTION_HEADER **FoundSection
273 )
274 {
275 EFI_STATUS Status;
276 EFI_PHYSICAL_ADDRESS CurrentAddress;
277 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
278 EFI_FFS_FILE_HEADER *File;
279 UINT32 Size;
280 EFI_PHYSICAL_ADDRESS EndOfFile;
281
282 if (Fv->Signature != EFI_FVH_SIGNATURE) {
283 DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
284 return EFI_VOLUME_CORRUPTED;
285 }
286
287 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv;
288 EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
289
290 //
291 // Loop through the FFS files in the Boot Firmware Volume
292 //
293 for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
294 CurrentAddress = (EndOfFile + 7) & ~(7ULL);
295 if (CurrentAddress > EndOfFirmwareVolume) {
296 return EFI_VOLUME_CORRUPTED;
297 }
298
299 File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
300 Size = FFS_FILE_SIZE (File);
301 if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
302 return EFI_VOLUME_CORRUPTED;
303 }
304
305 EndOfFile = CurrentAddress + Size;
306 if (EndOfFile > EndOfFirmwareVolume) {
307 return EFI_VOLUME_CORRUPTED;
308 }
309
310 //
311 // Look for the request file type
312 //
313 if (File->Type != FileType) {
314 continue;
315 }
316
317 Status = FindFfsSectionInSections (
318 (VOID *)(File + 1),
319 (UINTN)EndOfFile - (UINTN)(File + 1),
320 SectionType,
321 FoundSection
322 );
323 if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
324 return Status;
325 }
326 }
327 }
328
329 /**
330 Locates the compressed main firmware volume and decompresses it.
331
332 @param[in,out] Fv On input, the firmware volume to search
333 On output, the decompressed BOOT/PEI FV
334
335 @retval EFI_SUCCESS The file and section was found
336 @retval EFI_NOT_FOUND The file and section was not found
337 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
338
339 **/
340 EFI_STATUS
341 DecompressMemFvs (
342 IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv
343 )
344 {
345 EFI_STATUS Status;
346 EFI_GUID_DEFINED_SECTION *Section;
347 UINT32 OutputBufferSize;
348 UINT32 ScratchBufferSize;
349 UINT16 SectionAttribute;
350 UINT32 AuthenticationStatus;
351 VOID *OutputBuffer;
352 VOID *ScratchBuffer;
353 EFI_COMMON_SECTION_HEADER *FvSection;
354 EFI_FIRMWARE_VOLUME_HEADER *PeiMemFv;
355 EFI_FIRMWARE_VOLUME_HEADER *DxeMemFv;
356 UINT32 FvHeaderSize;
357 UINT32 FvSectionSize;
358
359 FvSection = (EFI_COMMON_SECTION_HEADER *)NULL;
360
361 Status = FindFfsFileAndSection (
362 *Fv,
363 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
364 EFI_SECTION_GUID_DEFINED,
365 (EFI_COMMON_SECTION_HEADER **)&Section
366 );
367 if (EFI_ERROR (Status)) {
368 DEBUG ((DEBUG_ERROR, "Unable to find GUID defined section\n"));
369 return Status;
370 }
371
372 Status = ExtractGuidedSectionGetInfo (
373 Section,
374 &OutputBufferSize,
375 &ScratchBufferSize,
376 &SectionAttribute
377 );
378 if (EFI_ERROR (Status)) {
379 DEBUG ((DEBUG_ERROR, "Unable to GetInfo for GUIDed section\n"));
380 return Status;
381 }
382
383 OutputBuffer = (VOID *)((UINT8 *)(UINTN)PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);
384 ScratchBuffer = ALIGN_POINTER ((UINT8 *)OutputBuffer + OutputBufferSize, SIZE_1MB);
385
386 DEBUG ((
387 DEBUG_VERBOSE,
388 "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
389 "PcdOvmfDecompressionScratchEnd=0x%x\n",
390 __FUNCTION__,
391 OutputBuffer,
392 OutputBufferSize,
393 ScratchBuffer,
394 ScratchBufferSize,
395 PcdGet32 (PcdOvmfDecompressionScratchEnd)
396 ));
397 ASSERT (
398 (UINTN)ScratchBuffer + ScratchBufferSize ==
399 PcdGet32 (PcdOvmfDecompressionScratchEnd)
400 );
401
402 Status = ExtractGuidedSectionDecode (
403 Section,
404 &OutputBuffer,
405 ScratchBuffer,
406 &AuthenticationStatus
407 );
408 if (EFI_ERROR (Status)) {
409 DEBUG ((DEBUG_ERROR, "Error during GUID section decode\n"));
410 return Status;
411 }
412
413 Status = FindFfsSectionInstance (
414 OutputBuffer,
415 OutputBufferSize,
416 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
417 0,
418 &FvSection
419 );
420 if (EFI_ERROR (Status)) {
421 DEBUG ((DEBUG_ERROR, "Unable to find PEI FV section\n"));
422 return Status;
423 }
424
425 ASSERT (
426 SECTION_SIZE (FvSection) ==
427 (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection))
428 );
429 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
430
431 PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfPeiMemFvBase);
432 CopyMem (PeiMemFv, (VOID *)(FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));
433
434 if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {
435 DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));
436 CpuDeadLoop ();
437 return EFI_VOLUME_CORRUPTED;
438 }
439
440 Status = FindFfsSectionInstance (
441 OutputBuffer,
442 OutputBufferSize,
443 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
444 1,
445 &FvSection
446 );
447 if (EFI_ERROR (Status)) {
448 DEBUG ((DEBUG_ERROR, "Unable to find DXE FV section\n"));
449 return Status;
450 }
451
452 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
453
454 if (IS_SECTION2 (FvSection)) {
455 FvSectionSize = SECTION2_SIZE (FvSection);
456 FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
457 } else {
458 FvSectionSize = SECTION_SIZE (FvSection);
459 FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
460 }
461
462 ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize));
463
464 DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfDxeMemFvBase);
465 CopyMem (DxeMemFv, (VOID *)((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize));
466
467 if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {
468 DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));
469 CpuDeadLoop ();
470 return EFI_VOLUME_CORRUPTED;
471 }
472
473 *Fv = PeiMemFv;
474 return EFI_SUCCESS;
475 }
476
477 /**
478 Locates the PEI Core entry point address
479
480 @param[in] Fv The firmware volume to search
481 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
482
483 @retval EFI_SUCCESS The file and section was found
484 @retval EFI_NOT_FOUND The file and section was not found
485 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
486
487 **/
488 EFI_STATUS
489 FindPeiCoreImageBaseInFv (
490 IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
491 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
492 )
493 {
494 EFI_STATUS Status;
495 EFI_COMMON_SECTION_HEADER *Section;
496
497 Status = FindFfsFileAndSection (
498 Fv,
499 EFI_FV_FILETYPE_PEI_CORE,
500 EFI_SECTION_PE32,
501 &Section
502 );
503 if (EFI_ERROR (Status)) {
504 Status = FindFfsFileAndSection (
505 Fv,
506 EFI_FV_FILETYPE_PEI_CORE,
507 EFI_SECTION_TE,
508 &Section
509 );
510 if (EFI_ERROR (Status)) {
511 DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
512 return Status;
513 }
514 }
515
516 *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
517 return EFI_SUCCESS;
518 }
519
520 /**
521 Reads 8-bits of CMOS data.
522
523 Reads the 8-bits of CMOS data at the location specified by Index.
524 The 8-bit read value is returned.
525
526 @param Index The CMOS location to read.
527
528 @return The value read.
529
530 **/
531 STATIC
532 UINT8
533 CmosRead8 (
534 IN UINTN Index
535 )
536 {
537 IoWrite8 (0x70, (UINT8)Index);
538 return IoRead8 (0x71);
539 }
540
541 STATIC
542 BOOLEAN
543 IsS3Resume (
544 VOID
545 )
546 {
547 return (CmosRead8 (0xF) == 0xFE);
548 }
549
550 STATIC
551 EFI_STATUS
552 GetS3ResumePeiFv (
553 IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv
554 )
555 {
556 *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfPeiMemFvBase);
557 return EFI_SUCCESS;
558 }
559
560 /**
561 Locates the PEI Core entry point address
562
563 @param[in,out] Fv The firmware volume to search
564 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
565
566 @retval EFI_SUCCESS The file and section was found
567 @retval EFI_NOT_FOUND The file and section was not found
568 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
569
570 **/
571 VOID
572 FindPeiCoreImageBase (
573 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv,
574 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
575 )
576 {
577 BOOLEAN S3Resume;
578
579 *PeiCoreImageBase = 0;
580
581 S3Resume = IsS3Resume ();
582 if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {
583 //
584 // A malicious runtime OS may have injected something into our previously
585 // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
586 //
587 DEBUG ((DEBUG_VERBOSE, "SEC: S3 resume\n"));
588 GetS3ResumePeiFv (BootFv);
589 } else {
590 //
591 // We're either not resuming, or resuming "securely" -- we'll decompress
592 // both PEI FV and DXE FV from pristine flash.
593 //
594 DEBUG ((
595 DEBUG_VERBOSE,
596 "SEC: %a\n",
597 S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"
598 ));
599 FindMainFv (BootFv);
600
601 DecompressMemFvs (BootFv);
602 }
603
604 FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
605 }
606
607 /**
608 Find core image base.
609
610 **/
611 EFI_STATUS
612 FindImageBase (
613 IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr,
614 OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase
615 )
616 {
617 EFI_PHYSICAL_ADDRESS CurrentAddress;
618 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
619 EFI_FFS_FILE_HEADER *File;
620 UINT32 Size;
621 EFI_PHYSICAL_ADDRESS EndOfFile;
622 EFI_COMMON_SECTION_HEADER *Section;
623 EFI_PHYSICAL_ADDRESS EndOfSection;
624
625 *SecCoreImageBase = 0;
626
627 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BootFirmwareVolumePtr;
628 EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
629
630 //
631 // Loop through the FFS files in the Boot Firmware Volume
632 //
633 for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
634 CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
635 if (CurrentAddress > EndOfFirmwareVolume) {
636 return EFI_NOT_FOUND;
637 }
638
639 File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
640 Size = FFS_FILE_SIZE (File);
641 if (Size < sizeof (*File)) {
642 return EFI_NOT_FOUND;
643 }
644
645 EndOfFile = CurrentAddress + Size;
646 if (EndOfFile > EndOfFirmwareVolume) {
647 return EFI_NOT_FOUND;
648 }
649
650 //
651 // Look for SEC Core
652 //
653 if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
654 continue;
655 }
656
657 //
658 // Loop through the FFS file sections within the FFS file
659 //
660 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)(File + 1);
661 for ( ; ;) {
662 CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
663 Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
664
665 Size = SECTION_SIZE (Section);
666 if (Size < sizeof (*Section)) {
667 return EFI_NOT_FOUND;
668 }
669
670 EndOfSection = CurrentAddress + Size;
671 if (EndOfSection > EndOfFile) {
672 return EFI_NOT_FOUND;
673 }
674
675 //
676 // Look for executable sections
677 //
678 if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) {
679 if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
680 *SecCoreImageBase = (PHYSICAL_ADDRESS)(UINTN)(Section + 1);
681 }
682
683 break;
684 }
685 }
686
687 //
688 // SEC Core image found
689 //
690 if (*SecCoreImageBase != 0) {
691 return EFI_SUCCESS;
692 }
693 }
694 }
695
696 /*
697 Find and return Pei Core entry point.
698
699 It also find SEC and PEI Core file debug information. It will report them if
700 remote debug is enabled.
701
702 **/
703 VOID
704 FindAndReportEntryPoints (
705 IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,
706 OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint
707 )
708 {
709 EFI_STATUS Status;
710 EFI_PHYSICAL_ADDRESS SecCoreImageBase;
711 EFI_PHYSICAL_ADDRESS PeiCoreImageBase;
712 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
713
714 //
715 // Find SEC Core and PEI Core image base
716 //
717 Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
718 ASSERT_EFI_ERROR (Status);
719
720 FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
721
722 ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
723 //
724 // Report SEC Core debug information when remote debug is enabled
725 //
726 ImageContext.ImageAddress = SecCoreImageBase;
727 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
728 PeCoffLoaderRelocateImageExtraAction (&ImageContext);
729
730 //
731 // Report PEI Core debug information when remote debug is enabled
732 //
733 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
734 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
735 PeCoffLoaderRelocateImageExtraAction (&ImageContext);
736
737 //
738 // Find PEI Core entry point
739 //
740 Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint);
741 if (EFI_ERROR (Status)) {
742 *PeiCoreEntryPoint = 0;
743 }
744
745 return;
746 }
747
748 VOID
749 EFIAPI
750 SecCoreStartupWithStack (
751 IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,
752 IN VOID *TopOfCurrentStack
753 )
754 {
755 EFI_SEC_PEI_HAND_OFF SecCoreData;
756 SEC_IDT_TABLE IdtTableInStack;
757 IA32_DESCRIPTOR IdtDescriptor;
758 UINT32 Index;
759 volatile UINT8 *Table;
760
761 #if defined (TDX_GUEST_SUPPORTED)
762 if (CcProbe () == CcGuestTypeIntelTdx) {
763 //
764 // From the security perspective all the external input should be measured before
765 // it is consumed. TdHob and Configuration FV (Cfv) image are passed from VMM
766 // and should be measured here.
767 //
768 if (EFI_ERROR (TdxHelperMeasureTdHob ())) {
769 CpuDeadLoop ();
770 }
771
772 if (EFI_ERROR (TdxHelperMeasureCfvImage ())) {
773 CpuDeadLoop ();
774 }
775
776 //
777 // For Td guests, the memory map info is in TdHobLib. It should be processed
778 // first so that the memory is accepted. Otherwise access to the unaccepted
779 // memory will trigger tripple fault.
780 //
781 if (TdxHelperProcessTdHob () != EFI_SUCCESS) {
782 CpuDeadLoop ();
783 }
784 }
785
786 #endif
787
788 //
789 // To ensure SMM can't be compromised on S3 resume, we must force re-init of
790 // the BaseExtractGuidedSectionLib. Since this is before library contructors
791 // are called, we must use a loop rather than SetMem.
792 //
793 Table = (UINT8 *)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
794 for (Index = 0;
795 Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
796 ++Index)
797 {
798 Table[Index] = 0;
799 }
800
801 //
802 // Initialize IDT - Since this is before library constructors are called,
803 // we use a loop rather than CopyMem.
804 //
805 IdtTableInStack.PeiService = NULL;
806
807 for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
808 //
809 // Declare the local variables that actually move the data elements as
810 // volatile to prevent the optimizer from replacing this function with
811 // the intrinsic memcpy()
812 //
813 CONST UINT8 *Src;
814 volatile UINT8 *Dst;
815 UINTN Byte;
816
817 Src = (CONST UINT8 *)&mIdtEntryTemplate;
818 Dst = (volatile UINT8 *)&IdtTableInStack.IdtTable[Index];
819 for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
820 Dst[Byte] = Src[Byte];
821 }
822 }
823
824 IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
825 IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
826
827 if (SevEsIsEnabled ()) {
828 SevEsProtocolCheck ();
829
830 //
831 // For SEV-ES guests, the exception handler is needed before calling
832 // ProcessLibraryConstructorList() because some of the library constructors
833 // perform some functions that result in #VC exceptions being generated.
834 //
835 // Due to this code executing before library constructors, *all* library
836 // API calls are theoretically interface contract violations. However,
837 // because this is SEC (executing in flash), those constructors cannot
838 // write variables with static storage duration anyway. Furthermore, only
839 // a small, restricted set of APIs, such as AsmWriteIdtr() and
840 // InitializeCpuExceptionHandlers(), are called, where we require that the
841 // underlying library not require constructors to have been invoked and
842 // that the library instance not trigger any #VC exceptions.
843 //
844 AsmWriteIdtr (&IdtDescriptor);
845 InitializeCpuExceptionHandlers (NULL);
846 }
847
848 ProcessLibraryConstructorList (NULL, NULL);
849
850 if (!SevEsIsEnabled ()) {
851 //
852 // For non SEV-ES guests, just load the IDTR.
853 //
854 AsmWriteIdtr (&IdtDescriptor);
855 } else {
856 //
857 // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
858 // caching in order to speed up the boot. Enable caching early for
859 // an SEV-ES guest.
860 //
861 AsmEnableCache ();
862 }
863
864 #if defined (TDX_GUEST_SUPPORTED)
865 if (CcProbe () == CcGuestTypeIntelTdx) {
866 //
867 // InitializeCpuExceptionHandlers () should be called in Td guests so that
868 // #VE exceptions can be handled correctly.
869 //
870 InitializeCpuExceptionHandlers (NULL);
871 }
872
873 #endif
874
875 DEBUG ((
876 DEBUG_INFO,
877 "SecCoreStartupWithStack(0x%x, 0x%x)\n",
878 (UINT32)(UINTN)BootFv,
879 (UINT32)(UINTN)TopOfCurrentStack
880 ));
881
882 //
883 // Initialize floating point operating environment
884 // to be compliant with UEFI spec.
885 //
886 InitializeFloatingPointUnits ();
887
888 #if defined (MDE_CPU_X64)
889 //
890 // ASSERT that the Page Tables were set by the reset vector code to
891 // the address we expect.
892 //
893 ASSERT (AsmReadCr3 () == (UINTN)PcdGet32 (PcdOvmfSecPageTablesBase));
894 #endif
895
896 //
897 // |-------------| <-- TopOfCurrentStack
898 // | Stack | 32k
899 // |-------------|
900 // | Heap | 32k
901 // |-------------| <-- SecCoreData.TemporaryRamBase
902 //
903
904 ASSERT (
905 (UINTN)(PcdGet32 (PcdOvmfSecPeiTempRamBase) +
906 PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
907 (UINTN)TopOfCurrentStack
908 );
909
910 //
911 // Initialize SEC hand-off state
912 //
913 SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
914
915 SecCoreData.TemporaryRamSize = (UINTN)PcdGet32 (PcdOvmfSecPeiTempRamSize);
916 SecCoreData.TemporaryRamBase = (VOID *)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
917
918 SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
919 SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
920
921 SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
922 SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
923
924 SecCoreData.BootFirmwareVolumeBase = BootFv;
925 SecCoreData.BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
926
927 //
928 // Validate the System RAM used in the SEC Phase
929 //
930 SecValidateSystemRam ();
931
932 //
933 // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
934 //
935 IoWrite8 (0x21, 0xff);
936 IoWrite8 (0xA1, 0xff);
937
938 //
939 // Initialize Local APIC Timer hardware and disable Local APIC Timer
940 // interrupts before initializing the Debug Agent and the debug timer is
941 // enabled.
942 //
943 InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
944 DisableApicTimerInterrupt ();
945
946 //
947 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
948 //
949 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
950 }
951
952 /**
953 Caller provided function to be invoked at the end of InitializeDebugAgent().
954
955 Entry point to the C language phase of SEC. After the SEC assembly
956 code has initialized some temporary memory and set up the stack,
957 the control is transferred to this function.
958
959 @param[in] Context The first input parameter of InitializeDebugAgent().
960
961 **/
962 VOID
963 EFIAPI
964 SecStartupPhase2 (
965 IN VOID *Context
966 )
967 {
968 EFI_SEC_PEI_HAND_OFF *SecCoreData;
969 EFI_FIRMWARE_VOLUME_HEADER *BootFv;
970 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
971 EFI_PEI_PPI_DESCRIPTOR *EfiPeiPpiDescriptor;
972
973 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
974
975 //
976 // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
977 // is enabled.
978 //
979 BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
980 FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
981 SecCoreData->BootFirmwareVolumeBase = BootFv;
982 SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
983
984 //
985 // Td guest is required to use the MpInitLibUp (unique-processor version).
986 // Other guests use the MpInitLib (multi-processor version).
987 //
988 if (CcProbe () == CcGuestTypeIntelTdx) {
989 EfiPeiPpiDescriptor = (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTableUp;
990 } else {
991 EfiPeiPpiDescriptor = (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTableMp;
992 }
993
994 //
995 // Transfer the control to the PEI core
996 //
997 (*PeiCoreEntryPoint)(SecCoreData, EfiPeiPpiDescriptor);
998
999 //
1000 // If we get here then the PEI Core returned, which is not recoverable.
1001 //
1002 ASSERT (FALSE);
1003 CpuDeadLoop ();
1004 }
1005
1006 EFI_STATUS
1007 EFIAPI
1008 TemporaryRamMigration (
1009 IN CONST EFI_PEI_SERVICES **PeiServices,
1010 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
1011 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
1012 IN UINTN CopySize
1013 )
1014 {
1015 IA32_DESCRIPTOR IdtDescriptor;
1016 VOID *OldHeap;
1017 VOID *NewHeap;
1018 VOID *OldStack;
1019 VOID *NewStack;
1020 DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;
1021 BOOLEAN OldStatus;
1022 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
1023
1024 DEBUG ((
1025 DEBUG_INFO,
1026 "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
1027 TemporaryMemoryBase,
1028 PermanentMemoryBase,
1029 (UINT64)CopySize
1030 ));
1031
1032 OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;
1033 NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));
1034
1035 OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
1036 NewStack = (VOID *)(UINTN)PermanentMemoryBase;
1037
1038 DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
1039 DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
1040
1041 OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
1042 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *)&DebugAgentContext, NULL);
1043
1044 //
1045 // Migrate Heap
1046 //
1047 CopyMem (NewHeap, OldHeap, CopySize >> 1);
1048
1049 //
1050 // Migrate Stack
1051 //
1052 CopyMem (NewStack, OldStack, CopySize >> 1);
1053
1054 //
1055 // Rebase IDT table in permanent memory
1056 //
1057 AsmReadIdtr (&IdtDescriptor);
1058 IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
1059
1060 AsmWriteIdtr (&IdtDescriptor);
1061
1062 //
1063 // Use SetJump()/LongJump() to switch to a new stack.
1064 //
1065 if (SetJump (&JumpBuffer) == 0) {
1066 #if defined (MDE_CPU_IA32)
1067 JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
1068 JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;
1069 #endif
1070 #if defined (MDE_CPU_X64)
1071 JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
1072 JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;
1073 #endif
1074 LongJump (&JumpBuffer, (UINTN)-1);
1075 }
1076
1077 SaveAndSetDebugTimerInterrupt (OldStatus);
1078
1079 return EFI_SUCCESS;
1080 }