]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
OVMF: Align PE images in ROM, and strip relocations were possible.
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
index a534f52236b035741a8b5fc4b4215655d5a8705b..eeabbb24bc301abf962f4c9b9520abdf2c98604d 100644 (file)
@@ -2,7 +2,8 @@
   Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but\r
   only supports relocating IA32, x64, IPF, and EBC images.\r
 \r
-  Copyright (c) 2006 - 2008, Intel Corporation\r
+  Copyright (c) 2006 - 2008, Intel Corporation<BR>\r
+  Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>\r
   All rights reserved. This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -35,7 +36,7 @@ PeCoffLoaderGetPeHeaderMagicValue (
   //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
   //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
   //\r
-  if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+  if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
     return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
   }\r
   //\r
@@ -67,7 +68,7 @@ PeCoffLoaderGetPeHeader (
   UINT16                Magic;\r
 \r
   //\r
-  // Read the DOS image header to check for it's existance\r
+  // Read the DOS image header to check for its existence\r
   //\r
   Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
   Status = ImageContext->ImageRead (\r
@@ -92,8 +93,8 @@ PeCoffLoaderGetPeHeader (
 \r
   //\r
   // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much\r
-  // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic\r
-  // determins if this is a PE32 or PE32+ image. The magic is in the same\r
+  // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic\r
+  // determines if this is a PE32 or PE32+ image. The magic is in the same\r
   // location in both images.\r
   //\r
   Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
@@ -158,7 +159,7 @@ PeCoffLoaderGetPeHeader (
   if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
     //\r
     // If the PE/COFF loader does not support the image type return\r
-    // unsupported. This library can suport lots of types of images\r
+    // unsupported. This library can support lots of types of images\r
     // this does not mean the user of this library can call the entry\r
     // point of the image.\r
     //\r
@@ -254,10 +255,11 @@ PeCoffLoaderGetImageInfo (
   ImageContext->DestinationAddress = 0;\r
 \r
   //\r
-  // Initialize the codeview pointer.\r
+  // Initialize the debug codeview pointer.\r
   //\r
-  ImageContext->CodeView    = NULL;\r
-  ImageContext->PdbPointer  = NULL;\r
+  ImageContext->DebugDirectoryEntryRva = 0;\r
+  ImageContext->CodeView               = NULL;\r
+  ImageContext->PdbPointer             = NULL;\r
 \r
   //\r
   // Three cases with regards to relocations:\r
@@ -411,7 +413,7 @@ PeCoffLoaderGetImageInfo (
       // In Te image header there is not a field to describe the ImageSize.\r
       // Actually, the ImageSize equals the RVA plus the VirtualSize of\r
       // the last section mapped into memory (Must be rounded up to\r
-      // a mulitple of Section Alignment). Per the PE/COFF specification, the\r
+      // a multiple of Section Alignment). Per the PE/COFF specification, the\r
       // section headers in the Section Table must appear in order of the RVA\r
       // values for the corresponding sections. So the ImageSize can be determined\r
       // by the RVA and the VirtualSize of the last section header in the\r
@@ -457,7 +459,7 @@ PeCoffLoaderGetImageInfo (
   Converts an image address to the loaded address.\r
 \r
   @param  ImageContext  The context of the image being loaded.\r
-  @param  Address       The address to be converted to the loaded address.\r
+  @param  Address       The relative virtual address to be converted to the loaded address.\r
 \r
   @return The converted address or NULL if the address can not be converted.\r
 \r
@@ -469,8 +471,7 @@ PeCoffLoaderImageAddress (
   )\r
 {\r
   //\r
-  // @bug Check to make sure ImageSize is correct for the relocated image.\r
-  //      it may only work for the file we start with and not the relocated image\r
+  // Make sure that Address and ImageSize is correct for the loaded image.\r
   //\r
   if (Address >= ImageContext->ImageSize) {\r
     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
@@ -495,6 +496,10 @@ PeCoffLoaderImageAddress (
     \r
   If ImageContext is NULL, then ASSERT().\r
 \r
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
+  prior to transferring control to a PE/COFF image that is loaded using this library.\r
+\r
   @param  ImageContext        Pointer to the image context structure that describes the PE/COFF\r
                               image that is being relocated.\r
 \r
@@ -541,6 +546,9 @@ PeCoffLoaderRelocateImage (
   // If there are no relocation entries, then we are done\r
   //\r
   if (ImageContext->RelocationsStripped) {\r
+    // Applies additional environment specific actions to relocate fixups \r
+    // to a PE/COFF image if needed\r
+    PeCoffLoaderRelocateImageExtraAction (ImageContext);  \r
     return RETURN_SUCCESS;\r
   }\r
 \r
@@ -586,19 +594,20 @@ PeCoffLoaderRelocateImage (
     // the optional header to verify a desired directory entry is there.\r
     //\r
 \r
-    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
+    if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) && (RelocDir->Size > 0)) {\r
       RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
-      ASSERT(RelocBase != NULL);\r
       RelocBaseEnd = PeCoffLoaderImageAddress (\r
                       ImageContext,\r
                       RelocDir->VirtualAddress + RelocDir->Size - 1\r
                       );\r
-      ASSERT(RelocBaseEnd !=NULL);\r
+      if (RelocBase == NULL || RelocBaseEnd == NULL) {\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
     } else {\r
       //\r
       // Set base and end to bypass processing below.\r
       //\r
-      RelocBase = RelocBaseEnd = 0;\r
+      RelocBase = RelocBaseEnd = NULL;\r
     }\r
   } else {\r
     Hdr.Te             = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
@@ -609,13 +618,20 @@ PeCoffLoaderRelocateImage (
     // Find the relocation block\r
     //\r
     RelocDir = &Hdr.Te->DataDirectory[0];\r
-    RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
-                                    ImageContext->ImageAddress +\r
-                                    RelocDir->VirtualAddress +\r
-                                    sizeof(EFI_TE_IMAGE_HEADER) -\r
-                                    Hdr.Te->StrippedSize\r
-                                    );\r
-    RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
+    if (RelocDir->Size > 0) {\r
+      RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
+                                      ImageContext->ImageAddress +\r
+                                      RelocDir->VirtualAddress +\r
+                                      sizeof(EFI_TE_IMAGE_HEADER) -\r
+                                      Hdr.Te->StrippedSize\r
+                                      );\r
+      RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
+    } else {\r
+      //\r
+      // Set base and end to bypass processing below.\r
+      //\r
+      RelocBase = RelocBaseEnd = NULL;    \r
+    }\r
   }\r
 \r
   //\r
@@ -626,23 +642,28 @@ PeCoffLoaderRelocateImage (
 \r
     Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
     RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
+    \r
+    //\r
+    // Make sure RelocEnd is in the Image range.\r
+    //\r
+    if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN) ImageContext->ImageAddress) ||\r
+        (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + (UINTN)ImageContext->ImageSize)) {\r
+      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+      return RETURN_LOAD_ERROR;\r
+    }\r
+\r
     if (!(ImageContext->IsTeImage)) {\r
       FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
-      ASSERT(FixupBase != NULL);\r
+      if (FixupBase == NULL) {\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
     } else {\r
       FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
                     RelocBase->VirtualAddress +\r
                     sizeof(EFI_TE_IMAGE_HEADER) -\r
                     Hdr.Te->StrippedSize\r
                     );\r
-    }\r
-\r
-    if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
-        (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +\r
-          (UINTN)ImageContext->ImageSize)) {\r
-      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
-      return RETURN_LOAD_ERROR;\r
-    }\r
+    }    \r
 \r
     //\r
     // Run this relocation record\r
@@ -695,8 +716,8 @@ PeCoffLoaderRelocateImage (
       default:\r
         //\r
         // The common code does not handle some of the stranger IPF relocations\r
-        // PeCoffLoaderRelocateImageEx () addes support for these complex fixups\r
-        // on IPF and is a No-Op on other archtiectures.\r
+        // PeCoffLoaderRelocateImageEx () adds support for these complex fixups\r
+        // on IPF and is a No-Op on other architectures.\r
         //\r
         Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
         if (RETURN_ERROR (Status)) {\r
@@ -724,6 +745,11 @@ PeCoffLoaderRelocateImage (
      ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;\r
      ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;\r
   }\r
+  \r
+  // Applies additional environment specific actions to relocate fixups \r
+  // to a PE/COFF image if needed\r
+  PeCoffLoaderRelocateImageExtraAction (ImageContext);\r
+  \r
   return RETURN_SUCCESS;\r
 }\r
 \r
@@ -733,13 +759,17 @@ PeCoffLoaderRelocateImage (
   Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer\r
   specified by the ImageAddress and ImageSize fields of ImageContext.  The caller must allocate\r
   the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.\r
-  The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.\r
+  The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.\r
   The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage,  Machine, ImageType, ImageAddress, ImageSize, \r
   DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva \r
   fields of the ImageContext structure must be valid prior to invoking this service.\r
   \r
   If ImageContext is NULL, then ASSERT().\r
 \r
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
+  prior to transferring control to a PE/COFF image that is loaded using this library.\r
+\r
   @param  ImageContext              Pointer to the image context structure that describes the PE/COFF\r
                                     image that is being loaded.\r
 \r
@@ -776,6 +806,11 @@ PeCoffLoaderLoadImage (
   UINT32                                TempDebugEntryRva;\r
   UINT32                                NumberOfRvaAndSizes;\r
   UINT16                                Magic;\r
+  EFI_IMAGE_RESOURCE_DIRECTORY          *ResourceDirectory;\r
+  EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY    *ResourceDirectoryEntry;\r
+  EFI_IMAGE_RESOURCE_DIRECTORY_STRING   *ResourceDirectoryString;\r
+  EFI_IMAGE_RESOURCE_DATA_ENTRY         *ResourceDataEntry;\r
+\r
 \r
   ASSERT (ImageContext != NULL);\r
 \r
@@ -890,6 +925,13 @@ PeCoffLoaderLoadImage (
   //\r
   Section = FirstSection;\r
   for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
+    //\r
+    // Read the section\r
+    //\r
+    Size = (UINTN) Section->Misc.VirtualSize;\r
+    if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
+      Size = (UINTN) Section->SizeOfRawData;\r
+    }\r
 \r
     //\r
     // Compute sections address\r
@@ -899,28 +941,22 @@ PeCoffLoaderLoadImage (
             ImageContext,\r
             Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
             );\r
-    if (ImageContext->IsTeImage) {\r
-      Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
-      End  = (CHAR8 *)((UINTN) End +  sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
-    }\r
 \r
-    if (End > MaxEnd) {\r
-      MaxEnd = End;\r
-    }\r
     //\r
-    // If the base start or end address resolved to 0, then fail.\r
+    // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.\r
     //\r
-    if ((Base == NULL) || (End == NULL)) {\r
+    if ((Size > 0) && ((Base == NULL) || (End == NULL))) {\r
       ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
       return RETURN_LOAD_ERROR;\r
     }\r
 \r
-    //\r
-    // Read the section\r
-    //\r
-    Size = (UINTN) Section->Misc.VirtualSize;\r
-    if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
-      Size = (UINTN) Section->SizeOfRawData;\r
+    if (ImageContext->IsTeImage) {\r
+      Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
+      End  = (CHAR8 *)((UINTN) End +  sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
+    }\r
+\r
+    if (End > MaxEnd) {\r
+      MaxEnd = End;\r
     }\r
 \r
     if (Section->SizeOfRawData > 0) {\r
@@ -947,7 +983,7 @@ PeCoffLoaderLoadImage (
     }\r
 \r
     //\r
-    // If raw size is less then virt size, zero fill the remaining\r
+    // If raw size is less then virtual size, zero fill the remaining\r
     //\r
 \r
     if (Size < Section->Misc.VirtualSize) {\r
@@ -1117,6 +1153,10 @@ PeCoffLoaderLoadImage (
           ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
           break;\r
 \r
+        case CODEVIEW_SIGNATURE_MTOC:\r
+          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);\r
+          break;\r
+\r
         default:\r
           break;\r
         }\r
@@ -1124,6 +1164,72 @@ PeCoffLoaderLoadImage (
     }\r
   }\r
 \r
+  //\r
+  // Get Image's HII resource section\r
+  //\r
+  ImageContext->HiiResourceData = 0;\r
+  if (!(ImageContext->IsTeImage)) {\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
+    } else {\r
+      //\r
+      // Use PE32+ offset\r
+      //\r
+      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];\r
+    }\r
+\r
+    if (DirectoryEntry->Size != 0) {\r
+      Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress);\r
+      if (Base != NULL) {\r
+        ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;\r
+        ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
+\r
+        for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {\r
+          if (ResourceDirectoryEntry->u1.s.NameIsString) {\r
+            ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);\r
+\r
+            if (ResourceDirectoryString->Length == 3 &&\r
+                ResourceDirectoryString->String[0] == L'H' &&\r
+                ResourceDirectoryString->String[1] == L'I' &&\r
+                ResourceDirectoryString->String[2] == L'I') {\r
+              //\r
+              // Resource Type "HII" found\r
+              //\r
+              if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+                //\r
+                // Move to next level - resource Name\r
+                //\r
+                ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
+                ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
+\r
+                if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+                  //\r
+                  // Move to next level - resource Language\r
+                  //\r
+                  ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
+                  ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);\r
+                }\r
+              }\r
+\r
+              //\r
+              // Now it ought to be resource Data\r
+              //\r
+              if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+                ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);\r
+                ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData);\r
+                break;\r
+              }\r
+            }\r
+          }\r
+          ResourceDirectoryEntry++;\r
+        }\r
+      }\r
+    }\r
+  }\r
\r
   return Status;\r
 }\r
 \r
@@ -1132,9 +1238,15 @@ PeCoffLoaderLoadImage (
   Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI\r
   runtime. \r
   \r
-  PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply\r
-  the fixups with a virtual mapping.\r
+  This function reapplies relocation fixups to the PE/COFF image specified by ImageBase \r
+  and ImageSize so the image will execute correctly when the PE/COFF image is mapped \r
+  to the address specified by VirtualImageBase.  RelocationData must be identical \r
+  to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure \r
+  after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().\r
 \r
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
+  prior to transferring control to a PE/COFF image that is loaded using this library.\r
 \r
   @param  ImageBase          Base address of a PE/COFF image that has been loaded \r
                              and relocated into system memory.\r
@@ -1396,5 +1508,10 @@ PeCoffLoaderUnloadImage (
   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
   )\r
 {\r
+  //\r
+  // Applies additional environment specific actions to unload a \r
+  // PE/COFF image if needed\r
+  //\r
+  PeCoffLoaderUnloadImageExtraAction (ImageContext);\r
   return RETURN_SUCCESS;\r
 }\r