]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
Clean up DEC files:
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / PiSmmIpl.c
index e372e7ecf198062f3ff4cf696db1680d7e4bf760..0cfd746a07c7938e4f1b7ac4ec53591dbd36452d 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation.  All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials are licensed and made available \r
   under the terms and conditions of the BSD License which accompanies this \r
   distribution.  The full text of the license may be found at        \r
 #include <Protocol/SmmConfiguration.h>\r
 #include <Protocol/SmmControl2.h>\r
 #include <Protocol/DxeSmmReadyToLock.h>\r
-#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/Cpu.h>\r
 \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
 #include <Library/DebugLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/DxeServicesTableLib.h>\r
+#include <Library/DxeServicesLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/UefiRuntimeLib.h>\r
+#include <Library/PcdLib.h>\r
 \r
 #include "PiSmmCorePrivateData.h"\r
 \r
@@ -87,8 +90,8 @@ SmmBase2GetSmstLocation (
   after SetVirtualAddressMap().\r
 \r
   @param[in]     This                The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
-  @param[in out] CommBuffer          A pointer to the buffer to convey into SMRAM.\r
-  @param[in out] CommSize            The size of the data buffer being passed in.On exit, the size of data\r
+  @param[in, out] CommBuffer          A pointer to the buffer to convey into SMRAM.\r
+  @param[in, out] CommSize            The size of the data buffer being passed in.On exit, the size of data\r
                                      being returned. Zero if the handler does not wish to reply with any data.\r
 \r
   @retval EFI_SUCCESS                The message was successfully posted.\r
@@ -208,8 +211,8 @@ SMM_CORE_PRIVATE_DATA  mSmmCorePrivateData = {
   FALSE,                              // SmmEntryPointRegistered\r
   FALSE,                              // InSmm\r
   NULL,                               // Smst\r
-  0,                                  // BufferSize\r
   NULL,                               // CommunicationBuffer\r
+  0,                                  // BufferSize\r
   EFI_SUCCESS                         // ReturnStatus\r
 };\r
 \r
@@ -225,6 +228,8 @@ EFI_SMM_CONTROL2_PROTOCOL  *mSmmControl2;
 EFI_SMM_ACCESS2_PROTOCOL   *mSmmAccess;\r
 EFI_SMRAM_DESCRIPTOR       *mCurrentSmramRange;\r
 BOOLEAN                    mSmmLocked = FALSE;\r
+EFI_PHYSICAL_ADDRESS       mSmramCacheBase;\r
+UINT64                     mSmramCacheSize;\r
 \r
 //\r
 // Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires\r
@@ -270,6 +275,49 @@ SMM_IPL_EVENT_NOTIFICATION  mSmmIplEvents[] = {
   { FALSE, FALSE, NULL,                               NULL,                              NULL,                               NULL }\r
 };\r
 \r
+/**\r
+  Find the maximum SMRAM cache range that covers the range specified by SmramRange.\r
+  \r
+  This function searches and joins all adjacent ranges of SmramRange into a range to be cached.\r
+\r
+  @param   SmramRange       The SMRAM range to search from.\r
+  @param   SmramCacheBase   The returned cache range base.\r
+  @param   SmramCacheSize   The returned cache range size.\r
+\r
+**/\r
+VOID\r
+GetSmramCacheRange (\r
+  IN  EFI_SMRAM_DESCRIPTOR *SmramRange,\r
+  OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,\r
+  OUT UINT64               *SmramCacheSize\r
+  )\r
+{\r
+  UINTN                Index;\r
+  EFI_PHYSICAL_ADDRESS RangeCpuStart;\r
+  UINT64               RangePhysicalSize;\r
+  BOOLEAN              FoundAjacentRange;\r
+\r
+  *SmramCacheBase = SmramRange->CpuStart;\r
+  *SmramCacheSize = SmramRange->PhysicalSize;\r
+\r
+  do {\r
+    FoundAjacentRange = FALSE;\r
+    for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+      RangeCpuStart     = gSmmCorePrivate->SmramRanges[Index].CpuStart;\r
+      RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;\r
+      if (RangeCpuStart < *SmramCacheBase && *SmramCacheBase == (RangeCpuStart + RangePhysicalSize)) {\r
+        *SmramCacheBase   = RangeCpuStart;\r
+        *SmramCacheSize  += RangePhysicalSize;\r
+        FoundAjacentRange = TRUE;\r
+      } else if ((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart && RangePhysicalSize > 0) {\r
+        *SmramCacheSize  += RangePhysicalSize;\r
+        FoundAjacentRange = TRUE;\r
+      }\r
+    }\r
+  } while (FoundAjacentRange);\r
+  \r
+}\r
+\r
 /**\r
   Indicate whether the driver is currently executing in the SMM Initialization phase.\r
 \r
@@ -337,8 +385,8 @@ SmmBase2GetSmstLocation (
   after SetVirtualAddressMap().\r
 \r
   @param[in] This                The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
-  @param[in out] CommBuffer          A pointer to the buffer to convey into SMRAM.\r
-  @param[in out] CommSize            The size of the data buffer being passed in.On exit, the size of data\r
+  @param[in, out] CommBuffer          A pointer to the buffer to convey into SMRAM.\r
+  @param[in, out] CommSize            The size of the data buffer being passed in.On exit, the size of data\r
                                  being returned. Zero if the handler does not wish to reply with any data.\r
 \r
   @retval EFI_SUCCESS            The message was successfully posted.\r
@@ -363,6 +411,13 @@ SmmCommunicationCommunicate (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  //\r
+  // CommSize must hold HeaderGuid and MessageLength\r
+  //\r
+  if (*CommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   //\r
   // If not already in SMM, then generate a Software SMI\r
   //\r
@@ -371,7 +426,7 @@ SmmCommunicationCommunicate (
     // Put arguments for Software SMI in gSmmCorePrivate\r
     //\r
     gSmmCorePrivate->CommunicationBuffer = CommBuffer;\r
-    gSmmCorePrivate->BufferSize          = CommSize;\r
+    gSmmCorePrivate->BufferSize          = *CommSize;\r
 \r
     //\r
     // Generate Software SMI\r
@@ -384,6 +439,7 @@ SmmCommunicationCommunicate (
     //\r
     // Return status from software SMI \r
     //\r
+    *CommSize = gSmmCorePrivate->BufferSize;\r
     return gSmmCorePrivate->ReturnStatus;\r
   }\r
 \r
@@ -398,9 +454,9 @@ SmmCommunicationCommunicate (
   }\r
 \r
   //\r
-  // Don't allow call SmiManage() directly when SMRAM is closed or locked.\r
+  // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.\r
   //\r
-  if (!mSmmAccess->OpenState || mSmmAccess->LockState) {\r
+  if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
  \r
@@ -511,10 +567,11 @@ SmmIplSmmConfigurationEventNotify (
 \r
   //\r
   // Attempt to reset SMRAM cacheability to UC\r
+  // Assume CPU AP is available at this time\r
   //\r
   Status = gDS->SetMemorySpaceAttributes(\r
-                  mCurrentSmramRange->CpuStart\r
-                  mCurrentSmramRange->PhysicalSize,\r
+                  mSmramCacheBase\r
+                  mSmramCacheSize,\r
                   EFI_MEMORY_UC\r
                   );\r
   if (EFI_ERROR (Status)) {\r
@@ -629,81 +686,100 @@ SmmIplSetVirtualAddressNotify (
 }\r
 \r
 /**\r
-  Searches all Firmware Volumes for the first file matching FileType and SectionType and returns the section data.\r
-\r
-  @param   FileType                FileType to search for within any of the firmware volumes in the platform.\r
-  @param   SectionType             SectionType to search for within any of the matching FileTypes in the firmware volumes in the platform.\r
-  @param   SourceSize              Return the size of the returned section data..\r
-\r
-  @retval  != NULL                 Pointer to the allocated buffer containing the section data.\r
-  @retval  NULL                    Section data was not found.\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
-VOID *\r
-GetSectionInAnyFv (\r
-  IN  EFI_FV_FILETYPE   FileType,\r
-  IN  EFI_SECTION_TYPE  SectionType,\r
-  OUT UINTN             *SourceSize\r
+EFI_STATUS\r
+GetPeCoffImageFixLoadingAssignedAddress(\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
   )\r
 {\r
-  EFI_STATUS                    Status;\r
-  UINTN                         HandleCount;\r
-  EFI_HANDLE                    *HandleBuffer;\r
-  UINTN                         Index;\r
-  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
-  UINTN                         Key;\r
-  EFI_GUID                      NameGuid;\r
-  EFI_FV_FILE_ATTRIBUTES        Attributes;\r
-  VOID                          *SourceBuffer;\r
-  UINT32                        AuthenticationStatus;\r
-\r
-  HandleBuffer = NULL;\r
-  Status = gBS->LocateHandleBuffer (\r
-                  ByProtocol,\r
-                  &gEfiFirmwareVolume2ProtocolGuid,\r
-                  NULL,\r
-                  &HandleCount,\r
-                  &HandleBuffer\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return NULL;\r
-  }\r
-\r
-  for (Index = 0; Index < HandleCount; Index++) {\r
-    Status = gBS->HandleProtocol (\r
-                    HandleBuffer[Index],\r
-                    &gEfiFirmwareVolume2ProtocolGuid,\r
-                    (VOID **)&Fv\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-\r
-    //\r
-    // Use Firmware Volume 2 Protocol to search for a file of type FileType\r
-    //\r
-    Key = 0;   \r
-    Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, SourceSize);\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-\r
-    //\r
-    // Use Firmware Volume 2 Protocol to read a section of type SectionType\r
-    //\r
-    SourceBuffer = NULL;\r
-    Status = Fv->ReadSection (Fv, &NameGuid, SectionType, 0, &SourceBuffer, SourceSize, &AuthenticationStatus);\r
-    if (!EFI_ERROR (Status)) {\r
-      FreePool (HandleBuffer);\r
-      return SourceBuffer;\r
-    }\r
-  }  \r
-\r
-  FreePool(HandleBuffer);\r
-  \r
-  return NULL;\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
 /**\r
   Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.\r
 \r
@@ -731,9 +807,16 @@ ExecuteSmmCoreFromSmram (
   //\r
   // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE\r
   //  \r
-  SourceBuffer = GetSectionInAnyFv (EFI_FV_FILETYPE_SMM_CORE, EFI_SECTION_PE32, &SourceSize);\r
-  if (SourceBuffer == NULL) {\r
-    return EFI_NOT_FOUND;\r
+  Status = GetSectionFromAnyFvByFileType (\r
+             EFI_FV_FILETYPE_SMM_CORE, \r
+             0,\r
+             EFI_SECTION_PE32, \r
+             0,\r
+             &SourceBuffer, \r
+             &SourceSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
   \r
   //\r
@@ -749,23 +832,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 +965,9 @@ 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
+  EFI_CPU_ARCH_PROTOCOL           *CpuArch;\r
 \r
   //\r
   // Fill in the image handle of the SMM IPL so the SMM Core can use this as the \r
@@ -920,10 +1041,17 @@ SmmIplEntry (
   }\r
   \r
   //\r
-  // Find the largest SMRAM range between 1MB and 4GB that is at least 1MB in size\r
+  // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size\r
   //\r
   mCurrentSmramRange = NULL;\r
-  for (Index = 0, MaxSize = SIZE_1MB; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+    //\r
+    // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization\r
+    //\r
+    if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
+      continue;\r
+    }\r
+\r
     if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {\r
       if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
         if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {\r
@@ -943,18 +1071,52 @@ SmmIplEntry (
       (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)\r
       ));\r
 \r
+    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);\r
     //\r
-    // Attempt to set SMRAM cacheability to WB\r
+    // If CPU AP is present, attempt to set SMRAM cacheability to WB\r
+    // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP\r
+    // is not available here.\r
     //\r
-    Status = gDS->SetMemorySpaceAttributes(\r
-                    mCurrentSmramRange->CpuStart, \r
-                    mCurrentSmramRange->PhysicalSize,\r
-                    EFI_MEMORY_WB\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));\r
-    }  \r
-\r
+    CpuArch = NULL;\r
+    Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = gDS->SetMemorySpaceAttributes(\r
+                      mSmramCacheBase, \r
+                      mSmramCacheSize,\r
+                      EFI_MEMORY_WB\r
+                      );\r
+      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
+        // Print the SMRAM base\r
+        //\r
+        DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", LMFAConfigurationTable->SmramBase));\r
+      }\r
+    }\r
     //\r
     // Load SMM Core into SMRAM and execute it from SMRAM\r
     //\r
@@ -968,14 +1130,16 @@ SmmIplEntry (
       //\r
       // Attempt to reset SMRAM cacheability to UC\r
       //\r
-      Status = gDS->SetMemorySpaceAttributes(\r
-                      mCurrentSmramRange->CpuStart, \r
-                      mCurrentSmramRange->PhysicalSize,\r
-                      EFI_MEMORY_UC\r
-                      );\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
-      }  \r
+      if (CpuArch != NULL) {\r
+        Status = gDS->SetMemorySpaceAttributes(\r
+                        mSmramCacheBase, \r
+                        mSmramCacheSize,\r
+                        EFI_MEMORY_UC\r
+                        );\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+        }  \r
+      }\r
     }\r
   } else {\r
     //\r