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