]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Pei/Image/Image.c
Enable the Load Module At fixed Address feature
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
index 63c8868894a163e92a4fcfc25649376c9f34eb1e..c2683762b73e4f62abe5e6e0eed3245e2c568cc0 100644 (file)
@@ -1,14 +1,14 @@
 /** @file\r
   Pei Core Load Image Support\r
-  \r
-Copyright (c) 2006 - 2010, Intel Corporation                                                         \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
-http://opensource.org/licenses/bsd-license.php                                            \r
-                                                                                          \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation\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
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
 **/\r
 \r
@@ -96,7 +96,192 @@ GetImageReadFunction (
 \r
   return EFI_SUCCESS;\r
 }\r
+/**\r
+  To check memory usage bit map arry to figure out if the memory range the image will be loaded in is available or not. If \r
+  memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used.\r
+  The function is only invoked when load modules at fixed address feature is enabled. \r
+  \r
+  @param  Private                  Pointer to the private data passed in from caller\r
+  @param  ImageBase                The base addres the image will be loaded at.\r
+  @param  ImageSize                The size of the image\r
+  \r
+  @retval EFI_SUCCESS              The memory range the image will be loaded in is available\r
+  @retval EFI_NOT_FOUND            The memory range the image will be loaded in is not available\r
+**/\r
+EFI_STATUS\r
+CheckAndMarkFixLoadingMemoryUsageBitMap (\r
+  IN  PEI_CORE_INSTANCE             *Private,\r
+  IN  EFI_PHYSICAL_ADDRESS          ImageBase,\r
+  IN  UINT32                        ImageSize\r
+  )\r
+{\r
+   UINT32                             DxeCodePageNumber;\r
+   UINT64                             ReservedCodeSize;\r
+   EFI_PHYSICAL_ADDRESS               PeiCodeBase;\r
+   UINT32                             BaseOffsetPageNumber;\r
+   UINT32                             TopOffsetPageNumber;\r
+   UINT32                             Index;\r
+   UINT64                             *MemoryUsageBitMap;\r
+   \r
+\r
+   //\r
+   // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.\r
+   //\r
+   DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
+   DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
+   ReservedCodeSize  = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));\r
+   PeiCodeBase       = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;\r
+   \r
+   //\r
+   // Test the memory range for loading the image in the PEI code range.\r
+   //\r
+   if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||\r
+       (PeiCodeBase > ImageBase)) {         \r
+     return EFI_NOT_FOUND; \r
+   }\r
+   \r
+   //\r
+   // Test if the memory is avalaible or not.\r
+   //\r
+   MemoryUsageBitMap    = Private->PeiCodeMemoryRangeUsageBitMap;  \r
+   BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));\r
+   TopOffsetPageNumber  = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));\r
+   for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+     if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {\r
+       //\r
+       // This page is already used.\r
+       //\r
+       return EFI_NOT_FOUND;  \r
+     }\r
+   }\r
+   \r
+   //\r
+   // Being here means the memory range is available.  So mark the bits for the memory range\r
+   // \r
+   for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+     MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
+   }\r
+   return  EFI_SUCCESS;   \r
+}\r
+/**\r
+\r
+  Get the fixed loadding address from image header assigned by build tool. This function only be called\r
+  when Loading module at Fixed address feature enabled.\r
+\r
+  @param ImageContext              Pointer to the image context structure that describes the PE/COFF\r
+                                    image that needs to be examined by this function.\r
+  @param Private                    Pointer to the private data passed in from caller\r
+\r
+  @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .\r
+  @retval EFI_NOT_FOUND             The image has no assigned fixed loadding address.\r
 \r
+**/\r
+EFI_STATUS\r
+GetPeCoffImageFixLoadingAssignedAddress(\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,\r
+  IN     PEI_CORE_INSTANCE             *Private\r
+  )\r
+{\r
+   UINTN                              SectionHeaderOffset;\r
+   EFI_STATUS                         Status;\r
+   EFI_IMAGE_SECTION_HEADER           SectionHeader;\r
+   EFI_IMAGE_OPTIONAL_HEADER_UNION    *ImgHdr;\r
+   EFI_PHYSICAL_ADDRESS               FixLoaddingAddress;\r
+   UINT16                             Index;\r
+   UINTN                              Size;\r
+   UINT16                             NumberOfSections;\r
+   UINT64                             ValueInSectionHeader;\r
\r
+\r
+   FixLoaddingAddress = 0;\r
+   Status = EFI_NOT_FOUND;\r
+\r
+   //\r
+   // Get PeHeader pointer\r
+   //\r
+   ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\r
+   if (ImageContext->IsTeImage) {\r
+     //\r
+     // for TE image, the fix loadding address is saved in first section header that doesn't point\r
+     // to code section.\r
+     //\r
+     SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);\r
+     NumberOfSections = ImgHdr->Te.NumberOfSections;\r
+   } else {\r
+     SectionHeaderOffset = (UINTN)(\r
+                                 ImageContext->PeCoffHeaderOffset +\r
+                                 sizeof (UINT32) +\r
+                                 sizeof (EFI_IMAGE_FILE_HEADER) +\r
+                                 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+                                 );\r
+      NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
+   }\r
+   //\r
+   // Get base address from the first section header that doesn't point to code section.\r
+   //\r
+   for (Index = 0; Index < NumberOfSections; Index++) {\r
+     //\r
+     // Read section header from file\r
+     //\r
+     Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+     Status = ImageContext->ImageRead (\r
+                              ImageContext->Handle,\r
+                              SectionHeaderOffset,\r
+                              &Size,\r
+                              &SectionHeader\r
+                              );\r
+     if (EFI_ERROR (Status)) {\r
+       return Status;\r
+     }\r
+\r
+     Status = EFI_NOT_FOUND;\r
+\r
+     if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
+       //\r
+       // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header\r
+       // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is\r
+       // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because\r
+       // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers\r
+       // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a\r
+       // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or\r
+       // else, these 2 fileds should be set to Zero\r
+       //\r
+       ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);\r
+       if (ValueInSectionHeader != 0) {\r
+         //\r
+         // Found first section header that doesn't point to code section.\r
+         //\r
+         if ((INT64)FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {\r
+           //\r
+           // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field\r
+           // hold the absolute address of image base runing in memory\r
+           //\r
+           FixLoaddingAddress = ValueInSectionHeader;\r
+         } else {\r
+           //\r
+           // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field\r
+           // hold the offset relative to a platform-specific top address.\r
+           //\r
+           FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);\r
+         }\r
+         //\r
+         // Check if the memory range is avaliable.\r
+         //\r
+         Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize);\r
+         if (!EFI_ERROR(Status)) {\r
+           //\r
+           // The assigned address is valid. Return the specified loadding address\r
+           //\r
+           ImageContext->ImageAddress = FixLoaddingAddress;\r
+         }\r
+       }\r
+       break;\r
+     }\r
+     SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+   }\r
+   DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %lx. Status= %r \n", FixLoaddingAddress, Status));\r
+   return Status;\r
+}\r
 /**\r
 \r
   Loads and relocates a PE/COFF image into memory.\r
@@ -139,29 +324,40 @@ LoadAndRelocatePeCoffImage (
   // When Image has no reloc section, it can't be relocated into memory.\r
   //\r
   if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
-    DEBUG ((EFI_D_INFO, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));\r
+    DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));\r
   }\r
 \r
   //\r
   // Set default base address to current image address.\r
   //\r
   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;\r
-  \r
+\r
   //\r
   // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.\r
   //\r
   if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
-    ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+    if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+      Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);\r
+      if (EFI_ERROR (Status)){\r
+        DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));\r
+        //\r
+        // The PEIM is not assiged valid address, try to allocate page to load it.\r
+        //\r
+        ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+      }\r
+    } else {\r
+      ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+    }\r
     ASSERT (ImageContext.ImageAddress != 0);\r
     if (ImageContext.ImageAddress == 0) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
-    \r
+\r
     //\r
     // Skip the reserved space for the stripped PeHeader when load TeImage into memory.\r
     //\r
     if (ImageContext.IsTeImage) {\r
-      ImageContext.ImageAddress = ImageContext.ImageAddress + \r
+      ImageContext.ImageAddress = ImageContext.ImageAddress +\r
                                   ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -\r
                                   sizeof (EFI_TE_IMAGE_HEADER);\r
     }\r
@@ -197,8 +393,8 @@ LoadAndRelocatePeCoffImage (
 }\r
 \r
 /**\r
-  Loads a PEIM into memory for subsequent execution. If there are compressed \r
-  images or images that need to be relocated into memory for performance reasons, \r
+  Loads a PEIM into memory for subsequent execution. If there are compressed\r
+  images or images that need to be relocated into memory for performance reasons,\r
   this service performs that transformation.\r
 \r
   @param PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
@@ -245,7 +441,7 @@ PeiLoadImageLoadImage (
   }\r
 \r
   //\r
-  // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst \r
+  // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst\r
   // is true, TE will be searched first).\r
   //\r
   Status = PeiServicesFfsFindSectionData (\r
@@ -270,7 +466,7 @@ PeiLoadImageLoadImage (
       return Status;\r
     }\r
   }\r
-  \r
+\r
   //\r
   // If memory is installed, perform the shadow operations\r
   //\r
@@ -293,9 +489,9 @@ PeiLoadImageLoadImage (
   //\r
   Pe32Data    = (VOID *) ((UINTN) ImageAddress);\r
   *EntryPoint = ImageEntryPoint;\r
-  \r
+\r
   Machine = PeCoffLoaderGetMachineType (Pe32Data);\r
-  \r
+\r
   if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {\r
     if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {\r
       return EFI_UNSUPPORTED;\r
@@ -309,7 +505,7 @@ PeiLoadImageLoadImage (
   if (ImageSizeArg != NULL) {\r
     *ImageSizeArg = ImageSize;\r
   }\r
-  \r
+\r
   DEBUG_CODE_BEGIN ();\r
     CHAR8                              *AsciiString;\r
     CHAR8                              AsciiBuffer[512];\r
@@ -327,12 +523,12 @@ PeiLoadImageLoadImage (
       //\r
       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));\r
     }\r
-    \r
+\r
     //\r
     // Print Module Name by PeImage PDB file name.\r
     //\r
     AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);\r
-    \r
+\r
     if (AsciiString != NULL) {\r
       for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {\r
         if (AsciiString[Index] == '\\') {\r
@@ -454,7 +650,7 @@ RelocationIsStrip (
 \r
 /**\r
   Routine to load image file for subsequent execution by LoadFile Ppi.\r
-  If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE \r
+  If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE\r
   XIP image format is used.\r
 \r
   @param PeiServices     - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
@@ -500,9 +696,9 @@ PeiLoadImage (
                   );\r
     if (!EFI_ERROR (PpiStatus)) {\r
       Status = LoadFile->LoadFile (\r
-                          LoadFile, \r
-                          FileHandle, \r
-                          &ImageAddress, \r
+                          LoadFile,\r
+                          FileHandle,\r
+                          &ImageAddress,\r
                           &ImageSize,\r
                           EntryPoint,\r
                           AuthenticationState\r
@@ -560,10 +756,10 @@ InitializeImageServices (
     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
+    // 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
+    PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);\r
   }\r
 }\r
 \r