• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Last PEIM.
3   Responsibility of this module is to load the DXE Core from a Firmware Volume.
4 
5 Copyright (c) 2016 HP Development Company, L.P.
6 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "DxeIpl.h"
18 
19 
20 //
21 // Module Globals used in the DXE to PEI hand off
22 // These must be module globals, so the stack can be switched
23 //
24 CONST EFI_DXE_IPL_PPI mDxeIplPpi = {
25   DxeLoadCore
26 };
27 
28 CONST EFI_PEI_PPI_DESCRIPTOR mDxeIplPpiList = {
29   EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
30   &gEfiDxeIplPpiGuid,
31   (VOID *) &mDxeIplPpi
32 };
33 
34 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
35   CustomGuidedSectionExtract
36 };
37 
38 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
39   Decompress
40 };
41 
42 CONST EFI_PEI_PPI_DESCRIPTOR mDecompressPpiList = {
43   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
44   &gEfiPeiDecompressPpiGuid,
45   (VOID *) &mDecompressPpi
46 };
47 
48 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = {
49   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
50   &gEfiEndOfPeiSignalPpiGuid,
51   NULL
52 };
53 
54 CONST EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList = {
55   (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
56   &gEfiPeiMemoryDiscoveredPpiGuid,
57   InstallIplPermanentMemoryPpis
58 };
59 
60 /**
61   Entry point of DXE IPL PEIM.
62 
63   This function installs DXE IPL PPI.  It also reloads
64   itself to memory on non-S3 resume boot path.
65 
66   @param  FileHandle  Handle of the file being invoked.
67   @param  PeiServices Describes the list of possible PEI Services.
68 
69   @retval EFI_SUCESS  The entry point of DXE IPL PEIM executes successfully.
70   @retval Others      Some error occurs during the execution of this function.
71 
72 **/
73 EFI_STATUS
74 EFIAPI
PeimInitializeDxeIpl(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)75 PeimInitializeDxeIpl (
76   IN       EFI_PEI_FILE_HANDLE  FileHandle,
77   IN CONST EFI_PEI_SERVICES     **PeiServices
78   )
79 {
80   EFI_STATUS                                Status;
81   EFI_BOOT_MODE                             BootMode;
82   VOID                                      *Dummy;
83 
84   BootMode = GetBootModeHob ();
85 
86   if (BootMode != BOOT_ON_S3_RESUME) {
87     Status = PeiServicesRegisterForShadow (FileHandle);
88     if (Status == EFI_SUCCESS) {
89       //
90       // EFI_SUCESS means it is the first time to call register for shadow.
91       //
92       return Status;
93     }
94 
95     //
96     // Ensure that DXE IPL is shadowed to permanent memory.
97     //
98     ASSERT (Status == EFI_ALREADY_STARTED);
99 
100     //
101     // DXE core load requires permanent memory.
102     //
103     Status = PeiServicesLocatePpi (
104                &gEfiPeiMemoryDiscoveredPpiGuid,
105                0,
106                NULL,
107                (VOID **) &Dummy
108                );
109     ASSERT_EFI_ERROR (Status);
110     if (EFI_ERROR (Status)) {
111       return Status;
112     }
113 
114     //
115     // Now the permanent memory exists, install the PPIs for decompression
116     // and section extraction.
117     //
118     Status = InstallIplPermanentMemoryPpis (NULL, NULL, NULL);
119     ASSERT_EFI_ERROR (Status);
120   } else {
121     //
122     // Install memory discovered PPI notification to install PPIs for
123     // decompression and section extraction.
124     //
125     Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList);
126     ASSERT_EFI_ERROR (Status);
127   }
128 
129   //
130   // Install DxeIpl PPI.
131   //
132   Status = PeiServicesInstallPpi (&mDxeIplPpiList);
133   ASSERT_EFI_ERROR(Status);
134 
135   return Status;
136 }
137 
138 /**
139    This function installs the PPIs that require permanent memory.
140 
141    @param  PeiServices      Indirect reference to the PEI Services Table.
142    @param  NotifyDescriptor Address of the notification descriptor data structure.
143    @param  Ppi              Address of the PPI that was installed.
144 
145    @return EFI_SUCCESS      The PPIs were installed successfully.
146    @return Others           Some error occurs during the execution of this function.
147 
148 **/
149 EFI_STATUS
150 EFIAPI
InstallIplPermanentMemoryPpis(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)151 InstallIplPermanentMemoryPpis (
152   IN EFI_PEI_SERVICES           **PeiServices,
153   IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
154   IN VOID                       *Ppi
155   )
156 {
157   EFI_STATUS                    Status;
158   EFI_GUID                      *ExtractHandlerGuidTable;
159   UINTN                         ExtractHandlerNumber;
160   EFI_PEI_PPI_DESCRIPTOR        *GuidPpi;
161 
162   //
163   // Get custom extract guided section method guid list
164   //
165   ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
166 
167   //
168   // Install custom guided section extraction PPI
169   //
170   if (ExtractHandlerNumber > 0) {
171     GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));
172     ASSERT (GuidPpi != NULL);
173     while (ExtractHandlerNumber-- > 0) {
174       GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
175       GuidPpi->Ppi   = (VOID *) &mCustomGuidedSectionExtractionPpi;
176       GuidPpi->Guid  = &ExtractHandlerGuidTable[ExtractHandlerNumber];
177       Status = PeiServicesInstallPpi (GuidPpi++);
178       ASSERT_EFI_ERROR(Status);
179     }
180   }
181 
182   //
183   // Install Decompress PPI.
184   //
185   Status = PeiServicesInstallPpi (&mDecompressPpiList);
186   ASSERT_EFI_ERROR(Status);
187 
188   return Status;
189 }
190 
191 /**
192    Validate variable data for the MemoryTypeInformation.
193 
194    @param MemoryData       Variable data.
195    @param MemoryDataSize   Variable data length.
196 
197    @return TRUE            The variable data is valid.
198    @return FALSE           The variable data is invalid.
199 
200 **/
201 BOOLEAN
ValidateMemoryTypeInfoVariable(IN EFI_MEMORY_TYPE_INFORMATION * MemoryData,IN UINTN MemoryDataSize)202 ValidateMemoryTypeInfoVariable (
203   IN EFI_MEMORY_TYPE_INFORMATION      *MemoryData,
204   IN UINTN                            MemoryDataSize
205   )
206 {
207   UINTN                       Count;
208   UINTN                       Index;
209 
210   // Check the input parameter.
211   if (MemoryData == NULL) {
212     return FALSE;
213   }
214 
215   // Get Count
216   Count = MemoryDataSize / sizeof (*MemoryData);
217 
218   // Check Size
219   if (Count * sizeof(*MemoryData) != MemoryDataSize) {
220     return FALSE;
221   }
222 
223   // Check last entry type filed.
224   if (MemoryData[Count - 1].Type != EfiMaxMemoryType) {
225     return FALSE;
226   }
227 
228   // Check the type filed.
229   for (Index = 0; Index < Count - 1; Index++) {
230     if (MemoryData[Index].Type >= EfiMaxMemoryType) {
231       return FALSE;
232     }
233   }
234 
235   return TRUE;
236 }
237 
238 /**
239    Main entry point to last PEIM.
240 
241    This function finds DXE Core in the firmware volume and transfer the control to
242    DXE core.
243 
244    @param This          Entry point for DXE IPL PPI.
245    @param PeiServices   General purpose services available to every PEIM.
246    @param HobList       Address to the Pei HOB list.
247 
248    @return EFI_SUCCESS              DXE core was successfully loaded.
249    @return EFI_OUT_OF_RESOURCES     There are not enough resources to load DXE core.
250 
251 **/
252 EFI_STATUS
253 EFIAPI
DxeLoadCore(IN CONST EFI_DXE_IPL_PPI * This,IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_HOB_POINTERS HobList)254 DxeLoadCore (
255   IN CONST EFI_DXE_IPL_PPI *This,
256   IN EFI_PEI_SERVICES      **PeiServices,
257   IN EFI_PEI_HOB_POINTERS  HobList
258   )
259 {
260   EFI_STATUS                                Status;
261   EFI_FV_FILE_INFO                          DxeCoreFileInfo;
262   EFI_PHYSICAL_ADDRESS                      DxeCoreAddress;
263   UINT64                                    DxeCoreSize;
264   EFI_PHYSICAL_ADDRESS                      DxeCoreEntryPoint;
265   EFI_BOOT_MODE                             BootMode;
266   EFI_PEI_FILE_HANDLE                       FileHandle;
267   EFI_PEI_READ_ONLY_VARIABLE2_PPI           *Variable;
268   EFI_PEI_LOAD_FILE_PPI                     *LoadFile;
269   UINTN                                     Instance;
270   UINT32                                    AuthenticationState;
271   UINTN                                     DataSize;
272   EFI_PEI_S3_RESUME2_PPI                    *S3Resume;
273   EFI_PEI_RECOVERY_MODULE_PPI               *PeiRecovery;
274   EFI_MEMORY_TYPE_INFORMATION               MemoryData[EfiMaxMemoryType + 1];
275 
276   //
277   // if in S3 Resume, restore configure
278   //
279   BootMode = GetBootModeHob ();
280 
281   if (BootMode == BOOT_ON_S3_RESUME) {
282     Status = PeiServicesLocatePpi (
283                &gEfiPeiS3Resume2PpiGuid,
284                0,
285                NULL,
286                (VOID **) &S3Resume
287                );
288     if (EFI_ERROR (Status)) {
289       //
290       // Report Status code that S3Resume PPI can not be found
291       //
292       REPORT_STATUS_CODE (
293         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
294         (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_PPI_NOT_FOUND)
295         );
296     }
297     ASSERT_EFI_ERROR (Status);
298 
299     Status = S3Resume->S3RestoreConfig2 (S3Resume);
300     ASSERT_EFI_ERROR (Status);
301   } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
302     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_RECOVERY_BEGIN));
303     Status = PeiServicesLocatePpi (
304                &gEfiPeiRecoveryModulePpiGuid,
305                0,
306                NULL,
307                (VOID **) &PeiRecovery
308                );
309 
310     if (EFI_ERROR (Status)) {
311       DEBUG ((DEBUG_ERROR, "Locate Recovery PPI Failed.(Status = %r)\n", Status));
312       //
313       // Report Status code the failure of locating Recovery PPI
314       //
315       REPORT_STATUS_CODE (
316         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
317         (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND)
318         );
319       CpuDeadLoop ();
320     }
321 
322     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_LOAD));
323     Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
324     if (EFI_ERROR (Status)) {
325       DEBUG ((DEBUG_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
326       //
327       // Report Status code that recovery image can not be found
328       //
329       REPORT_STATUS_CODE (
330         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
331         (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE)
332         );
333       CpuDeadLoop ();
334     }
335     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_START));
336     //
337     // Now should have a HOB with the DXE core
338     //
339   }
340 
341   if (GetFirstGuidHob ((CONST EFI_GUID *)&gEfiMemoryTypeInformationGuid) == NULL) {
342     //
343     // Don't build GuidHob if GuidHob has been installed.
344     //
345     Status = PeiServicesLocatePpi (
346                &gEfiPeiReadOnlyVariable2PpiGuid,
347                0,
348                NULL,
349                (VOID **)&Variable
350                );
351     if (!EFI_ERROR (Status)) {
352       DataSize = sizeof (MemoryData);
353       Status = Variable->GetVariable (
354                            Variable,
355                            EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
356                            &gEfiMemoryTypeInformationGuid,
357                            NULL,
358                            &DataSize,
359                            &MemoryData
360                            );
361       if (!EFI_ERROR (Status) && ValidateMemoryTypeInfoVariable(MemoryData, DataSize)) {
362         //
363         // Build the GUID'd HOB for DXE
364         //
365         BuildGuidDataHob (
366           &gEfiMemoryTypeInformationGuid,
367           MemoryData,
368           DataSize
369           );
370       }
371     }
372   }
373 
374   //
375   // Look in all the FVs present in PEI and find the DXE Core FileHandle
376   //
377   FileHandle = DxeIplFindDxeCore ();
378 
379   //
380   // Load the DXE Core from a Firmware Volume.
381   //
382   Instance = 0;
383   do {
384     Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **) &LoadFile);
385     //
386     // These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
387     //
388     ASSERT_EFI_ERROR (Status);
389 
390     Status = LoadFile->LoadFile (
391                          LoadFile,
392                          FileHandle,
393                          &DxeCoreAddress,
394                          &DxeCoreSize,
395                          &DxeCoreEntryPoint,
396                          &AuthenticationState
397                          );
398   } while (EFI_ERROR (Status));
399 
400   //
401   // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
402   //
403   Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
404   ASSERT_EFI_ERROR (Status);
405 
406   //
407   // Add HOB for the DXE Core
408   //
409   BuildModuleHob (
410     &DxeCoreFileInfo.FileName,
411     DxeCoreAddress,
412     ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
413     DxeCoreEntryPoint
414     );
415 
416   //
417   // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
418   //
419   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT));
420 
421   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN)DxeCoreAddress, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)));
422 
423   //
424   // Transfer control to the DXE Core
425   // The hand off state is simply a pointer to the HOB list
426   //
427   HandOffToDxeCore (DxeCoreEntryPoint, HobList);
428   //
429   // If we get here, then the DXE Core returned.  This is an error
430   // DxeCore should not return.
431   //
432   ASSERT (FALSE);
433   CpuDeadLoop ();
434 
435   return EFI_OUT_OF_RESOURCES;
436 }
437 
438 
439 /**
440    Searches DxeCore in all firmware Volumes and loads the first
441    instance that contains DxeCore.
442 
443    @return FileHandle of DxeCore to load DxeCore.
444 
445 **/
446 EFI_PEI_FILE_HANDLE
DxeIplFindDxeCore(VOID)447 DxeIplFindDxeCore (
448   VOID
449   )
450 {
451   EFI_STATUS            Status;
452   UINTN                 Instance;
453   EFI_PEI_FV_HANDLE     VolumeHandle;
454   EFI_PEI_FILE_HANDLE   FileHandle;
455 
456   Instance    = 0;
457   while (TRUE) {
458     //
459     // Traverse all firmware volume instances
460     //
461     Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
462     //
463     // If some error occurs here, then we cannot find any firmware
464     // volume that may contain DxeCore.
465     //
466     if (EFI_ERROR (Status)) {
467       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_EC_DXE_CORRUPT));
468     }
469     ASSERT_EFI_ERROR (Status);
470 
471     //
472     // Find the DxeCore file type from the beginning in this firmware volume.
473     //
474     FileHandle = NULL;
475     Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle);
476     if (!EFI_ERROR (Status)) {
477       //
478       // Find DxeCore FileHandle in this volume, then we skip other firmware volume and
479       // return the FileHandle.
480       //
481       return FileHandle;
482     }
483     //
484     // We cannot find DxeCore in this firmware volume, then search the next volume.
485     //
486     Instance++;
487   }
488 }
489 
490 
491 
492 /**
493   The ExtractSection() function processes the input section and
494   returns a pointer to the section contents. If the section being
495   extracted does not require processing (if the section
496   GuidedSectionHeader.Attributes has the
497   EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
498   OutputBuffer is just updated to point to the start of the
499   section's contents. Otherwise, *Buffer must be allocated
500   from PEI permanent memory.
501 
502   @param This                   Indicates the
503                                 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
504                                 Buffer containing the input GUIDed section to be
505                                 processed. OutputBuffer OutputBuffer is
506                                 allocated from PEI permanent memory and contains
507                                 the new section stream.
508   @param InputSection           A pointer to the input buffer, which contains
509                                 the input section to be processed.
510   @param OutputBuffer           A pointer to a caller-allocated buffer, whose
511                                 size is specified by the contents of OutputSize.
512   @param OutputSize             A pointer to a caller-allocated
513                                 UINTN in which the size of *OutputBuffer
514                                 allocation is stored. If the function
515                                 returns anything other than EFI_SUCCESS,
516                                 the value of OutputSize is undefined.
517   @param AuthenticationStatus   A pointer to a caller-allocated
518                                 UINT32 that indicates the
519                                 authentication status of the
520                                 output buffer. If the input
521                                 section's GuidedSectionHeader.
522                                 Attributes field has the
523                                 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
524                                 bit as clear,
525                                 AuthenticationStatus must return
526                                 zero. These bits reflect the
527                                 status of the extraction
528                                 operation. If the function
529                                 returns anything other than
530                                 EFI_SUCCESS, the value of
531                                 AuthenticationStatus is
532                                 undefined.
533 
534   @retval EFI_SUCCESS           The InputSection was
535                                 successfully processed and the
536                                 section contents were returned.
537 
538   @retval EFI_OUT_OF_RESOURCES  The system has insufficient
539                                 resources to process the request.
540 
541   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
542                                 not match this instance of the
543                                 GUIDed Section Extraction PPI.
544 
545 **/
546 EFI_STATUS
547 EFIAPI
CustomGuidedSectionExtract(IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI * This,IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,OUT UINTN * OutputSize,OUT UINT32 * AuthenticationStatus)548 CustomGuidedSectionExtract (
549   IN CONST  EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
550   IN CONST  VOID                                  *InputSection,
551   OUT       VOID                                  **OutputBuffer,
552   OUT       UINTN                                 *OutputSize,
553   OUT       UINT32                                *AuthenticationStatus
554 )
555 {
556   EFI_STATUS      Status;
557   UINT8           *ScratchBuffer;
558   UINT32          ScratchBufferSize;
559   UINT32          OutputBufferSize;
560   UINT16          SectionAttribute;
561 
562   //
563   // Init local variable
564   //
565   ScratchBuffer = NULL;
566 
567   //
568   // Call GetInfo to get the size and attribute of input guided section data.
569   //
570   Status = ExtractGuidedSectionGetInfo (
571              InputSection,
572              &OutputBufferSize,
573              &ScratchBufferSize,
574              &SectionAttribute
575              );
576 
577   if (EFI_ERROR (Status)) {
578     DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
579     return Status;
580   }
581 
582   if (ScratchBufferSize != 0) {
583     //
584     // Allocate scratch buffer
585     //
586     ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
587     if (ScratchBuffer == NULL) {
588       return EFI_OUT_OF_RESOURCES;
589     }
590   }
591 
592   if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {
593     //
594     // Allocate output buffer
595     //
596     *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1);
597     if (*OutputBuffer == NULL) {
598       return EFI_OUT_OF_RESOURCES;
599     }
600     DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
601     //
602     // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
603     // skip EFI section header to make section data at page alignment.
604     //
605     *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER));
606   }
607 
608   Status = ExtractGuidedSectionDecode (
609              InputSection,
610              OutputBuffer,
611              ScratchBuffer,
612              AuthenticationStatus
613              );
614   if (EFI_ERROR (Status)) {
615     //
616     // Decode failed
617     //
618     DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
619     return Status;
620   }
621 
622   *OutputSize = (UINTN) OutputBufferSize;
623 
624   return EFI_SUCCESS;
625 }
626 
627 
628 
629 /**
630    Decompresses a section to the output buffer.
631 
632    This function looks up the compression type field in the input section and
633    applies the appropriate compression algorithm to compress the section to a
634    callee allocated buffer.
635 
636    @param  This                  Points to this instance of the
637                                  EFI_PEI_DECOMPRESS_PEI PPI.
638    @param  CompressionSection    Points to the compressed section.
639    @param  OutputBuffer          Holds the returned pointer to the decompressed
640                                  sections.
641    @param  OutputSize            Holds the returned size of the decompress
642                                  section streams.
643 
644    @retval EFI_SUCCESS           The section was decompressed successfully.
645                                  OutputBuffer contains the resulting data and
646                                  OutputSize contains the resulting size.
647 
648 **/
649 EFI_STATUS
650 EFIAPI
Decompress(IN CONST EFI_PEI_DECOMPRESS_PPI * This,IN CONST EFI_COMPRESSION_SECTION * CompressionSection,OUT VOID ** OutputBuffer,OUT UINTN * OutputSize)651 Decompress (
652   IN CONST  EFI_PEI_DECOMPRESS_PPI  *This,
653   IN CONST  EFI_COMPRESSION_SECTION *CompressionSection,
654   OUT       VOID                    **OutputBuffer,
655   OUT       UINTN                   *OutputSize
656  )
657 {
658   EFI_STATUS                      Status;
659   UINT8                           *DstBuffer;
660   UINT8                           *ScratchBuffer;
661   UINT32                          DstBufferSize;
662   UINT32                          ScratchBufferSize;
663   VOID                            *CompressionSource;
664   UINT32                          CompressionSourceSize;
665   UINT32                          UncompressedLength;
666   UINT8                           CompressionType;
667 
668   if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
669     ASSERT (FALSE);
670     return EFI_INVALID_PARAMETER;
671   }
672 
673   if (IS_SECTION2 (CompressionSection)) {
674     CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2));
675     CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2));
676     UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength;
677     CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType;
678   } else {
679     CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION));
680     CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION));
681     UncompressedLength = CompressionSection->UncompressedLength;
682     CompressionType = CompressionSection->CompressionType;
683   }
684 
685   //
686   // This is a compression set, expand it
687   //
688   switch (CompressionType) {
689   case EFI_STANDARD_COMPRESSION:
690     if (FeaturePcdGet(PcdDxeIplSupportUefiDecompress)) {
691       //
692       // Load EFI standard compression.
693       // For compressed data, decompress them to destination buffer.
694       //
695       Status = UefiDecompressGetInfo (
696                  CompressionSource,
697                  CompressionSourceSize,
698                  &DstBufferSize,
699                  &ScratchBufferSize
700                  );
701       if (EFI_ERROR (Status)) {
702         //
703         // GetInfo failed
704         //
705         DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));
706         return EFI_NOT_FOUND;
707       }
708       //
709       // Allocate scratch buffer
710       //
711       ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
712       if (ScratchBuffer == NULL) {
713         return EFI_OUT_OF_RESOURCES;
714       }
715       //
716       // Allocate destination buffer, extra one page for adjustment
717       //
718       DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
719       if (DstBuffer == NULL) {
720         return EFI_OUT_OF_RESOURCES;
721       }
722       //
723       // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
724       // to make section data at page alignment.
725       //
726       DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
727       //
728       // Call decompress function
729       //
730       Status = UefiDecompress (
731                   CompressionSource,
732                   DstBuffer,
733                   ScratchBuffer
734                   );
735       if (EFI_ERROR (Status)) {
736         //
737         // Decompress failed
738         //
739         DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));
740         return EFI_NOT_FOUND;
741       }
742       break;
743     } else {
744       //
745       // PcdDxeIplSupportUefiDecompress is FALSE
746       // Don't support UEFI decompression algorithm.
747       //
748       ASSERT (FALSE);
749       return EFI_NOT_FOUND;
750     }
751 
752   case EFI_NOT_COMPRESSED:
753     //
754     // Allocate destination buffer
755     //
756     DstBufferSize = UncompressedLength;
757     DstBuffer     = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
758     if (DstBuffer == NULL) {
759       return EFI_OUT_OF_RESOURCES;
760     }
761     //
762     // Adjust DstBuffer offset, skip EFI section header
763     // to make section data at page alignment.
764     //
765     DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
766     //
767     // stream is not actually compressed, just encapsulated.  So just copy it.
768     //
769     CopyMem (DstBuffer, CompressionSource, DstBufferSize);
770     break;
771 
772   default:
773     //
774     // Don't support other unknown compression type.
775     //
776     ASSERT (FALSE);
777     return EFI_NOT_FOUND;
778   }
779 
780   *OutputSize = DstBufferSize;
781   *OutputBuffer = DstBuffer;
782 
783   return EFI_SUCCESS;
784 }
785 
786 
787 /**
788    Updates the Stack HOB passed to DXE phase.
789 
790    This function traverses the whole HOB list and update the stack HOB to
791    reflect the real stack that is used by DXE core.
792 
793    @param BaseAddress           The lower address of stack used by DxeCore.
794    @param Length                The length of stack used by DxeCore.
795 
796 **/
797 VOID
UpdateStackHob(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length)798 UpdateStackHob (
799   IN EFI_PHYSICAL_ADDRESS        BaseAddress,
800   IN UINT64                      Length
801   )
802 {
803   EFI_PEI_HOB_POINTERS           Hob;
804 
805   Hob.Raw = GetHobList ();
806   while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
807     if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) {
808       //
809       // Build a new memory allocation HOB with old stack info with EfiBootServicesData type. Need to
810       // avoid this region be reclaimed by DXE core as the IDT built in SEC might be on stack, and some
811       // PEIMs may also keep key information on stack
812       //
813       BuildMemoryAllocationHob (
814         Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress,
815         Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength,
816         EfiBootServicesData
817         );
818       //
819       // Update the BSP Stack Hob to reflect the new stack info.
820       //
821       Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress;
822       Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length;
823       break;
824     }
825     Hob.Raw = GET_NEXT_HOB (Hob);
826   }
827 }
828