]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / PiSmmIpl.c
index 1029a077794cb23fe8daf7bd5eaa1e713ab97af9..21c69ca6ef5bbf8a503b97f8f561abbc9c0d4177 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 - 2014, 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
@@ -137,6 +140,20 @@ SmmIplReadyToLockEventNotify (
   @param  Event                 The Event that is being processed, not used.\r
   @param  Context               Event Context, not used.\r
 \r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplDxeDispatchEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+/**\r
+  Event notification that is fired when a GUIDed Event Group is signaled.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -172,6 +189,7 @@ typedef struct {
   EFI_GUID          *Guid;\r
   EFI_EVENT_NOTIFY  NotifyFunction;\r
   VOID              *NotifyContext;\r
+  EFI_TPL           NotifyTpl;\r
   EFI_EVENT         Event;\r
 } SMM_IPL_EVENT_NOTIFICATION;\r
 \r
@@ -208,8 +226,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 +243,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
@@ -235,41 +255,90 @@ SMM_IPL_EVENT_NOTIFICATION  mSmmIplEvents[] = {
   // the associated event is immediately signalled, so the notification function will be executed and the \r
   // SMM Configuration Protocol will be found if it is already in the handle database.\r
   //\r
-  { TRUE,  FALSE, &gEfiSmmConfigurationProtocolGuid,  SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid,  NULL },\r
+  { TRUE,  FALSE, &gEfiSmmConfigurationProtocolGuid,  SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid,  TPL_NOTIFY,   NULL },\r
   //\r
   // Declare protocl notification on DxeSmmReadyToLock protocols.  When this notification is etablished, \r
   // the associated event is immediately signalled, so the notification function will be executed and the \r
   // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.\r
   //\r
-  { TRUE,  TRUE,  &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify,      &gEfiDxeSmmReadyToLockProtocolGuid, NULL },\r
+  { TRUE,  TRUE,  &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify,      &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL },\r
+  //\r
+  // Declare event notification on EndOfDxe event.  When this notification is etablished, \r
+  // the associated event is immediately signalled, so the notification function will be executed and the \r
+  // SMM End Of Dxe Protocol will be found if it is already in the handle database.\r
+  //\r
+  { FALSE, FALSE,  &gEfiEndOfDxeEventGroupGuid,        SmmIplGuidedEventNotify,           &gEfiEndOfDxeEventGroupGuid,        TPL_CALLBACK, NULL },\r
   //\r
   // Declare event notification on the DXE Dispatch Event Group.  This event is signaled by the DXE Core\r
   // each time the DXE Core dispatcher has completed its work.  When this event is signalled, the SMM Core\r
   // if notified, so the SMM Core can dispatch SMM drivers.\r
   //\r
-  { FALSE, TRUE,  &gEfiEventDxeDispatchGuid,          SmmIplGuidedEventNotify,           &gEfiEventDxeDispatchGuid,          NULL },\r
+  { FALSE, TRUE,  &gEfiEventDxeDispatchGuid,          SmmIplDxeDispatchEventNotify,      &gEfiEventDxeDispatchGuid,          TPL_CALLBACK, NULL },\r
   //\r
   // Declare event notification on Ready To Boot Event Group.  This is an extra event notification that is\r
   // used to make sure SMRAM is locked before any boot options are processed.\r
   //\r
-  { FALSE, TRUE,  &gEfiEventReadyToBootGuid,          SmmIplReadyToLockEventNotify,      &gEfiEventReadyToBootGuid,          NULL },\r
+  { FALSE, TRUE,  &gEfiEventReadyToBootGuid,          SmmIplReadyToLockEventNotify,      &gEfiEventReadyToBootGuid,          TPL_CALLBACK, NULL },\r
   //\r
   // Declare event notification on Legacy Boot Event Group.  This is used to inform the SMM Core that the platform \r
   // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core \r
   // must guarantee that it does not access any UEFI related structures outside of SMRAM.\r
   //\r
-  { FALSE, FALSE, &gEfiEventLegacyBootGuid,           SmmIplGuidedEventNotify,           &gEfiEventLegacyBootGuid,           NULL },\r
+  { FALSE, FALSE, &gEfiEventLegacyBootGuid,           SmmIplGuidedEventNotify,           &gEfiEventLegacyBootGuid,           TPL_CALLBACK, NULL },\r
   //\r
   // Declare event notification on SetVirtualAddressMap() Event Group.  This is used to convert gSmmCorePrivate \r
   // and mSmmControl2 from physical addresses to virtual addresses.\r
   //\r
-  { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify,     NULL,                               NULL },\r
+  { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify,     NULL,                               TPL_CALLBACK, NULL },\r
   //\r
   // Terminate the table of event notifications\r
   //\r
-  { FALSE, FALSE, NULL,                               NULL,                              NULL,                               NULL }\r
+  { FALSE, FALSE, NULL,                               NULL,                              NULL,                               TPL_CALLBACK, 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
@@ -363,6 +432,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 +447,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 +460,7 @@ SmmCommunicationCommunicate (
     //\r
     // Return status from software SMI \r
     //\r
+    *CommSize = gSmmCorePrivate->BufferSize;\r
     return gSmmCorePrivate->ReturnStatus;\r
   }\r
 \r
@@ -398,9 +475,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
@@ -433,11 +510,11 @@ SmmCommunicationCommunicate (
   //\r
   gSmmCorePrivate->InSmm = OldInSmm;\r
 \r
-  return (Status == EFI_WARN_INTERRUPT_SOURCE_QUIESCED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+  return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
 }\r
 \r
 /**\r
-  Event notification that is fired when DxeDispatch Event Group is signaled.\r
+  Event notification that is fired when GUIDed Event Group is signaled.\r
 \r
   @param  Event                 The Event that is being processed, not used.\r
   @param  Context               Event Context, not used.\r
@@ -467,6 +544,76 @@ SmmIplGuidedEventNotify (
   SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);\r
 }\r
 \r
+/**\r
+  Event notification that is fired when DxeDispatch Event Group is signaled.\r
+\r
+  @param  Event                 The Event that is being processed, not used.\r
+  @param  Context               Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplDxeDispatchEventNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_SMM_COMMUNICATE_HEADER  CommunicateHeader;\r
+  UINTN                       Size;\r
+  EFI_STATUS                  Status;\r
+\r
+  //\r
+  // Keep calling the SMM Core Dispatcher until there is no request to restart it.\r
+  //\r
+  while (TRUE) {\r
+    //\r
+    // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure\r
+    // Clear the buffer passed into the Software SMI.  This buffer will return\r
+    // the status of the SMM Core Dispatcher.\r
+    //\r
+    CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
+    CommunicateHeader.MessageLength = 1;\r
+    CommunicateHeader.Data[0] = 0;\r
+\r
+    //\r
+    // Generate the Software SMI and return the result\r
+    //\r
+    Size = sizeof (CommunicateHeader);\r
+    SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);\r
+    \r
+    //\r
+    // Return if there is no request to restart the SMM Core Dispatcher\r
+    //\r
+    if (CommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {\r
+      return;\r
+    }\r
+      \r
+    //\r
+    // Attempt to reset SMRAM cacheability to UC\r
+    // Assume CPU AP is available at this time\r
+    //\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
+    // Close all SMRAM ranges to protect SMRAM\r
+    //\r
+    Status = mSmmAccess->Close (mSmmAccess);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Print debug message that the SMRAM window is now closed.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
+  }\r
+}\r
+\r
 /**\r
   Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
 \r
@@ -499,7 +646,7 @@ SmmIplSmmConfigurationEventNotify (
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
-  // Set flag to indicate that the SM< Entry Point has been registered which \r
+  // Set flag to indicate that the SMM Entry Point has been registered which \r
   // means that SMIs are now fully operational.\r
   //\r
   gSmmCorePrivate->SmmEntryPointRegistered = TRUE;\r
@@ -508,29 +655,6 @@ SmmIplSmmConfigurationEventNotify (
   // Print debug message showing SMM Core entry point address.\r
   //\r
   DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));\r
-\r
-  //\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
-\r
-  //\r
-  // Close all SMRAM ranges to protect SMRAM\r
-  //\r
-  Status = mSmmAccess->Close (mSmmAccess);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  //\r
-  // Print debug message that the SMRAM window is now closed.\r
-  //\r
-  DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
 }\r
 \r
 /**\r
@@ -580,7 +704,7 @@ SmmIplReadyToLockEventNotify (
   // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)\r
   //\r
   mSmmAccess->Lock (mSmmAccess);\r
-\r
+  \r
   //\r
   // Close protocol and event notification events that do not apply after the \r
   // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot \r
@@ -629,81 +753,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 +874,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,25 +899,60 @@ 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((UINTN)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((UINTN)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
+  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));\r
 \r
   //\r
   // Print debug message showing SMM Core load address.\r
@@ -794,6 +979,13 @@ ExecuteSmmCoreFromSmram (
       //\r
       DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));\r
 \r
+      gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress;\r
+      gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize;\r
+      DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase));\r
+      DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize));\r
+\r
+      gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint;\r
+\r
       //\r
       // Execute image\r
       //\r
@@ -847,6 +1039,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
@@ -888,6 +1083,14 @@ SmmIplEntry (
 \r
   gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
 \r
+  //\r
+  // Save a full copy\r
+  //\r
+  gSmmCorePrivate->FullSmramRangeCount = gSmmCorePrivate->SmramRangeCount;\r
+  gSmmCorePrivate->FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);\r
+  ASSERT (gSmmCorePrivate->FullSmramRanges != NULL);\r
+  CopyMem (gSmmCorePrivate->FullSmramRanges, gSmmCorePrivate->SmramRanges, Size);\r
+\r
   //\r
   // Open all SMRAM ranges\r
   //\r
@@ -924,6 +1127,13 @@ SmmIplEntry (
   //\r
   mCurrentSmramRange = NULL;\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 +1153,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 +1212,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
@@ -1026,7 +1272,7 @@ SmmIplEntry (
     if (mSmmIplEvents[Index].Protocol) {\r
       mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (\r
                                      mSmmIplEvents[Index].Guid,\r
-                                    TPL_CALLBACK,\r
+                                     mSmmIplEvents[Index].NotifyTpl,\r
                                      mSmmIplEvents[Index].NotifyFunction,\r
                                      mSmmIplEvents[Index].NotifyContext,\r
                                     &Registration\r
@@ -1034,7 +1280,7 @@ SmmIplEntry (
     } else {\r
       Status = gBS->CreateEventEx (\r
                       EVT_NOTIFY_SIGNAL,\r
-                      TPL_CALLBACK,\r
+                      mSmmIplEvents[Index].NotifyTpl,\r
                       mSmmIplEvents[Index].NotifyFunction,\r
                       mSmmIplEvents[Index].NotifyContext,\r
                       mSmmIplEvents[Index].Guid,\r