]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Pei/Image/Image.c
Merge branch of PI tree to main trunk
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
index 202936869b62eb4b2f9417f4b5dc6562d76f934c..ebe79a6c50a05fd7ee013f4eacd6720bd910945a 100644 (file)
@@ -21,13 +21,33 @@ Abstract:
 \r
 #include <PeiMain.h>\r
 \r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
 \r
+Arguments:\r
+\r
+  FileHandle - The handle to the PE/COFF file\r
+  FileOffset - The offset, in bytes, into the file to read\r
+  ReadSize   - The number of bytes to read from the file starting at FileOffset\r
+  Buffer     - A pointer to the buffer to read the data into.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+--*/  \r
 \r
 EFI_STATUS\r
-PeiLoadImage (\r
-  IN EFI_PEI_SERVICES         **PeiServices,\r
-  IN EFI_FFS_FILE_HEADER      *PeimFileHeader,\r
-  OUT VOID                    **EntryPoint\r
+PeiLoadImageLoadImage (\r
+  IN     EFI_PEI_SERVICES             **PeiServices,\r
+  IN     EFI_PEI_FILE_HANDLE          FileHandle,\r
+  OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL\r
+  OUT    UINT64                       *ImageSizeArg,     OPTIONAL\r
+  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,\r
+  OUT    UINT32                       *AuthenticationState\r
   )\r
 /*++\r
 \r
@@ -37,9 +57,247 @@ Routine Description:
 \r
 Arguments:\r
 \r
-  PeiServices     - The PEI core services table.\r
-  PeimFileHeader  - Pointer to the FFS file header of the image.\r
-  EntryPoint      - Pointer to entry point of specified image file for output.\r
+  PeiServices          - The PEI core services table.\r
+  FileHandle           - Pointer to the FFS file header of the image.\r
+  ImageAddressArg      - Pointer to PE/TE image.\r
+  ImageSizeArg         - Size of PE/TE image.\r
+  EntryPoint           - Pointer to entry point of specified image file for output.\r
+  AuthenticationState  - Pointer to attestation authentication state of image.\r
+\r
+Returns:\r
+\r
+  Status - EFI_SUCCESS    - Image is successfully loaded.\r
+           EFI_NOT_FOUND  - Fail to locate necessary PPI\r
+           Others         - Fail to load file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PeiLoadImageLoadImageWrapper (\r
+  IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,\r
+  IN     EFI_PEI_FILE_HANDLE          FileHandle,\r
+  OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL\r
+  OUT    UINT64                       *ImageSizeArg,     OPTIONAL\r
+  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,\r
+  OUT    UINT32                       *AuthenticationState\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The wrapper function of PeiLoadImageLoadImage().\r
+\r
+Arguments:\r
+\r
+  This                 - Pointer to EFI_PEI_LOAD_FILE_PPI.\r
+  PeiServices          - The PEI core services table.\r
+  FileHandle           - Pointer to the FFS file header of the image.\r
+  ImageAddressArg      - Pointer to PE/TE image.\r
+  ImageSizeArg         - Size of PE/TE image.\r
+  EntryPoint           - Pointer to entry point of specified image file for output.\r
+  AuthenticationState  - Pointer to attestation authentication state of image.\r
+\r
+Returns:\r
+\r
+  EFI_STATUS.\r
+  \r
+--*/ \r
+;\r
+\r
+STATIC EFI_PEI_LOAD_FILE_PPI   mPeiLoadImagePpi = {\r
+  PeiLoadImageLoadImageWrapper\r
+};\r
+\r
+\r
+STATIC EFI_PEI_PPI_DESCRIPTOR     gPpiLoadFilePpiList = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEfiPeiLoadFilePpiGuid,\r
+  &mPeiLoadImagePpi\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PeiImageRead (\r
+  IN     VOID    *FileHandle,\r
+  IN     UINTN   FileOffset,\r
+  IN OUT UINTN   *ReadSize,\r
+  OUT    VOID    *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
+\r
+Arguments:\r
+\r
+  FileHandle - The handle to the PE/COFF file\r
+  FileOffset - The offset, in bytes, into the file to read\r
+  ReadSize   - The number of bytes to read from the file starting at FileOffset\r
+  Buffer     - A pointer to the buffer to read the data into.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+--*/\r
+{\r
+  CHAR8 *Destination8;\r
+  CHAR8 *Source8;\r
+  UINTN Length;\r
+\r
+  Destination8  = Buffer;\r
+  Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
+  Length        = *ReadSize;\r
+  while (Length--) {\r
+    *(Destination8++) = *(Source8++);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetImageReadFunction (\r
+  IN      PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Support routine to return the Image Read\r
+\r
+Arguments:\r
+\r
+  PeiServices   - PEI Services Table\r
+\r
+  ImageContext  - The context of the image being loaded\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - If Image function location is found\r
+\r
+--*/\r
+{\r
+  VOID*  MemoryBuffer;\r
+\r
+  MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1);\r
+  ASSERT (MemoryBuffer != NULL);\r
+\r
+  CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageRead, 0x400);\r
+\r
+  ImageContext->ImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+LoadAndRelocatePeCoffImage (\r
+  IN  EFI_PEI_PE_COFF_LOADER_PROTOCOL           *PeiEfiPeiPeCoffLoader,\r
+  IN  VOID                                      *Pe32Data,\r
+  OUT EFI_PHYSICAL_ADDRESS                      *ImageAddress,\r
+  OUT UINT64                                    *ImageSize,\r
+  OUT EFI_PHYSICAL_ADDRESS                      *EntryPoint\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Loads and relocates a PE/COFF image into memory.\r
+\r
+Arguments:\r
+\r
+  PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
+\r
+  Pe32Data         - The base address of the PE/COFF file that is to be loaded and relocated\r
+\r
+  ImageAddress     - The base address of the relocated PE/COFF image\r
+\r
+  ImageSize        - The size of the relocated PE/COFF image\r
+\r
+  EntryPoint       - The entry point of the relocated PE/COFF image\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS   - The file was loaded and relocated\r
+\r
+  EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                            Status;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
+\r
+  ASSERT (PeiEfiPeiPeCoffLoader != NULL);\r
+\r
+  ZeroMem (&ImageContext, sizeof (ImageContext));\r
+  ImageContext.Handle = Pe32Data;\r
+  Status              = GetImageReadFunction (&ImageContext);\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Allocate Memory for the image\r
+  //\r
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+  ASSERT (ImageContext.ImageAddress != 0);\r
+\r
+  //\r
+  // Load the image to our new buffer\r
+  //\r
+  Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Relocate the image in our new buffer\r
+  //\r
+  Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Flush the instruction cache so the image data is written before we execute it\r
+  //\r
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
+\r
+  *ImageAddress = ImageContext.ImageAddress;\r
+  *ImageSize    = ImageContext.ImageSize;\r
+  *EntryPoint   = ImageContext.EntryPoint;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PeiLoadImageLoadImage (\r
+  IN     EFI_PEI_SERVICES             **PeiServices,\r
+  IN     EFI_PEI_FILE_HANDLE          FileHandle,\r
+  OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL\r
+  OUT    UINT64                       *ImageSizeArg,     OPTIONAL\r
+  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,\r
+  OUT    UINT32                       *AuthenticationState\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Routine for loading file image.\r
+\r
+Arguments:\r
+\r
+  PeiServices          - The PEI core services table.\r
+  FileHandle           - Pointer to the FFS file header of the image.\r
+  ImageAddressArg      - Pointer to PE/TE image.\r
+  ImageSizeArg         - Size of PE/TE image.\r
+  EntryPoint           - Pointer to entry point of specified image file for output.\r
+  AuthenticationState  - Pointer to attestation authentication state of image.\r
 \r
 Returns:\r
 \r
@@ -51,55 +309,63 @@ Returns:
 {\r
   EFI_STATUS                  Status;\r
   VOID                        *Pe32Data;\r
-  EFI_PEI_FV_FILE_LOADER_PPI  *FvLoadFilePpi;\r
   EFI_PHYSICAL_ADDRESS        ImageAddress;\r
   UINT64                      ImageSize;\r
   EFI_PHYSICAL_ADDRESS        ImageEntryPoint;\r
   EFI_TE_IMAGE_HEADER         *TEImageHeader;\r
   UINT16                      Machine;\r
+  PEI_CORE_INSTANCE           *Private;\r
+  VOID                        *EntryPointArg;\r
 \r
-  *EntryPoint   = NULL;\r
+  *EntryPoint   = 0;\r
   TEImageHeader = NULL;\r
+  ImageSize = 0;\r
+  *AuthenticationState = 0;\r
 \r
   //\r
-  // Try to find a PE32 section.\r
+  // Try to find a TE section.\r
   //\r
   Status = PeiServicesFfsFindSectionData (\r
-             EFI_SECTION_PE32,\r
-             PeimFileHeader,\r
+             EFI_SECTION_TE,\r
+             FileHandle,\r
              &Pe32Data\r
              );\r
+  if (!EFI_ERROR (Status)) {\r
+     TEImageHeader = (EFI_TE_IMAGE_HEADER *)Pe32Data;\r
+  }\r
   //\r
   // If we didn't find a PE32 section, try to find a TE section.\r
   //\r
   if (EFI_ERROR (Status)) {\r
     Status = PeiServicesFfsFindSectionData (\r
-               EFI_SECTION_TE,\r
-               PeimFileHeader,\r
-               (VOID **) &TEImageHeader\r
+               EFI_SECTION_PE32,\r
+               FileHandle,\r
+               &Pe32Data\r
                );\r
-    if (EFI_ERROR (Status) || TEImageHeader == NULL) {\r
+    if (EFI_ERROR (Status)) {\r
       //\r
-      // There was not a PE32 or a TE section, so assume that it's a Compressed section\r
-      // and use the LoadFile\r
+      // PEI core only carry the loader function fro TE and PE32 executables\r
+      // If this two section does not exist, just return.\r
       //\r
-      Status = PeiServicesLocatePpi (\r
-                &gEfiPeiFvFileLoaderPpiGuid,\r
-                0,\r
-                NULL,\r
-                (VOID **)&FvLoadFilePpi\r
-                );\r
-      if (EFI_ERROR (Status)) {\r
-        return EFI_NOT_FOUND;\r
-      }\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
 \r
-      Status = FvLoadFilePpi->FvLoadFile (\r
-                                FvLoadFilePpi,\r
-                                PeimFileHeader,\r
-                                &ImageAddress,\r
-                                &ImageSize,\r
-                                &ImageEntryPoint\r
-                                );\r
+  if (Private->PeiMemoryInstalled && \r
+      (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
+    {\r
+      //\r
+      // If memory is installed, perform the shadow operations\r
+      //\r
+      Status = LoadAndRelocatePeCoffImage (\r
+        Private->PeCoffLoader,\r
+        Pe32Data,\r
+        &ImageAddress,\r
+        &ImageSize,\r
+        &ImageEntryPoint\r
+      );\r
 \r
       if (EFI_ERROR (Status)) {\r
         return EFI_NOT_FOUND;\r
@@ -109,23 +375,28 @@ Returns:
       // Got the entry point from ImageEntryPoint and ImageStartAddress\r
       //\r
       Pe32Data    = (VOID *) ((UINTN) ImageAddress);\r
-      *EntryPoint = (VOID *) ((UINTN) ImageEntryPoint);\r
-    } else {\r
+      *EntryPoint = ImageEntryPoint;\r
+    }\r
+  } else {\r
+   if (TEImageHeader != NULL) {\r
       //\r
       // Retrieve the entry point from the TE image header\r
       //\r
       ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) TEImageHeader;\r
-      *EntryPoint  = (VOID *)((UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) +\r
+      ImageSize = 0;\r
+      *EntryPoint  = (EFI_PHYSICAL_ADDRESS)((UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) +\r
                     TEImageHeader->AddressOfEntryPoint - TEImageHeader->StrippedSize);\r
-    }\r
-  } else {\r
-    //\r
-    // Retrieve the entry point from the PE/COFF image header\r
-    //\r
-    ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data;\r
-    Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_NOT_FOUND;\r
+    } else {\r
+      //\r
+      // Retrieve the entry point from the PE/COFF image header\r
+      //\r
+      ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data;\r
+      ImageSize = 0;\r
+      Status = PeCoffLoaderGetEntryPoint (Pe32Data, &EntryPointArg);\r
+      *EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) EntryPointArg;\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
     }\r
   }\r
 \r
@@ -140,6 +411,14 @@ Returns:
     return EFI_UNSUPPORTED;  \r
   }\r
 \r
+  if (ImageAddressArg != NULL) {\r
+    *ImageAddressArg = ImageAddress;\r
+  }\r
+\r
+  if (ImageSizeArg != NULL) {\r
+    *ImageSizeArg = ImageSize;\r
+  }\r
+  \r
   //\r
   // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi\r
   //\r
@@ -264,4 +543,175 @@ Returns:
   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));\r
 \r
   return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+PeiLoadImageLoadImageWrapper (\r
+  IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,\r
+  IN     EFI_PEI_FILE_HANDLE          FileHandle,\r
+  OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL\r
+  OUT    UINT64                       *ImageSizeArg,     OPTIONAL\r
+  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,\r
+  OUT    UINT32                       *AuthenticationState\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The wrapper function of PeiLoadImageLoadImage().\r
+\r
+Arguments:\r
+\r
+  This                 - Pointer to EFI_PEI_LOAD_FILE_PPI.\r
+  PeiServices          - The PEI core services table.\r
+  FileHandle           - Pointer to the FFS file header of the image.\r
+  ImageAddressArg      - Pointer to PE/TE image.\r
+  ImageSizeArg         - Size of PE/TE image.\r
+  EntryPoint           - Pointer to entry point of specified image file for output.\r
+  AuthenticationState  - Pointer to attestation authentication state of image.\r
+\r
+Returns:\r
+\r
+  EFI_STATUS.\r
+  \r
+--*/      \r
+{\r
+  return PeiLoadImageLoadImage (\r
+           GetPeiServicesTablePointer (),\r
+           FileHandle,\r
+           ImageAddressArg,\r
+           ImageSizeArg,\r
+           EntryPoint,\r
+           AuthenticationState\r
+           );\r
 }\r
+\r
+EFI_STATUS\r
+PeiLoadImage (\r
+  IN     EFI_PEI_SERVICES             **PeiServices,\r
+  IN     EFI_PEI_FILE_HANDLE          FileHandle,\r
+  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,\r
+  OUT    UINT32                       *AuthenticationState\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Routine for load image file.\r
+\r
+Arguments:\r
+\r
+  PeiServices          - The PEI core services table.\r
+  FileHandle           - Pointer to the FFS file header of the image.\r
+  EntryPoint           - Pointer to entry point of specified image file for output.\r
+  AuthenticationState  - Pointer to attestation authentication state of image.\r
+\r
+Returns:\r
+\r
+  Status - EFI_SUCCESS    - Image is successfully loaded.\r
+           EFI_NOT_FOUND  - Fail to locate necessary PPI\r
+           Others         - Fail to load file.\r
+  \r
+--*/    \r
+{\r
+  EFI_STATUS              PpiStatus;\r
+  EFI_STATUS              Status;\r
+  UINTN                   Index;\r
+  EFI_PEI_LOAD_FILE_PPI   *LoadFile;\r
+  EFI_PHYSICAL_ADDRESS    ImageAddress;\r
+  UINT64                  ImageSize;\r
+\r
+  //\r
+  // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.\r
+  // one at a time, until one reports EFI_SUCCESS.\r
+  //\r
+  Index = 0;\r
+  do {\r
+    PpiStatus = PeiServicesLocatePpi (\r
+                  &gEfiPeiLoadFilePpiGuid,\r
+                  Index,\r
+                  NULL,\r
+                  (VOID **)&LoadFile\r
+                  );\r
+    if (!EFI_ERROR (PpiStatus)) {\r
+      Status = LoadFile->LoadFile (\r
+                          LoadFile, \r
+                          FileHandle, \r
+                          &ImageAddress, \r
+                          &ImageSize,\r
+                          EntryPoint,\r
+                          AuthenticationState\r
+                          );\r
+      if (!EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+    Index++;\r
+  } while (!EFI_ERROR (PpiStatus));\r
+\r
+  //\r
+  // If no instances reports EFI_SUCCESS, then build-in support for\r
+  // the PE32+/TE XIP image format is used.\r
+  //\r
+  Status = PeiLoadImageLoadImage (\r
+            PeiServices, \r
+            FileHandle, \r
+            NULL, \r
+            NULL, \r
+            EntryPoint, \r
+            AuthenticationState\r
+            );\r
+  return Status;\r
+}\r
+\r
+\r
+VOID\r
+InitializeImageServices (\r
+  IN  PEI_CORE_INSTANCE   *PrivateData,\r
+  IN  PEI_CORE_INSTANCE   *OldCoreData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Regitser PeCoffLoader to PeiCore PrivateData. And install\r
+  Pei Load File PPI.\r
+\r
+Arguments:\r
+\r
+  PrivateData    - Pointer to PEI_CORE_INSTANCE.\r
+  OldCoreData    - Pointer to PEI_CORE_INSTANCE.\r
+\r
+Returns:\r
+\r
+  NONE.\r
+  \r
+--*/      \r
+{\r
+  //\r
+  // Always update PeCoffLoader pointer as PEI core itself may get \r
+  // shadowed into memory\r
+  //\r
+  PrivateData->PeCoffLoader = GetPeCoffLoaderProtocol ();\r
+  \r
+  if (OldCoreData == NULL) {\r
+    //\r
+    // The first time we are XIP (running from FLASH). We need to remember the\r
+    // FLASH address so we can reinstall the memory version that runs faster\r
+    //\r
+    PrivateData->XipLoadFile = &gPpiLoadFilePpiList;\r
+    PeiServicesInstallPpi (PrivateData->XipLoadFile);\r
+  } else {\r
+    //\r
+    // 2nd time we are running from memory so replace the XIP version with the \r
+    // new memory version. \r
+    //\r
+    PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList); \r
+  }\r
+}\r
+\r
+\r
+\r