]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
Enable "Load Module At fixed Address" feature in SMM Core
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / PiSmmIpl.c
index 1029a077794cb23fe8daf7bd5eaa1e713ab97af9..ff7eff73bfb08976b3f72fa4f139bbd0c804533b 100644 (file)
@@ -24,6 +24,7 @@
 \r
 #include <Guid/EventGroup.h>\r
 #include <Guid/EventLegacyBios.h>\r
+#include <Guid/LoadModuleAtFixedAddress.h>\r
 \r
 #include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
@@ -35,6 +36,7 @@
 #include <Library/DxeServicesTableLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/UefiRuntimeLib.h>\r
+#include <Library/PcdLib.h>\r
 \r
 #include "PiSmmCorePrivateData.h"\r
 \r
@@ -703,7 +705,101 @@ GetSectionInAnyFv (
   \r
   return NULL;\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
+  @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
+EFI_STATUS\r
+GetPeCoffImageFixLoadingAssignedAddress(\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\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
+   EFI_PHYSICAL_ADDRESS               SmramBase;\r
+   UINT64                             SmmCodeSize;\r
+   UINT64                             ValueInSectionHeader;\r
+   //\r
+   // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
+   //\r
+   SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32(PcdLoadFixAddressSmmCodePageNumber));\r
\r
+   FixLoaddingAddress = 0;\r
+   Status = EFI_NOT_FOUND;\r
+   SmramBase = mCurrentSmramRange->CpuStart;\r
+   //\r
+   // Get PeHeader pointer\r
+   //\r
+   ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\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 saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the\r
+       // first section header that doesn't point to code section in image header. And there is an assumption that when the\r
+       // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers\r
+       // fields should NOT be Zero, or 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 in which uild tool saves the\r
+         // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields\r
+         //\r
+         FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader);\r
+\r
+         if (SmramBase + SmmCodeSize > FixLoaddingAddress && SmramBase <=  FixLoaddingAddress) {\r
+           //\r
+           // The assigned address is valid. Return the specified loadding address\r
+           //\r
+           ImageContext->ImageAddress = FixLoaddingAddress;\r
+           Status = EFI_SUCCESS;\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 %x, Status = %r \n", FixLoaddingAddress, Status));\r
+   return Status;\r
+}\r
 /**\r
   Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.\r
 \r
@@ -749,23 +845,58 @@ ExecuteSmmCoreFromSmram (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-\r
   //\r
-  // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
-  // specified by SmramRange\r
+  // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to \r
+  // the address assigned by build tool.\r
   //\r
-  PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+  if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+    //\r
+    // Get the fixed loading address assigned by Build tool\r
+    //\r
+    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range\r
+      //\r
+      PageCount = 0;\r
+     } else {\r
+      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));\r
+      //\r
+      // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
+      // specified by SmramRange\r
+      //\r
+      PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
 \r
-  ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
-  ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
+      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
+      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
 \r
-  SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
-  DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+      SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
+      DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
 \r
-  //\r
-  // Align buffer on section boundry\r
-  //\r
-  ImageContext.ImageAddress = DestinationBuffer;\r
+      //\r
+      // Align buffer on section boundry\r
+      //\r
+      ImageContext.ImageAddress = DestinationBuffer;\r
+    }\r
+  } else {\r
+    //\r
+    // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
+    // specified by SmramRange\r
+    //\r
+    PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+\r
+    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
+    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
+\r
+    SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
+    DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+\r
+    //\r
+    // Align buffer on section boundry\r
+    //\r
+    ImageContext.ImageAddress = DestinationBuffer;\r
+  }\r
+  \r
   ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
   ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
 \r
@@ -847,6 +978,8 @@ SmmIplEntry (
   EFI_SMM_RESERVED_SMRAM_REGION   *SmramResRegion;\r
   UINT64                          MaxSize;\r
   VOID                            *Registration;\r
+  UINT64                           SmmCodeSize;\r
+  EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE    *LMFAConfigurationTable;\r
 \r
   //\r
   // Fill in the image handle of the SMM IPL so the SMM Core can use this as the \r
@@ -954,7 +1087,34 @@ SmmIplEntry (
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));\r
     }  \r
-\r
+    //\r
+    // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load\r
+    // Modules At Fixed Address Configuration Table.\r
+    //\r
+    if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+      //\r
+      // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
+      //\r
+      SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);\r
+      //\r
+      // The SMRAM available memory is assumed to be larger than SmmCodeSize\r
+      //\r
+      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);\r
+      //\r
+      // Retrieve Load modules At fixed address configuration table and save the SMRAM base.\r
+      //\r
+      Status = EfiGetSystemConfigurationTable (\r
+                &gLoadFixedAddressConfigurationTableGuid,\r
+               (VOID **) &LMFAConfigurationTable\r
+               );\r
+      if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {\r
+        LMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;\r
+      }\r
+      //\r
+      // Print the SMRAM base\r
+      //\r
+      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", LMFAConfigurationTable->SmramBase));\r
+    }\r
     //\r
     // Load SMM Core into SMRAM and execute it from SMRAM\r
     //\r