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