Home | History | Annotate | Download | only in FspDxeIpl
      1 /** @file
      2 
      3   Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
      4   This program and the accompanying materials
      5   are licensed and made available under the terms and conditions of the BSD License
      6   which accompanies this distribution.  The full text of the license may be found at
      7   http://opensource.org/licenses/bsd-license.php.
      8 
      9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 **/
     13 
     14 #include "DxeIpl.h"
     15 
     16 
     17 //
     18 // Module Globals used in the DXE to PEI hand off
     19 // These must be module globals, so the stack can be switched
     20 //
     21 CONST EFI_DXE_IPL_PPI mDxeIplPpi = {
     22   DxeLoadCore
     23 };
     24 
     25 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
     26   CustomGuidedSectionExtract
     27 };
     28 
     29 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
     30   Decompress
     31 };
     32 
     33 CONST EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
     34   {
     35     EFI_PEI_PPI_DESCRIPTOR_PPI,
     36     &gEfiDxeIplPpiGuid,
     37     (VOID *) &mDxeIplPpi
     38   },
     39   {
     40     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     41     &gEfiPeiDecompressPpiGuid,
     42     (VOID *) &mDecompressPpi
     43   }
     44 };
     45 
     46 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = {
     47   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     48   &gEfiEndOfPeiSignalPpiGuid,
     49   NULL
     50 };
     51 
     52 /**
     53   Entry point of DXE IPL PEIM.
     54 
     55   This function installs DXE IPL PPI and Decompress PPI.  It also reloads
     56   itself to memory on non-S3 resume boot path.
     57 
     58   @param[in] FileHandle  Handle of the file being invoked.
     59   @param[in] PeiServices Describes the list of possible PEI Services.
     60 
     61   @retval EFI_SUCESS  The entry point of DXE IPL PEIM executes successfully.
     62   @retval Others      Some error occurs during the execution of this function.
     63 
     64 **/
     65 EFI_STATUS
     66 EFIAPI
     67 PeimInitializeDxeIpl (
     68   IN       EFI_PEI_FILE_HANDLE  FileHandle,
     69   IN CONST EFI_PEI_SERVICES     **PeiServices
     70   )
     71 {
     72   EFI_STATUS                                Status;
     73   EFI_GUID                                  *ExtractHandlerGuidTable;
     74   UINTN                                     ExtractHandlerNumber;
     75   EFI_PEI_PPI_DESCRIPTOR                    *GuidPpi;
     76 
     77   //
     78   // Get custom extract guided section method guid list
     79   //
     80   ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
     81 
     82   //
     83   // Install custom extraction guid PPI
     84   //
     85   if (ExtractHandlerNumber > 0) {
     86     GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));
     87     ASSERT (GuidPpi != NULL);
     88     while (ExtractHandlerNumber-- > 0) {
     89       GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
     90       GuidPpi->Ppi   = (VOID *) &mCustomGuidedSectionExtractionPpi;
     91       GuidPpi->Guid  = &ExtractHandlerGuidTable[ExtractHandlerNumber];
     92       Status = PeiServicesInstallPpi (GuidPpi++);
     93       ASSERT_EFI_ERROR(Status);
     94     }
     95   }
     96 
     97   //
     98   // Install DxeIpl and Decompress PPIs.
     99   //
    100   Status = PeiServicesInstallPpi (mPpiList);
    101   ASSERT_EFI_ERROR(Status);
    102 
    103   return Status;
    104 }
    105 
    106 /**
    107   The ExtractSection() function processes the input section and
    108   returns a pointer to the section contents. If the section being
    109   extracted does not require processing (if the section
    110   GuidedSectionHeader.Attributes has the
    111   EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
    112   OutputBuffer is just updated to point to the start of the
    113   section's contents. Otherwise, *Buffer must be allocated
    114   from PEI permanent memory.
    115 
    116   @param[in]  This                   Indicates the
    117                                      EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
    118                                      Buffer containing the input GUIDed section to be
    119                                      processed. OutputBuffer OutputBuffer is
    120                                      allocated from PEI permanent memory and contains
    121                                      the new section stream.
    122   @param[in]  InputSection           A pointer to the input buffer, which contains
    123                                      the input section to be processed.
    124   @param[out] OutputBuffer           A pointer to a caller-allocated buffer, whose
    125                                      size is specified by the contents of OutputSize.
    126   @param[out] OutputSize             A pointer to a caller-allocated
    127                                      UINTN in which the size of *OutputBuffer
    128                                      allocation is stored. If the function
    129                                      returns anything other than EFI_SUCCESS,
    130                                      the value of OutputSize is undefined.
    131   @param[out] AuthenticationStatus   A pointer to a caller-allocated
    132                                      UINT32 that indicates the
    133                                      authentication status of the
    134                                      output buffer. If the input
    135                                      section's GuidedSectionHeader.
    136                                      Attributes field has the
    137                                      EFI_GUIDED_SECTION_AUTH_STATUS_VALID
    138                                      bit as clear,
    139                                      AuthenticationStatus must return
    140                                      zero. These bits reflect the
    141                                      status of the extraction
    142                                      operation. If the function
    143                                      returns anything other than
    144                                      EFI_SUCCESS, the value of
    145                                      AuthenticationStatus is
    146                                      undefined.
    147 
    148   @retval EFI_SUCCESS           The InputSection was
    149                                 successfully processed and the
    150                                 section contents were returned.
    151 
    152   @retval EFI_OUT_OF_RESOURCES  The system has insufficient
    153                                 resources to process the request.
    154 
    155   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
    156                                 not match this instance of the
    157                                 GUIDed Section Extraction PPI.
    158 
    159 **/
    160 EFI_STATUS
    161 EFIAPI
    162 CustomGuidedSectionExtract (
    163   IN CONST  EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
    164   IN CONST  VOID                                  *InputSection,
    165   OUT       VOID                                  **OutputBuffer,
    166   OUT       UINTN                                 *OutputSize,
    167   OUT       UINT32                                *AuthenticationStatus
    168 )
    169 {
    170   EFI_STATUS      Status;
    171   UINT8           *ScratchBuffer;
    172   UINT32          ScratchBufferSize;
    173   UINT32          OutputBufferSize;
    174   UINT16          SectionAttribute;
    175 
    176   //
    177   // Init local variable
    178   //
    179   ScratchBuffer = NULL;
    180 
    181   //
    182   // Call GetInfo to get the size and attribute of input guided section data.
    183   //
    184   Status = ExtractGuidedSectionGetInfo (
    185              InputSection,
    186              &OutputBufferSize,
    187              &ScratchBufferSize,
    188              &SectionAttribute
    189              );
    190 
    191   if (EFI_ERROR (Status)) {
    192     DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
    193     return Status;
    194   }
    195 
    196   if (ScratchBufferSize != 0) {
    197     //
    198     // Allocate scratch buffer
    199     //
    200     ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
    201     if (ScratchBuffer == NULL) {
    202       return EFI_OUT_OF_RESOURCES;
    203     }
    204   }
    205 
    206   if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {
    207     //
    208     // Allocate output buffer
    209     //
    210     *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1);
    211     if (*OutputBuffer == NULL) {
    212       return EFI_OUT_OF_RESOURCES;
    213     }
    214     DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
    215     //
    216     // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
    217     // skip EFI section header to make section data at page alignment.
    218     //
    219     *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER));
    220   }
    221 
    222   Status = ExtractGuidedSectionDecode (
    223              InputSection,
    224              OutputBuffer,
    225              ScratchBuffer,
    226              AuthenticationStatus
    227              );
    228   if (EFI_ERROR (Status)) {
    229     //
    230     // Decode failed
    231     //
    232     DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
    233     return Status;
    234   }
    235 
    236   *OutputSize = (UINTN) OutputBufferSize;
    237 
    238   return EFI_SUCCESS;
    239 }
    240 
    241 
    242 
    243 /**
    244    Decompresses a section to the output buffer.
    245 
    246    This function looks up the compression type field in the input section and
    247    applies the appropriate compression algorithm to compress the section to a
    248    callee allocated buffer.
    249 
    250    @param[in]  This                  Points to this instance of the
    251                                      EFI_PEI_DECOMPRESS_PEI PPI.
    252    @param[in]  CompressionSection    Points to the compressed section.
    253    @param[out] OutputBuffer          Holds the returned pointer to the decompressed
    254                                      sections.
    255    @param[out] OutputSize            Holds the returned size of the decompress
    256                                      section streams.
    257 
    258    @retval EFI_SUCCESS           The section was decompressed successfully.
    259                                  OutputBuffer contains the resulting data and
    260                                  OutputSize contains the resulting size.
    261 
    262 **/
    263 EFI_STATUS
    264 EFIAPI
    265 Decompress (
    266   IN CONST  EFI_PEI_DECOMPRESS_PPI  *This,
    267   IN CONST  EFI_COMPRESSION_SECTION *CompressionSection,
    268   OUT       VOID                    **OutputBuffer,
    269   OUT       UINTN                   *OutputSize
    270  )
    271 {
    272   EFI_STATUS                      Status;
    273   UINT8                           *DstBuffer;
    274   UINT8                           *ScratchBuffer;
    275   UINT32                          DstBufferSize;
    276   UINT32                          ScratchBufferSize;
    277   VOID                            *CompressionSource;
    278   UINT32                          CompressionSourceSize;
    279   UINT32                          UncompressedLength;
    280   UINT8                           CompressionType;
    281 
    282   if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
    283     ASSERT (FALSE);
    284     return EFI_INVALID_PARAMETER;
    285   }
    286 
    287   if (IS_SECTION2 (CompressionSection)) {
    288     CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2));
    289     CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2));
    290     UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength;
    291     CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType;
    292   } else {
    293     CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION));
    294     CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION));
    295     UncompressedLength = CompressionSection->UncompressedLength;
    296     CompressionType = CompressionSection->CompressionType;
    297   }
    298 
    299   //
    300   // This is a compression set, expand it
    301   //
    302   switch (CompressionType) {
    303   case EFI_STANDARD_COMPRESSION:
    304     //
    305     // Load EFI standard compression.
    306     // For compressed data, decompress them to destination buffer.
    307     //
    308     Status = UefiDecompressGetInfo (
    309                CompressionSource,
    310                CompressionSourceSize,
    311                &DstBufferSize,
    312                &ScratchBufferSize
    313                );
    314     if (EFI_ERROR (Status)) {
    315       //
    316       // GetInfo failed
    317       //
    318       DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));
    319       return EFI_NOT_FOUND;
    320     }
    321     //
    322     // Allocate scratch buffer
    323     //
    324     ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
    325     if (ScratchBuffer == NULL) {
    326       return EFI_OUT_OF_RESOURCES;
    327     }
    328     //
    329     // Allocate destination buffer, extra one page for adjustment
    330     //
    331     DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
    332     if (DstBuffer == NULL) {
    333       return EFI_OUT_OF_RESOURCES;
    334     }
    335     //
    336     // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
    337     // to make section data at page alignment.
    338     //
    339     DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
    340     //
    341     // Call decompress function
    342     //
    343     Status = UefiDecompress (
    344                 CompressionSource,
    345                 DstBuffer,
    346                 ScratchBuffer
    347                 );
    348     if (EFI_ERROR (Status)) {
    349       //
    350       // Decompress failed
    351       //
    352       DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));
    353       return EFI_NOT_FOUND;
    354     }
    355     break;
    356 
    357   case EFI_NOT_COMPRESSED:
    358     //
    359     // Allocate destination buffer
    360     //
    361     DstBufferSize = UncompressedLength;
    362     DstBuffer     = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
    363     if (DstBuffer == NULL) {
    364       return EFI_OUT_OF_RESOURCES;
    365     }
    366     //
    367     // Adjust DstBuffer offset, skip EFI section header
    368     // to make section data at page alignment.
    369     //
    370     DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
    371     //
    372     // stream is not actually compressed, just encapsulated.  So just copy it.
    373     //
    374     CopyMem (DstBuffer, CompressionSource, DstBufferSize);
    375     break;
    376 
    377   default:
    378     //
    379     // Don't support other unknown compression type.
    380     //
    381     ASSERT (FALSE);
    382     return EFI_NOT_FOUND;
    383   }
    384 
    385   *OutputSize = DstBufferSize;
    386   *OutputBuffer = DstBuffer;
    387 
    388   return EFI_SUCCESS;
    389 }
    390 
    391 /**
    392    Main entry point to last PEIM.
    393 
    394    This function finds DXE Core in the firmware volume and transfer the control to
    395    DXE core.
    396 
    397    @param[in] This          Entry point for DXE IPL PPI.
    398    @param[in] PeiServices   General purpose services available to every PEIM.
    399    @param[in] HobList       Address to the Pei HOB list.
    400 
    401    @return EFI_SUCCESS              DXE core was successfully loaded.
    402    @return EFI_OUT_OF_RESOURCES     There are not enough resources to load DXE core.
    403 
    404 **/
    405 EFI_STATUS
    406 EFIAPI
    407 DxeLoadCore (
    408   IN CONST EFI_DXE_IPL_PPI *This,
    409   IN EFI_PEI_SERVICES      **PeiServices,
    410   IN EFI_PEI_HOB_POINTERS  HobList
    411   )
    412 {
    413   EFI_STATUS   Status;
    414 
    415   DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP HOB is located at 0x%08X\n", HobList));
    416 
    417   //
    418   // End of PEI phase signal
    419   //
    420   Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
    421   ASSERT_EFI_ERROR (Status);
    422 
    423   //
    424   // Give control back to BootLoader after FspInit
    425   //
    426   DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP is waiting for NOTIFY\n"));
    427   FspInitDone ();
    428 
    429   //
    430   // BootLoader called FSP again through NotifyPhase
    431   //
    432   FspWaitForNotify ();
    433 
    434 
    435   //
    436   // Give control back to the boot loader framework caller
    437   //
    438   DEBUG ((DEBUG_INFO | DEBUG_INIT,   "============= PEIM FSP is Completed =============\n\n"));
    439 
    440   SetFspApiReturnStatus(EFI_SUCCESS);
    441 
    442   SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_RDYBOOT_EXIT);
    443 
    444   Pei2LoaderSwitchStack();
    445 
    446   //
    447   // Should not come here
    448   //
    449   while (TRUE) {
    450     DEBUG ((DEBUG_ERROR, "No FSP API should be called after FSP is DONE!\n"));
    451     SetFspApiReturnStatus(EFI_UNSUPPORTED);
    452     Pei2LoaderSwitchStack();
    453   }
    454 
    455   return EFI_SUCCESS;
    456 }
    457