[edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.

Zhang, Hongbin1 posted 1 patch 11 months, 1 week ago
Failed in applying to current master (apply log)
There is a newer version of this series
StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     | 456 ++++++++++++
StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   | 787 ++++++++++++++++++++
StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |  32 +
StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  | 148 ++++
StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66 ++
StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |  75 ++
StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
edksetup.sh                                                       | 294 ++++----
10 files changed, 1744 insertions(+), 167 deletions(-)
[edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
Posted by Zhang, Hongbin1 11 months, 1 week ago
Add StandaloneMmIplPei IA32/X64 driver at PEI stage.
FSP will use this driver to load Standalone MM code
to dispatch other Standalone MM drivers.

Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
---
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     | 456 ++++++++++++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   | 787 ++++++++++++++++++++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |  32 +
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  | 148 ++++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66 ++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |  75 ++
 StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
 StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
 UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
 edksetup.sh                                                       | 294 ++++----
 10 files changed, 1744 insertions(+), 167 deletions(-)

diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
new file mode 100644
index 0000000000..d6174d73a3
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
@@ -0,0 +1,456 @@
+/** @file
+  SMM IPL that load the SMM Core into SMRAM
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <PiSmm.h>
+#include <StandaloneMm.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <StandaloneMmIplPei.h>
+
+#pragma pack(1)
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+  struct {
+    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in memory
+    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64    Reserved             : 1;   // Reserved
+    UINT64    MustBeZero           : 2;   // Must Be Zero
+    UINT64    Available            : 3;   // Available for use by system software
+    UINT64    PageTableBaseAddress : 40;  // Page Table Base Address
+    UINT64    AvailableHigh        : 11;  // Available for use by system software
+    UINT64    Nx                   : 1;   // No Execute bit
+  } Bits;
+  UINT64    Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+  struct {
+    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in memory
+    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on access to page
+    UINT64    MustBe1              : 1;   // Must be 1
+    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+    UINT64    Available            : 3;   // Available for use by system software
+    UINT64    Pat                  : 1;   //
+    UINT64    MustBeZero           : 8;   // Must be zero
+    UINT64    PageTableBaseAddress : 31;  // Page Table Base Address
+    UINT64    AvailableHigh        : 11;  // Available for use by system software
+    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+  struct {
+    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in memory
+    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on access to page
+    UINT64    MustBe1              : 1;   // Must be 1
+    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+    UINT64    Available            : 3;   // Available for use by system software
+    UINT64    Pat                  : 1;   //
+    UINT64    MustBeZero           : 17;  // Must be zero;
+    UINT64    PageTableBaseAddress : 22;  // Page Table Base Address
+    UINT64    AvailableHigh        : 11;  // Available for use by system software
+    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR  mGdtEntries[] = {
+  /* selector { Global Segment Descriptor                              } */
+  /* 0x00 */ {
+    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
+  },                                                                      // null descriptor
+  /* 0x08 */ {
+    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
+  },                                                                      // linear data segment descriptor
+  /* 0x10 */ {
+    { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
+  },                                                                      // linear code segment descriptor
+  /* 0x18 */ {
+    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
+  },                                                                      // system data segment descriptor
+  /* 0x20 */ {
+    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
+  },                                                                      // system code segment descriptor
+  /* 0x28 */ {
+    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
+  },                                                                      // spare segment descriptor
+  /* 0x30 */ {
+    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
+  },                                                                      // system data segment descriptor
+  /* 0x38 */ {
+    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
+  },                                                                      // system code segment descriptor
+  /* 0x40 */ {
+    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
+  },                                                                      // spare segment descriptor
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR  mGdt = {
+  sizeof (mGdtEntries) - 1,
+  (UINTN)mGdtEntries
+};
+
+/**
+  Calculate the total size of page table.
+
+  @return The size of page table.
+
+**/
+UINTN
+CalculatePageTableSize (
+  VOID
+  )
+{
+  UINT32   RegEax;
+  UINT32   RegEdx;
+  UINTN    TotalPagesNum;
+  UINT8    PhysicalAddressBits;
+  VOID     *Hob;
+  UINT32   NumberOfPml4EntriesNeeded;
+  UINT32   NumberOfPdpEntriesNeeded;
+  BOOLEAN  Page1GSupport;
+
+  Page1GSupport = FALSE;
+  if (PcdGetBool (PcdUse1GPageTable)) {
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+    if (RegEax >= 0x80000001) {
+      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+      if ((RegEdx & BIT26) != 0) {
+        Page1GSupport = TRUE;
+      }
+    }
+  }
+
+  //
+  // Get physical address bits supported.
+  //
+  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+  if (Hob != NULL) {
+    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
+  } else {
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+    if (RegEax >= 0x80000008) {
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+      PhysicalAddressBits = (UINT8)RegEax;
+    } else {
+      PhysicalAddressBits = 36;
+    }
+  }
+
+  //
+  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
+  //
+  ASSERT (PhysicalAddressBits <= 52);
+  if (PhysicalAddressBits > 48) {
+    PhysicalAddressBits = 48;
+  }
+
+  //
+  // Calculate the table entries needed.
+  //
+  if (PhysicalAddressBits <= 39 ) {
+    NumberOfPml4EntriesNeeded = 1;
+    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
+  } else {
+    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
+    NumberOfPdpEntriesNeeded  = 512;
+  }
+
+  if (!Page1GSupport) {
+    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+  } else {
+    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
+  }
+
+  return EFI_PAGES_TO_SIZE (TotalPagesNum);
+}
+
+/**
+  Allocates and fills in the Page Directory and Page Table Entries to
+  establish a 1:1 Virtual to Physical mapping.
+
+  @param[in]  PageTablesAddress  The base address of page table.
+
+**/
+VOID
+CreateIdentityMappingPageTables (
+  IN  EFI_PHYSICAL_ADDRESS  PageTablesAddress
+  )
+{
+  UINT32                          RegEax;
+  UINT32                          RegEdx;
+  UINT8                           PhysicalAddressBits;
+  EFI_PHYSICAL_ADDRESS            PageAddress;
+  UINTN                           IndexOfPml4Entries;
+  UINTN                           IndexOfPdpEntries;
+  UINTN                           IndexOfPageDirectoryEntries;
+  UINT32                          NumberOfPml4EntriesNeeded;
+  UINT32                          NumberOfPdpEntriesNeeded;
+  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
+  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMap;
+  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
+  PAGE_TABLE_ENTRY                *PageDirectoryEntry;
+  UINTN                           BigPageAddress;
+  VOID                            *Hob;
+  BOOLEAN                         Page1GSupport;
+  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
+
+  Page1GSupport = FALSE;
+  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+  if (RegEax >= 0x80000001) {
+    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+    if ((RegEdx & BIT26) != 0) {
+      Page1GSupport = TRUE;
+    }
+  }
+
+  //
+  // Get physical address bits supported.
+  //
+  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+  if (Hob != NULL) {
+    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
+  } else {
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+    if (RegEax >= 0x80000008) {
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+      PhysicalAddressBits = (UINT8)RegEax;
+    } else {
+      PhysicalAddressBits = 36;
+    }
+  }
+
+  //
+  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
+  //
+  ASSERT (PhysicalAddressBits <= 52);
+  if (PhysicalAddressBits > 48) {
+    PhysicalAddressBits = 48;
+  }
+
+  //
+  // Calculate the table entries needed.
+  //
+  if (PhysicalAddressBits <= 39 ) {
+    NumberOfPml4EntriesNeeded = 1;
+    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
+  } else {
+    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
+    NumberOfPdpEntriesNeeded  = 512;
+  }
+
+  //
+  // Pre-allocate big pages to avoid later allocations.
+  //
+  BigPageAddress = (UINTN)PageTablesAddress;
+
+  //
+  // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
+  //
+  PageMap         = (VOID *)BigPageAddress;
+  BigPageAddress += SIZE_4KB;
+
+  PageMapLevel4Entry = PageMap;
+  PageAddress        = 0;
+  for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
+    //
+    // Each PML4 entry points to a page of Page Directory Pointer entires.
+    // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
+    //
+    PageDirectoryPointerEntry = (VOID *)BigPageAddress;
+    BigPageAddress           += SIZE_4KB;
+
+    //
+    // Make a PML4 Entry
+    //
+    PageMapLevel4Entry->Uint64         = (UINT64)(UINTN)PageDirectoryPointerEntry;
+    PageMapLevel4Entry->Bits.ReadWrite = 1;
+    PageMapLevel4Entry->Bits.Present   = 1;
+
+    if (Page1GSupport) {
+      PageDirectory1GEntry = (VOID *)PageDirectoryPointerEntry;
+
+      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
+        //
+        // Fill in the Page Directory entries
+        //
+        PageDirectory1GEntry->Uint64         = (UINT64)PageAddress;
+        PageDirectory1GEntry->Bits.ReadWrite = 1;
+        PageDirectory1GEntry->Bits.Present   = 1;
+        PageDirectory1GEntry->Bits.MustBe1   = 1;
+      }
+    } else {
+      for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+        //
+        // Each Directory Pointer entries points to a page of Page Directory entires.
+        // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
+        //
+        PageDirectoryEntry = (VOID *)BigPageAddress;
+        BigPageAddress    += SIZE_4KB;
+
+        //
+        // Fill in a Page Directory Pointer Entries
+        //
+        PageDirectoryPointerEntry->Uint64         = (UINT64)(UINTN)PageDirectoryEntry;
+        PageDirectoryPointerEntry->Bits.ReadWrite = 1;
+        PageDirectoryPointerEntry->Bits.Present   = 1;
+
+        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
+          //
+          // Fill in the Page Directory entries
+          //
+          PageDirectoryEntry->Uint64         = (UINT64)PageAddress;
+          PageDirectoryEntry->Bits.ReadWrite = 1;
+          PageDirectoryEntry->Bits.Present   = 1;
+          PageDirectoryEntry->Bits.MustBe1   = 1;
+        }
+      }
+
+      for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
+        ZeroMem (
+          PageDirectoryPointerEntry,
+          sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
+          );
+      }
+    }
+  }
+
+  //
+  // For the PML4 entries we are not using fill in a null entry.
+  //
+  for ( ; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {
+    ZeroMem (
+      PageMapLevel4Entry,
+      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
+      );
+  }
+}
+
+/**
+  If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
+
+  @param  Entry                     Entry of Standalone MM Foundation.
+  @param  Context1                  A pointer to the context to pass into the EntryPoint
+                                    function.
+  @param  Context2                  A pointer to the context to pass into the EntryPoint
+                                    function.
+  @retval EFI_SUCCESS               Successfully switched to long mode and execute coalesce.
+  @retval Others                    Failed to execute coalesce in long mode.
+
+**/
+EFI_STATUS
+ModeSwitch (
+  IN EFI_PHYSICAL_ADDRESS  Entry,
+  IN VOID                  *Context1,
+  IN VOID                  *Context2
+  )
+{
+  UINTN            PageTableAddress;
+  UINTN            PageTableSize;
+  EFI_STATUS       Status;
+  IA32_DESCRIPTOR  Gdtr;
+
+  DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
+
+  //
+  // Save IA32 GDTR
+  //
+  AsmReadGdtr (&Gdtr);
+
+  //
+  // Set X64 GDTR
+  //
+  AsmWriteGdtr (&mGdt);
+
+  PageTableAddress = AsmReadCr3 () & 0xFFFFF000;
+
+  //
+  // If page table was created, no need to create
+  //
+  if (PageTableAddress == 0) {
+    PageTableSize = CalculatePageTableSize ();
+
+    PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PageTableSize));
+    ASSERT (PageTableAddress != 0);
+
+    CreateIdentityMappingPageTables (PageTableAddress);
+
+    AsmWriteCr3 ((UINTN)PageTableAddress);
+  }
+
+  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n"));
+
+  Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1, (UINT64)(UINTN)Context2, NULL);
+  if (Status != 0) {
+    Status = Status | MAX_BIT;
+  }
+
+  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status));
+
+  //
+  // Restore IA32 GDTR
+  //
+  AsmWriteGdtr (&Gdtr);
+
+  return Status;
+}
+
+/**
+  Load SMM core to dispatch other Standalone MM drivers.
+
+  @param  Entry                     Entry of Standalone MM Foundation.
+  @param  Context1                  A pointer to the context to pass into the EntryPoint
+                                    function.
+  @retval EFI_SUCCESS               Successfully loaded SMM core.
+  @retval Others                    Failed to load SMM core.
+**/
+EFI_STATUS
+LoadSmmCore (
+  IN EFI_PHYSICAL_ADDRESS  Entry,
+  IN VOID                  *Context1
+  )
+{
+  return ModeSwitch (Entry, Context1, NULL);
+}
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
new file mode 100644
index 0000000000..7fa42c32fb
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
@@ -0,0 +1,787 @@
+/** @file
+  SMM IPL that load the SMM Core into SMRAM at PEI stage
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <PiSmm.h>
+#include <Ppi/SmmAccess.h>
+#include <Ppi/SmmControl.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Guid/SmramMemoryReserve.h>
+#include <Guid/MmCoreData.h>
+#include <StandaloneMmIplPei.h>
+
+//
+// MM Core Private Data structure that contains the data shared between
+// the SMM IPL and the Standalone MM Core.
+//
+MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
+  MM_CORE_PRIVATE_DATA_SIGNATURE,     // Signature
+  0,                                  // MmramRangeCount
+  0,                                  // MmramRanges
+  0,                                  // MmEntryPoint
+  FALSE,                              // MmEntryPointRegistered
+  FALSE,                              // InMm
+  0,                                  // Mmst
+  0,                                  // CommunicationBuffer
+  0,                                  // BufferSize
+  EFI_SUCCESS,                        // ReturnStatus
+  0,                                  // MmCoreImageBase
+  0,                                  // MmCoreImageSize
+  0,                                  // MmCoreEntryPoint
+  0,                                  // StandaloneBfvAddress
+};
+
+//
+// Global pointer used to access mMmCorePrivateData from outside and inside SMM
+//
+MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
+
+//
+// SMM IPL global variables
+//
+PEI_SMM_ACCESS_PPI    *mSmmAccess;
+EFI_SMRAM_DESCRIPTOR  *mCurrentSmramRange;
+BOOLEAN               mSmmLocked = FALSE;
+EFI_PHYSICAL_ADDRESS  mSmramCacheBase;
+UINT64                mSmramCacheSize;
+
+EFI_PEI_NOTIFY_DESCRIPTOR  mReadyToBootNotifyList = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiEventReadyToBootGuid,
+  ReadyToBootEvent
+};
+
+/**
+  This is the callback function on ready to boot.
+
+  Close and Lock smram range on ready to boot stage.
+
+  @param   PeiServices          General purpose services available to every PEIM.
+  @param   NotifyDescriptor     The notification structure this PEIM registered on install.
+  @param   Ppi                  Pointer to the PPI data associated with this function.
+  @retval  EFI_SUCCESS          Close and lock smram ranges successfully.
+  @retval  Other                Close and lock smram ranges failed.
+**/
+EFI_STATUS
+EFIAPI
+ReadyToBootEvent (
+  IN  EFI_PEI_SERVICES           **PeiServices,
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN  VOID                       *Ppi
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Close all SMRAM ranges
+  //
+  Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices, mSmmAccess, 0);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Lock all SMRAM ranges
+  //
+  Status = mSmmAccess->Lock ((EFI_PEI_SERVICES **)PeiServices, mSmmAccess, 0);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Find the maximum SMRAM cache range that covers the range specified by SmramRange.
+
+  This function searches and joins all adjacent ranges of SmramRange into a range to be cached.
+
+  @param   SmramRange       The SMRAM range to search from.
+  @param   SmramCacheBase   The returned cache range base.
+  @param   SmramCacheSize   The returned cache range size.
+**/
+VOID
+GetSmramCacheRange (
+  IN  EFI_SMRAM_DESCRIPTOR  *SmramRange,
+  OUT EFI_PHYSICAL_ADDRESS  *SmramCacheBase,
+  OUT UINT64                *SmramCacheSize
+  )
+{
+  UINTN                 Index;
+  EFI_PHYSICAL_ADDRESS  RangeCpuStart;
+  UINT64                RangePhysicalSize;
+  BOOLEAN               FoundAdjacentRange;
+  EFI_SMRAM_DESCRIPTOR  *SmramRanges;
+
+  *SmramCacheBase = SmramRange->CpuStart;
+  *SmramCacheSize = SmramRange->PhysicalSize;
+
+  SmramRanges = (EFI_SMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;
+  do {
+    FoundAdjacentRange = FALSE;
+    for (Index = 0; Index < gMmCorePrivate->MmramRangeCount; Index++) {
+      RangeCpuStart     = SmramRanges[Index].CpuStart;
+      RangePhysicalSize = SmramRanges[Index].PhysicalSize;
+      if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase == (RangeCpuStart + RangePhysicalSize))) {
+        *SmramCacheBase    = RangeCpuStart;
+        *SmramCacheSize   += RangePhysicalSize;
+        FoundAdjacentRange = TRUE;
+      } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) && (RangePhysicalSize > 0)) {
+        *SmramCacheSize   += RangePhysicalSize;
+        FoundAdjacentRange = TRUE;
+      }
+    }
+  } while (FoundAdjacentRange);
+}
+
+/**
+  Get the fixed loading address from image header assigned by build tool. This function only be called
+  when Loading module at Fixed address feature enabled.
+
+  @param  ImageContext              Pointer to the image context structure that describes the PE/COFF
+                                    image that needs to be examined by this function.
+  @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .
+  @retval EFI_NOT_FOUND             The image has no assigned fixed loading address.
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  )
+{
+  UINTN                            SectionHeaderOffset;
+  EFI_STATUS                       Status;
+  EFI_IMAGE_SECTION_HEADER         SectionHeader;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
+  EFI_PHYSICAL_ADDRESS             FixLoadingAddress;
+  UINT16                           Index;
+  UINTN                            Size;
+  UINT16                           NumberOfSections;
+  EFI_PHYSICAL_ADDRESS             SmramBase;
+  UINT64                           SmmCodeSize;
+  UINT64                           ValueInSectionHeader;
+
+  //
+  // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
+  //
+  SmmCodeSize       = EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber));
+  FixLoadingAddress = 0;
+  Status            = EFI_NOT_FOUND;
+  SmramBase         = mCurrentSmramRange->CpuStart;
+  //
+  // Get PeHeader pointer
+  //
+  ImgHdr              = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+  SectionHeaderOffset = (UINTN)(
+                                ImageContext->PeCoffHeaderOffset +
+                                sizeof (UINT32) +
+                                sizeof (EFI_IMAGE_FILE_HEADER) +
+                                ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+                                );
+  NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+
+  //
+  // Get base address from the first section header that doesn't point to code section.
+  //
+  for (Index = 0; Index < NumberOfSections; Index++) {
+    //
+    // Read section header from file
+    //
+    Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
+    Status = ImageContext->ImageRead (
+                             ImageContext->Handle,
+                             SectionHeaderOffset,
+                             &Size,
+                             &SectionHeader
+                             );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Status = EFI_NOT_FOUND;
+
+    if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+      //
+      // Build tool saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the
+      // first section header that doesn't point to code section in image header. And there is an assumption that when the
+      // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers
+      // fields should NOT be Zero, or else, these 2 fields should be set to Zero
+      //
+      ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
+      if (ValueInSectionHeader != 0) {
+        //
+        // Found first section header that doesn't point to code section in which build tool saves the
+        // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
+        //
+        FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader);
+
+        if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <= FixLoadingAddress)) {
+          //
+          // The assigned address is valid. Return the specified loading address
+          //
+          ImageContext->ImageAddress = FixLoadingAddress;
+          Status                     = EFI_SUCCESS;
+        }
+      }
+
+      break;
+    }
+
+    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+  }
+
+  DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status));
+  return Status;
+}
+
+/**
+  Searches all the available firmware volumes and returns the first matching FFS section.
+
+  This function searches all the firmware volumes for FFS files with FV file type specified by FileType
+  The order that the firmware volumes is searched is not deterministic. For each available FV a search
+  is made for FFS file of type FileType. If the FV contains more than one FFS file with the same FileType,
+  the FileInstance instance will be the matched FFS file. For each FFS file found a search
+  is made for FFS sections of type SectionType. If the FFS file contains at least SectionInstance instances
+  of the FFS section specified by SectionType, then the SectionInstance instance is returned in Buffer.
+  Buffer is allocated using AllocatePool(), and the size of the allocated buffer is returned in Size.
+  It is the caller's responsibility to use FreePool() to free the allocated buffer.
+
+  If Buffer is NULL, then ASSERT().
+  If Size is NULL, then ASSERT().
+
+  @param  FileType             Indicates the FV file type to search for within all available FVs.
+  @param  FileInstance         Indicates which file instance within all available FVs specified by FileType.
+                               FileInstance starts from zero.
+  @param  SectionType          Indicates the FFS section type to search for within the FFS file
+                               specified by FileType with FileInstance.
+  @param  SectionInstance      Indicates which section instance within the FFS file
+                               specified by FileType with FileInstance to retrieve. SectionInstance starts from zero.
+  @param  Buffer               On output, a pointer to a callee allocated buffer containing the FFS file section that was found.
+                               Is it the caller's responsibility to free this buffer using FreePool().
+  @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
+
+  @retval  EFI_SUCCESS          The specified FFS section was returned.
+  @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
+  @retval  EFI_OUT_OF_RESOURCES There are not enough resources available to retrieve the matching FFS section.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSectionFromAnyFvByFileType  (
+  IN  EFI_FV_FILETYPE   FileType,
+  IN  UINTN             FileInstance,
+  IN  EFI_SECTION_TYPE  SectionType,
+  IN  UINTN             SectionInstance,
+  OUT VOID              **Buffer,
+  OUT UINTN             *Size
+  )
+{
+  EFI_STATUS           Status;
+  UINTN                FvIndex;
+  EFI_PEI_FV_HANDLE    VolumeHandle;
+  EFI_PEI_FILE_HANDLE  FileHandle;
+  EFI_PE32_SECTION     *SectionData;
+  UINT32               SectionSize;
+
+  //
+  // Search all FV
+  //
+  VolumeHandle = NULL;
+  for (FvIndex = 0; ; FvIndex++) {
+    Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    //
+    // Search PEIM FFS
+    //
+    FileHandle = NULL;
+    Status     = PeiServicesFfsFindNextFile (FileType, VolumeHandle, &FileHandle);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    //
+    // Search Section
+    //
+    SectionData = NULL;
+    Status      = PeiServicesFfsFindSectionData (SectionType, FileHandle, Buffer);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    //
+    // Great!
+    //
+    SectionData = (EFI_PE32_SECTION *)((UINT8 *)*Buffer - sizeof (EFI_PE32_SECTION));
+    ASSERT (SectionData->Type == SectionType);
+    SectionSize  = *(UINT32 *)SectionData->Size;
+    SectionSize &= 0xFFFFFF;
+    *Size        = SectionSize - sizeof (EFI_PE32_SECTION);
+
+    if (FileType == EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
+      EFI_FV_INFO  VolumeInfo;
+      //
+      // This is SMM BFV
+      //
+      Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
+      if (!EFI_ERROR (Status)) {
+        gMmCorePrivate->StandaloneBfvAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
+      }
+    }
+
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.
+
+  @param[in, out] SmramRange            Descriptor for the range of SMRAM to reload the
+                                        currently executing image, the rang of SMRAM to
+                                        hold SMM Core will be excluded.
+  @param[in, out] SmramRangeSmmCore     Descriptor for the range of SMRAM to hold SMM Core.
+
+  @param[in]      Context               Context to pass into SMM Core
+
+  @return  EFI_STATUS
+
+**/
+EFI_STATUS
+ExecuteSmmCoreFromSmram (
+  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRange,
+  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRangeSmmCore,
+  IN     VOID                  *Context
+  )
+{
+  EFI_STATUS                    Status;
+  VOID                          *SourceBuffer;
+  UINTN                         SourceSize;
+  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
+  UINTN                         PageCount;
+  VOID                          *HobList;
+
+  Status = PeiServicesGetHobList (&HobList);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
+  //
+  Status = GetSectionFromAnyFvByFileType (
+             EFI_FV_FILETYPE_MM_CORE_STANDALONE,
+             0,
+             EFI_SECTION_PE32,
+             0,
+             &SourceBuffer,
+             &SourceSize
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Initialize ImageContext
+  //
+  ImageContext.Handle    = SourceBuffer;
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+  //
+  // Get information about the image being loaded
+  //
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to
+  // the address assigned by build tool.
+  //
+  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
+    //
+    // Get the fixed loading address assigned by Build tool
+    //
+    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
+    if (!EFI_ERROR (Status)) {
+      //
+      // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
+      //
+      PageCount = 0;
+      //
+      // Reserved Smram Region for SmmCore is not used, and remove it from SmramRangeCount.
+      //
+      gMmCorePrivate->MmramRangeCount--;
+    } else {
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
+      //
+      // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
+      // specified by SmramRange
+      //
+      PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+
+      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
+      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
+
+      SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
+      SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart + SmramRange->PhysicalSize;
+      SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
+      SmramRangeSmmCore->RegionState   = SmramRange->RegionState | EFI_ALLOCATED;
+      SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
+
+      //
+      // Align buffer on section boundary
+      //
+      ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
+    }
+  } else {
+    //
+    // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
+    // specified by SmramRange
+    //
+    PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
+
+    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
+    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
+
+    SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
+    SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart + SmramRange->PhysicalSize;
+    SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
+    SmramRangeSmmCore->RegionState   = SmramRange->RegionState | EFI_ALLOCATED;
+    SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
+
+    //
+    // Align buffer on section boundary
+    //
+    ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
+  }
+
+  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+
+  //
+  // Print debug message showing SMM Core load address.
+  //
+  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
+
+  //
+  // Load the image to our new buffer
+  //
+  Status = PeCoffLoaderLoadImage (&ImageContext);
+  if (!EFI_ERROR (Status)) {
+    //
+    // Relocate the image in our new buffer
+    //
+    Status = PeCoffLoaderRelocateImage (&ImageContext);
+    if (!EFI_ERROR (Status)) {
+      //
+      // Flush the instruction cache so the image data are written before we execute it
+      //
+      InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+      //
+      // Print debug message showing SMM Core entry point address.
+      //
+      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
+
+      gMmCorePrivate->MmCoreImageBase = ImageContext.ImageAddress;
+      gMmCorePrivate->MmCoreImageSize = ImageContext.ImageSize;
+      DEBUG ((DEBUG_INFO, "SmmCoreImageBase - 0x%016lx\n", gMmCorePrivate->MmCoreImageBase));
+      DEBUG ((DEBUG_INFO, "SmmCoreImageSize - 0x%016lx\n", gMmCorePrivate->MmCoreImageSize));
+
+      gMmCorePrivate->MmCoreEntryPoint = ImageContext.EntryPoint;
+
+      //
+      // Print debug message showing Standalone MM Core entry point address.
+      //
+      DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
+
+      //
+      // Execute image
+      //
+      LoadSmmCore (ImageContext.EntryPoint, HobList);
+    }
+  }
+
+  //
+  // If the load operation, relocate operation, or the image execution return an
+  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by
+  // SmramRange
+  //
+  if (EFI_ERROR (Status)) {
+    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
+  }
+
+  //
+  // Always free memory allocated by GetFileBufferByFilePath ()
+  //
+  FreePool (SourceBuffer);
+
+  return Status;
+}
+
+/**
+  Get full SMRAM ranges.
+
+  It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved ranges from
+  SmmConfiguration protocol, split the entries if there is overlap between them.
+  It will also reserve one entry for SMM core.
+
+  @param[in]  PeiServices           Describes the list of possible PEI Services.
+  @param[out] FullSmramRangeCount   Output pointer to full SMRAM range count.
+
+  @return Pointer to full SMRAM ranges.
+
+**/
+EFI_SMRAM_DESCRIPTOR *
+GetFullSmramRanges (
+  IN  CONST EFI_PEI_SERVICES  **PeiServices,
+  OUT       UINTN             *FullSmramRangeCount
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 Size;
+  EFI_SMRAM_DESCRIPTOR  *FullSmramRanges;
+  UINTN                 AdditionSmramRangeCount;
+  UINTN                 SmramRangeCount;
+
+  //
+  // Get SMRAM information.
+  //
+  Size   = 0;
+  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices, mSmmAccess, &Size, NULL);
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+  SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
+
+  //
+  // Reserve one entry SMM Core in the full SMRAM ranges.
+  //
+  AdditionSmramRangeCount = 1;
+  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
+    //
+    // Reserve two entries for all SMM drivers & SMM Core in the full SMRAM ranges.
+    //
+    AdditionSmramRangeCount = 2;
+  }
+
+  *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
+  Size                 = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);
+  FullSmramRanges      = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
+  ASSERT (FullSmramRanges != NULL);
+  if (FullSmramRanges == NULL) {
+    return NULL;
+  }
+
+  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices, mSmmAccess, &Size, FullSmramRanges);
+
+  ASSERT_EFI_ERROR (Status);
+
+  return FullSmramRanges;
+}
+
+/**
+  The Entry Point for SMM IPL
+
+  Load SMM Core into SMRAM.
+
+  @param  FileHandle  Handle of the file being invoked.
+  @param  PeiServices Describes the list of possible PEI Services.
+
+  @retval EFI_SUCCESS    The entry point is executed successfully.
+  @retval Other          Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmIplEntry (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS             Status;
+  UINTN                  Index;
+  UINT64                 MaxSize;
+  UINT64                 SmmCodeSize;
+  MM_CORE_DATA_HOB_DATA  SmmCoreDataHobData;
+  EFI_SMRAM_DESCRIPTOR   *MmramRanges;
+  EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmDriver;
+
+  //
+  // Build Hob for SMM and DXE phase
+  //
+  SmmCoreDataHobData.Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES (sizeof (mMmCorePrivateData)));
+  ASSERT (SmmCoreDataHobData.Address != 0);
+  gMmCorePrivate = (VOID *)(UINTN)SmmCoreDataHobData.Address;
+  CopyMem ((VOID *)(UINTN)SmmCoreDataHobData.Address, &mMmCorePrivateData, sizeof (mMmCorePrivateData));
+  DEBUG ((DEBUG_INFO, "gMmCorePrivate - 0x%x\n", gMmCorePrivate));
+
+  BuildGuidDataHob (
+    &gMmCoreDataHobGuid,
+    (VOID *)&SmmCoreDataHobData,
+    sizeof (SmmCoreDataHobData)
+    );
+
+  //
+  // Get SMM Access Protocol
+  //
+  Status = PeiServicesLocatePpi (&gPeiSmmAccessPpiGuid, 0, NULL, (VOID **)&mSmmAccess);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Get SMRAM information
+  //
+  gMmCorePrivate->MmramRanges = (EFI_PHYSICAL_ADDRESS)(UINTN)GetFullSmramRanges (PeiServices, (UINTN *)&gMmCorePrivate->MmramRangeCount);
+  ASSERT (gMmCorePrivate->MmramRanges != 0);
+  if (gMmCorePrivate->MmramRanges == 0) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Open all SMRAM ranges
+  //
+  Status = mSmmAccess->Open ((EFI_PEI_SERVICES **)PeiServices, mSmmAccess, 0);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Print debug message that the SMRAM window is now open.
+  //
+  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
+
+  //
+  // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
+  //
+  mCurrentSmramRange = NULL;
+  MmramRanges        = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;
+  if (MmramRanges == NULL) {
+    DEBUG ((DEBUG_ERROR, "Fail to retrieve MmramRanges\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gMmCorePrivate->MmramRangeCount; Index++) {
+    //
+    // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
+    //
+    if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+      continue;
+    }
+
+    if (MmramRanges[Index].CpuStart >= BASE_1MB) {
+      if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize) <= BASE_4GB) {
+        if (MmramRanges[Index].PhysicalSize >= MaxSize) {
+          MaxSize            = MmramRanges[Index].PhysicalSize;
+          mCurrentSmramRange = &MmramRanges[Index];
+        }
+      }
+    }
+  }
+
+  if (mCurrentSmramRange != NULL) {
+    //
+    // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core
+    //
+    DEBUG ((
+      DEBUG_INFO,
+      "SMM IPL found SMRAM window %p - %p\n",
+      (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
+      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)
+      ));
+
+    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);
+
+    //
+    // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load
+    // Modules At Fixed Address Configuration Table.
+    //
+    if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
+      //
+      // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
+      //
+      SmmCodeSize = LShiftU64 (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
+      //
+      // The SMRAM available memory is assumed to be larger than SmmCodeSize
+      //
+      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
+      //
+      // Fill the Smram range for all SMM code
+      //
+      MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges;
+      //
+      // Note: SmramRanges specific for all SMM code will put in the gMmCorePrivate->MmramRangeCount - 2.
+      //
+      SmramRangeSmmDriver                = &MmramRanges[gMmCorePrivate->MmramRangeCount - 2];
+      SmramRangeSmmDriver->CpuStart      = mCurrentSmramRange->CpuStart;
+      SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange->PhysicalStart;
+      SmramRangeSmmDriver->RegionState   = mCurrentSmramRange->RegionState | EFI_ALLOCATED;
+      SmramRangeSmmDriver->PhysicalSize  = SmmCodeSize;
+
+      mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
+      mCurrentSmramRange->CpuStart      = mCurrentSmramRange->CpuStart + SmmCodeSize;
+      mCurrentSmramRange->PhysicalStart = mCurrentSmramRange->PhysicalStart + SmmCodeSize;
+    }
+
+    //
+    // Load SMM Core into SMRAM and execute it from SMRAM
+    // Note: SmramRanges specific for SMM Core will put in the gMmCorePrivate->MmramRangeCount - 1.
+    //
+    Status = ExecuteSmmCoreFromSmram (
+               mCurrentSmramRange,
+               &(((EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate->MmramRanges)[gMmCorePrivate->MmramRangeCount - 1]),
+               gMmCorePrivate
+               );
+    if (EFI_ERROR (Status)) {
+      //
+      // Print error message that the SMM Core failed to be loaded and executed.
+      //
+      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));
+    }
+  } else {
+    //
+    // Print error message that there are not enough SMRAM resources to load the SMM Core.
+    //
+    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));
+  }
+
+  //
+  // If the SMM Core could not be loaded then close SMRAM window, free allocated
+  // resources, and return an error so SMM IPL will be unloaded.
+  //
+  if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
+    //
+    // Close all SMRAM ranges
+    //
+    Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices, mSmmAccess, 0);
+    ASSERT_EFI_ERROR (Status);
+
+    //
+    // Print debug message that the SMRAM window is now closed.
+    //
+    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
+
+    //
+    // Free all allocated resources
+    //
+    FreePool ((VOID *)(UINTN)gMmCorePrivate->MmramRanges);
+
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Create ready to boot for close and lock smram ranges
+  //
+  Status = PeiServicesNotifyPpi (&mReadyToBootNotifyList);
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
new file mode 100644
index 0000000000..6d3497f2ea
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
@@ -0,0 +1,32 @@
+/** @file
+  SMM IPL that load the SMM Core into SMRAM
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <PiSmm.h>
+#include <StandaloneMm.h>
+
+/**
+  Load SMM core to dispatch other Standalone MM drivers.
+
+  @param  Entry                     Entry of Standalone MM Foundation.
+  @param  Context1                  A pointer to the context to pass into the EntryPoint
+                                    function.
+  @retval EFI_SUCCESS               Successfully loaded SMM core.
+  @retval Others                    Failed to load SMM core.
+**/
+EFI_STATUS
+LoadSmmCore (
+  IN EFI_PHYSICAL_ADDRESS  Entry,
+  IN VOID                  *Context1
+  )
+{
+  STANDALONE_MM_FOUNDATION_ENTRY_POINT  EntryPoint;
+
+  EntryPoint = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
+  return EntryPoint (Context1);
+}
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
new file mode 100644
index 0000000000..7f887eb77d
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
@@ -0,0 +1,148 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+;    Thunk32To64.nasm
+;
+; Abstract:
+;
+;   This is the assembly code to transition from long mode to compatibility
+;   mode to execute 32-bit code and then transit back to long mode.
+;
+;------------------------------------------------------------------------------
+
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; Procedure:    AsmExecute64BitCode
+;
+; Input:        None
+;
+; Output:       None
+;
+; Prototype:    UINT32
+;               AsmExecute64BitCode (
+;                 IN UINT64           Function,
+;                 IN UINT64           Param1,
+;                 IN UINT64           Param2,
+;                 IN IA32_DESCRIPTOR  *InternalGdtr
+;                 );
+;
+;
+; Description:  A thunk function to execute 32-bit code in long mode.
+;
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmExecute64BitCode)
+ASM_PFX(AsmExecute64BitCode):
+;
+; +---------+
+; | EIP(64) |
+; +---------+
+; | CS (64) |
+; +---------+
+; | EIP(32) |
+; +---------+
+; | CS (32) |<-ESP (16 bytes aligned)
+; +---------+
+; | ...     |
+; +---------+
+; | ebx     |<-EBP
+; +---------+
+; | ebp     |<-EBP + 4
+; +---------+
+; | esi     |<-EBP + 8
+; +---------+
+; | edi     |<-EBP + 12
+; +---------+
+; | RFlags  |<-EBP + 16
+; +---------+
+; | RetAddr |<-EBP (org)
+; +---------+
+; | Func    |<-EBP + 24
+; | Func    |
+; +---------+
+; | Param1  |<-EBP + 32
+; | Param1  |
+; +---------+
+; | Param2  |<-EBP + 40
+; | Param2  |
+; +---------+
+; | Gdtr    |
+; +---------+
+;
+    ;
+    ; Save general purpose register and RFlags register
+    ;
+    pushfd
+    push    edi
+    push    esi
+    push    ebp
+    push    ebx
+    mov     ebp, esp
+
+    and     esp, 0FFFFFFF0h
+
+    push    010h                        ; protected mode selector on stack
+    mov     eax, Compatible             ; offset for LongMode
+    push    eax                         ; offset on stack
+
+    push    038h                        ; long mode selector on stack
+    mov     eax, LongMode               ; offset for LongMode
+    push    eax                         ; offset on stack
+
+    mov     eax, cr4
+    or      al, 020h
+    mov     cr4, eax                    ; enable PAE
+    mov     ecx, 0c0000080h
+    rdmsr
+    or      ah, 1                       ; set LME
+    wrmsr
+    mov     eax, cr0
+    bts     eax, 31                     ; set PG
+    mov     cr0, eax                    ; enable paging
+    retf                                ; topmost 2 dwords hold the address
+LongMode:                               ; long mode starts here
+
+    ; Call long mode function
+    DB      67h, 48h                    ; 32-bit address size, 64-bit operand size
+    mov     eax, [ebp + 24]             ; mov rbx, [ebp + 24]
+    DB      67h, 48h
+    mov     ecx, [ebp + 24 + 8]         ; mov rcx, [ebp + 24 + 8]
+    DB      67h, 48h
+    mov     edx, [ebp + 24 + 16]        ; mov rdx, [ebp + 24 + 16]
+
+    DB      48h
+    add     esp, -20h                   ; add rsp, -20h
+    call    eax                         ; call rax
+    DB      48h
+    add     esp, 20h                    ; add rsp, 20h
+
+    ; after long mode function call
+    mov     ebx, eax
+
+    retf
+Compatible:
+    mov     ecx, cr0
+    btc     ecx, 31                     ; clear PG
+    mov     cr0, ecx                    ; disable paging
+    mov     ecx, 0C0000080h
+    rdmsr
+    btc     eax, 8                      ; clear LME
+    wrmsr
+
+    ;
+    ; Restore C register and eax hold the return status from 32-bit function.
+    ; Note: Do not touch rax from now which hold the return value from IA32 function
+    ;
+    mov     eax, ebx                    ; put return status to EAX
+    mov     esp, ebp                    ; restore stack pointer
+    pop     ebx
+    pop     ebp
+    pop     esi
+    pop     edi
+    popfd
+
+    ret
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
new file mode 100644
index 0000000000..be0aae70f0
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
@@ -0,0 +1,66 @@
+/** @file
+  Private header with declarations and definitions specific to the Standalone
+  MM IPL PEI driver
+
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef STANDALONE_MM_IPL_PEI_H_
+#define STANDALONE_MM_IPL_PEI_H_
+
+/**
+  Load SMM core to dispatch other Standalone MM drivers.
+
+  @param  Entry                     Entry of Standalone MM Foundation.
+  @param  Context1                  A pointer to the context to pass into the EntryPoint
+                                    function.
+  @retval EFI_SUCCESS               Successfully loaded SMM core.
+  @retval Others                    Failed to load SMM core.
+**/
+EFI_STATUS
+LoadSmmCore (
+  IN EFI_PHYSICAL_ADDRESS  Entry,
+  IN VOID                  *Context1
+  );
+
+/**
+  Assembly function to transition from long mode to compatibility mode to
+  execute 32-bit code and then transit back to long mode.
+
+  @param[in] Function     The 32bit code entry to be executed.
+  @param[in] Param1       The first parameter to pass to 32bit code
+  @param[in] Param2       The second parameter to pass to 32bit code
+  @param[in] InternalGdtr The GDT and GDT descriptor used by this library
+
+  @retval status.
+**/
+UINT32
+AsmExecute64BitCode (
+  IN UINT64           Function,
+  IN UINT64           Param1,
+  IN UINT64           Param2,
+  IN IA32_DESCRIPTOR  *InternalGdtr
+  );
+
+/**
+  This is the callback function on ready to boot.
+
+  Close and lock smram ranges on ready to boot stage.
+
+  @param   PeiServices       General purpose services available to every PEIM.
+  @param   NotifyDescriptor  The notification structure this PEIM registered on install.
+  @param   Ppi               Pointer to the PPI data associated with this function.
+  @retval  EFI_SUCCESS       Close and lock smram ranges successfully.
+  @retval  Other             Close and lock smram ranges failed.
+**/
+EFI_STATUS
+EFIAPI
+ReadyToBootEvent (
+  IN  EFI_PEI_SERVICES           **PeiServices,
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN  VOID                       *Ppi
+  );
+
+#endif
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
new file mode 100644
index 0000000000..ff4c67a92c
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
@@ -0,0 +1,75 @@
+## @file
+#  This module provide a Standalone SMM compliant implementation of SMM IPL PEIM.
+#
+#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = StandaloneMmIplPei
+  FILE_GUID                      = 578A0D17-2DC0-4C7D-A121-D8D771923BB0
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x0001000A
+  ENTRY_POINT                    = SmmIplEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  StandaloneMmIplPei.h
+  StandaloneMmIplPei.c
+
+[Sources.Ia32]
+  Ia32/LoadSmmCore.c
+  Ia32/Thunk32To64.nasm
+
+[Sources.X64]
+  X64/LoadSmmCore.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+  PeimEntryPoint
+  PeiServicesTablePointerLib
+  PeiServicesLib
+  BaseLib
+  BaseMemoryLib
+  PeCoffLib
+  CacheMaintenanceLib
+  MemoryAllocationLib
+  DebugLib
+  HobLib
+  IntrinsicLib
+
+[Guids]
+  gMmCoreDataHobGuid
+  gEfiEventReadyToBootGuid
+
+[Ppis]
+  gPeiSmmAccessPpiGuid                     ## CONSUMES
+  gPeiSmmControlPpiGuid                    ## CONSUMES
+
+[FeaturePcd.IA32]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ## CONSUMES
+
+[Pcd.IA32]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ## SOMETIMES_CONSUMES
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber     ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable        ## CONSUMES
+
+[Depex]
+  gPeiSmmAccessPpiGuid AND
+  gPeiSmmControlPpiGuid
+
diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
index 4777532a7e..872f7958be 100644
--- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
+++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
@@ -78,7 +78,9 @@
     ## options defined .pytool/Plugin/SpellCheck
     "SpellCheck": {
         "AuditOnly": False,
-        "IgnoreFiles": [],           # use gitignore syntax to ignore errors
+        "IgnoreFiles": [
+            "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm"
+        ],           # use gitignore syntax to ignore errors
                                      # in matching files
         "ExtendWords": [
             "Bsymbolic",
diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc b/StandaloneMmPkg/StandaloneMmPkg.dsc
index 8012f93b7d..d88471fe82 100644
--- a/StandaloneMmPkg/StandaloneMmPkg.dsc
+++ b/StandaloneMmPkg/StandaloneMmPkg.dsc
@@ -20,7 +20,7 @@
   PLATFORM_VERSION               = 1.0
   DSC_SPECIFICATION              = 0x00010011
   OUTPUT_DIRECTORY               = Build/StandaloneMm
-  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM
+  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM|IA32
   BUILD_TARGETS                  = DEBUG|RELEASE
   SKUID_IDENTIFIER               = DEFAULT
 
@@ -60,6 +60,14 @@
   StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
   VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf
 
+[LibraryClasses.common.PEIM]
+  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+  MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+  PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+
 [LibraryClasses.AARCH64, LibraryClasses.ARM]
   ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
   StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
@@ -104,7 +112,7 @@
 #       generated for it, but the binary will not be put into any firmware volume.
 #
 ###################################################################################################
-[Components.common]
+[Components.AARCH64, Components.ARM, Components.X64]
   #
   # MM Core
   #
@@ -122,6 +130,9 @@
   StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
   StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf
 
+[Components.X64, Components.IA32]
+  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
+
 ###################################################################################################
 #
 # BuildOptions Section - Define the module specific tool chain flags that should be used as
diff --git a/UefiPayloadPkg/UniversalPayloadBuild.sh b/UefiPayloadPkg/UniversalPayloadBuild.sh
index 9a72eedd35..bacf5233a8 100644
--- a/UefiPayloadPkg/UniversalPayloadBuild.sh
+++ b/UefiPayloadPkg/UniversalPayloadBuild.sh
@@ -1,17 +1,17 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
-    echo python_exe=${PYTHON_COMMAND}
-fi
-
-# Get file path of UniversalPayloadBuild.sh
-uplbld_filepath=${BASH_SOURCE:-$0}
-# Remove ".sh" extension
-uplbld_filepath_noext=${uplbld_filepath%.*}
-# execute UniversalPayloadBuild.py to build UefiPayloadPkg
-exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
+#!/usr/bin/env bash
+#
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
+    echo python_exe=${PYTHON_COMMAND}
+fi
+
+# Get file path of UniversalPayloadBuild.sh
+uplbld_filepath=${BASH_SOURCE:-$0}
+# Remove ".sh" extension
+uplbld_filepath_noext=${uplbld_filepath%.*}
+# execute UniversalPayloadBuild.py to build UefiPayloadPkg
+exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
diff --git a/edksetup.sh b/edksetup.sh
index cab3a8c113..553e1676d0 100755
--- a/edksetup.sh
+++ b/edksetup.sh
@@ -1,147 +1,147 @@
-#
-# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
-# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-# In *inux environment, the build tools's source is required and need to be compiled
-# firstly, please reference https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-Github-Quick-Start
-# to get how to setup build tool.
-#
-# Setup the environment for unix-like systems running a bash-like shell.
-# This file must be "sourced" not merely executed. For example: ". edksetup.sh"
-#
-# CYGWIN users: Your path and filename related environment variables should be
-# set up in the unix style.  This script will make the necessary conversions to
-# windows style.
-#
-# Please reference edk2 user manual for more detail descriptions at https://github.com/tianocore-docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
-#
-
-SCRIPTNAME="edksetup.sh"
-RECONFIG=FALSE
-
-HelpMsg()
-{
-  echo "Usage: $SCRIPTNAME [Options]"
-  echo
-  echo "The system environment variable, WORKSPACE, is always set to the current"
-  echo "working directory."
-  echo
-  echo "Options: "
-  echo "  --help, -h, -?        Print this help screen and exit."
-  echo
-  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with the"
-  echo "                        template files from the BaseTools/Conf directory."
-  echo
-  echo Please note: This script must be \'sourced\' so the environment can be changed.
-  echo ". $SCRIPTNAME"
-  echo "source $SCRIPTNAME"
-}
-
-SetWorkspace()
-{
-  #
-  # If WORKSPACE is already set, then we can return right now
-  #
-  export PYTHONHASHSEED=1
-  if [ -n "$WORKSPACE" ]
-  then
-    return 0
-  fi
-
-  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
-  then
-    echo Source this script from the base of your tree.  For example:
-    echo "  cd /Path/To/Edk2/Clone"
-    echo "  . $SCRIPTNAME"
-    return 1
-  fi
-
-  #
-  # Check for BaseTools/BuildEnv before dirtying the user's environment.
-  #
-  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
-  then
-    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
-    echo Please point EDK_TOOLS_PATH at the directory that contains
-    echo the EDK2 BuildEnv script.
-    return 1
-  fi
-
-  #
-  # Set $WORKSPACE
-  #
-  export WORKSPACE=$PWD
-  return 0
-}
-
-SetupEnv()
-{
-  if [ -n "$EDK_TOOLS_PATH" ]
-  then
-    . $EDK_TOOLS_PATH/BuildEnv
-  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
-  then
-    . $WORKSPACE/BaseTools/BuildEnv
-  elif [ -n "$PACKAGES_PATH" ]
-  then
-    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
-    do
-      if [ -f "$DIR/BaseTools/BuildEnv" ]
-      then
-        export EDK_TOOLS_PATH=$DIR/BaseTools
-        . $DIR/BaseTools/BuildEnv
-        break
-      fi
-    done
-  else
-    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
-    echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly
-    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
-    echo the EDK2 BuildEnv script.
-    return 1
-  fi
-}
-
-SetupPython3()
-{
-  export PYTHON_COMMAND=python3
-}
-
-SourceEnv()
-{
-  SetupPython3
-  SetWorkspace
-  SetupEnv
-}
-
-I=$#
-while [ $I -gt 0 ]
-do
-  case "$1" in
-    BaseTools)
-      # Ignore argument for backwards compatibility
-      shift
-    ;;
-    --reconfig)
-      RECONFIG=TRUE
-      shift
-    ;;
-    *)
-      HelpMsg
-      break
-    ;;
-  esac
-  I=$((I - 1))
-done
-
-if [ $I -gt 0 ]
-then
-  return 1
-fi
-
-SourceEnv
-
-unset SCRIPTNAME RECONFIG
-
-return $?
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# In *inux environment, the build tools's source is required and need to be compiled
+# firstly, please reference https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-Github-Quick-Start
+# to get how to setup build tool.
+#
+# Setup the environment for unix-like systems running a bash-like shell.
+# This file must be "sourced" not merely executed. For example: ". edksetup.sh"
+#
+# CYGWIN users: Your path and filename related environment variables should be
+# set up in the unix style.  This script will make the necessary conversions to
+# windows style.
+#
+# Please reference edk2 user manual for more detail descriptions at https://github.com/tianocore-docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
+#
+
+SCRIPTNAME="edksetup.sh"
+RECONFIG=FALSE
+
+HelpMsg()
+{
+  echo "Usage: $SCRIPTNAME [Options]"
+  echo
+  echo "The system environment variable, WORKSPACE, is always set to the current"
+  echo "working directory."
+  echo
+  echo "Options: "
+  echo "  --help, -h, -?        Print this help screen and exit."
+  echo
+  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with the"
+  echo "                        template files from the BaseTools/Conf directory."
+  echo
+  echo Please note: This script must be \'sourced\' so the environment can be changed.
+  echo ". $SCRIPTNAME"
+  echo "source $SCRIPTNAME"
+}
+
+SetWorkspace()
+{
+  #
+  # If WORKSPACE is already set, then we can return right now
+  #
+  export PYTHONHASHSEED=1
+  if [ -n "$WORKSPACE" ]
+  then
+    return 0
+  fi
+
+  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
+  then
+    echo Source this script from the base of your tree.  For example:
+    echo "  cd /Path/To/Edk2/Clone"
+    echo "  . $SCRIPTNAME"
+    return 1
+  fi
+
+  #
+  # Check for BaseTools/BuildEnv before dirtying the user's environment.
+  #
+  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
+  then
+    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
+    echo Please point EDK_TOOLS_PATH at the directory that contains
+    echo the EDK2 BuildEnv script.
+    return 1
+  fi
+
+  #
+  # Set $WORKSPACE
+  #
+  export WORKSPACE=$PWD
+  return 0
+}
+
+SetupEnv()
+{
+  if [ -n "$EDK_TOOLS_PATH" ]
+  then
+    . $EDK_TOOLS_PATH/BuildEnv
+  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
+  then
+    . $WORKSPACE/BaseTools/BuildEnv
+  elif [ -n "$PACKAGES_PATH" ]
+  then
+    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
+    do
+      if [ -f "$DIR/BaseTools/BuildEnv" ]
+      then
+        export EDK_TOOLS_PATH=$DIR/BaseTools
+        . $DIR/BaseTools/BuildEnv
+        break
+      fi
+    done
+  else
+    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
+    echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly
+    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
+    echo the EDK2 BuildEnv script.
+    return 1
+  fi
+}
+
+SetupPython3()
+{
+  export PYTHON_COMMAND=python3
+}
+
+SourceEnv()
+{
+  SetupPython3
+  SetWorkspace
+  SetupEnv
+}
+
+I=$#
+while [ $I -gt 0 ]
+do
+  case "$1" in
+    BaseTools)
+      # Ignore argument for backwards compatibility
+      shift
+    ;;
+    --reconfig)
+      RECONFIG=TRUE
+      shift
+    ;;
+    *)
+      HelpMsg
+      break
+    ;;
+  esac
+  I=$((I - 1))
+done
+
+if [ $I -gt 0 ]
+then
+  return 1
+fi
+
+SourceEnv
+
+unset SCRIPTNAME RECONFIG
+
+return $?
-- 
2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105142): https://edk2.groups.io/g/devel/message/105142
Mute This Topic: https://groups.io/mt/99079640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
Posted by Ni, Ray 10 months, 3 weeks ago
Hongbin,
The patch is so big. Can you please split the patch to small patches? For example:
1st patch only implements the Ipl entrypoint to find the correct SMRAM range and dump it
2nd patch loads SMM CORE without mode switch if sizeof (UINTN) matches SMM core module type.
3rd patch loads SMM CORE with mode switch if sizeof (UINTN) == 4 but SMM core module type is 64bit.
4th patch Deadloop() when sizeof (UINTN) == 8 but SMM core module type is 32bit.
5th patch register ReadyToBoot callback. But is it too late from security perspective? Why not lock after SMM core exit? @Yao, Jiewen

Back to the code content, 3 comments:
1. Have you tested the flow when LoadImageAtFixedAddress is enabled? If no, I prefer you do not add the logic at all in the first version. We can enable that later.
2. "EFIAPI" for GetSectionFromAnyFvByFileType should be removed. And the function prototype could be refined as below:
    EFI_STATUS
    LocateMmFvAndCore
      OUT EFI_PHYSICAL_ADDRESS  *MmFvBaseAddress,
      OUT VOID                  **MmCoreImageAddress
    Please avoid directly modifying global variables inside this function.

3. Can the StandaloneMmCore in open source be directly used with this IPL? 

Thanks,
Ray


> -----Original Message-----
> From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> Sent: Monday, May 22, 2023 1:21 PM
> To: devel@edk2.groups.io
> Cc: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Yao, Jiewen
> <jiewen.yao@intel.com>; Ni, Ray <ray.ni@intel.com>; Zeng, Star
> <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar
> <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> Subject: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Add StandaloneMmIplPei IA32/X64 driver at PEI stage.
> FSP will use this driver to load Standalone MM code
> to dispatch other Standalone MM drivers.
> 
> Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> ---
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     | 456
> ++++++++++++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   | 787
> ++++++++++++++++++++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |  32 +
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  | 148
> ++++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66
> ++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |  75
> ++
>  StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
>  StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
>  UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
>  edksetup.sh                                                       | 294 ++++----
>  10 files changed, 1744 insertions(+), 167 deletions(-)
> 
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> new file mode 100644
> index 0000000000..d6174d73a3
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> @@ -0,0 +1,456 @@
> +/** @file
> +  SMM IPL that load the SMM Core into SMRAM
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <PiSmm.h>
> +#include <StandaloneMm.h>
> +#include <Library/HobLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <StandaloneMmIplPei.h>
> +
> +#pragma pack(1)
> +
> +//
> +// Page-Map Level-4 Offset (PML4) and
> +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
> +//
> +
> +typedef union {
> +  struct {
> +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> memory
> +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through
> caching
> +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
> +    UINT64    Reserved             : 1;   // Reserved
> +    UINT64    MustBeZero           : 2;   // Must Be Zero
> +    UINT64    Available            : 3;   // Available for use by system software
> +    UINT64    PageTableBaseAddress : 40;  // Page Table Base Address
> +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> +    UINT64    Nx                   : 1;   // No Execute bit
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_MAP_AND_DIRECTORY_POINTER;
> +
> +//
> +// Page Table Entry 2MB
> +//
> +typedef union {
> +  struct {
> +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> memory
> +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through
> caching
> +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
> +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> access to page
> +    UINT64    MustBe1              : 1;   // Must be 1
> +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB not
> cleared on CR3 write
> +    UINT64    Available            : 3;   // Available for use by system software
> +    UINT64    Pat                  : 1;   //
> +    UINT64    MustBeZero           : 8;   // Must be zero
> +    UINT64    PageTableBaseAddress : 31;  // Page Table Base Address
> +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_ENTRY;
> +
> +//
> +// Page Table Entry 1GB
> +//
> +typedef union {
> +  struct {
> +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> memory
> +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through
> caching
> +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
> +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> access to page
> +    UINT64    MustBe1              : 1;   // Must be 1
> +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB not
> cleared on CR3 write
> +    UINT64    Available            : 3;   // Available for use by system software
> +    UINT64    Pat                  : 1;   //
> +    UINT64    MustBeZero           : 17;  // Must be zero;
> +    UINT64    PageTableBaseAddress : 22;  // Page Table Base Address
> +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_1G_ENTRY;
> +
> +#pragma pack()
> +
> +//
> +// Global Descriptor Table (GDT)
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR
> mGdtEntries[] = {
> +  /* selector { Global Segment Descriptor                              } */
> +  /* 0x00 */ {
> +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> +  },                                                                      // null descriptor
> +  /* 0x08 */ {
> +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // linear data segment descriptor
> +  /* 0x10 */ {
> +    { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // linear code segment descriptor
> +  /* 0x18 */ {
> +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // system data segment descriptor
> +  /* 0x20 */ {
> +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // system code segment descriptor
> +  /* 0x28 */ {
> +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> +  },                                                                      // spare segment descriptor
> +  /* 0x30 */ {
> +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // system data segment descriptor
> +  /* 0x38 */ {
> +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
> +  },                                                                      // system code segment descriptor
> +  /* 0x40 */ {
> +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> +  },                                                                      // spare segment descriptor
> +};
> +
> +//
> +// IA32 Gdt register
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR  mGdt = {
> +  sizeof (mGdtEntries) - 1,
> +  (UINTN)mGdtEntries
> +};
> +
> +/**
> +  Calculate the total size of page table.
> +
> +  @return The size of page table.
> +
> +**/
> +UINTN
> +CalculatePageTableSize (
> +  VOID
> +  )
> +{
> +  UINT32   RegEax;
> +  UINT32   RegEdx;
> +  UINTN    TotalPagesNum;
> +  UINT8    PhysicalAddressBits;
> +  VOID     *Hob;
> +  UINT32   NumberOfPml4EntriesNeeded;
> +  UINT32   NumberOfPdpEntriesNeeded;
> +  BOOLEAN  Page1GSupport;
> +
> +  Page1GSupport = FALSE;
> +  if (PcdGetBool (PcdUse1GPageTable)) {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000001) {
> +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +      if ((RegEdx & BIT26) != 0) {
> +        Page1GSupport = TRUE;
> +      }
> +    }
> +  }
> +
> +  //
> +  // Get physical address bits supported.
> +  //
> +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> +  if (Hob != NULL) {
> +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> +  } else {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000008) {
> +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> +      PhysicalAddressBits = (UINT8)RegEax;
> +    } else {
> +      PhysicalAddressBits = 36;
> +    }
> +  }
> +
> +  //
> +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
> +  //
> +  ASSERT (PhysicalAddressBits <= 52);
> +  if (PhysicalAddressBits > 48) {
> +    PhysicalAddressBits = 48;
> +  }
> +
> +  //
> +  // Calculate the table entries needed.
> +  //
> +  if (PhysicalAddressBits <= 39 ) {
> +    NumberOfPml4EntriesNeeded = 1;
> +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 30));
> +  } else {
> +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 39));
> +    NumberOfPdpEntriesNeeded  = 512;
> +  }
> +
> +  if (!Page1GSupport) {
> +    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) *
> NumberOfPml4EntriesNeeded + 1;
> +  } else {
> +    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
> +  }
> +
> +  return EFI_PAGES_TO_SIZE (TotalPagesNum);
> +}
> +
> +/**
> +  Allocates and fills in the Page Directory and Page Table Entries to
> +  establish a 1:1 Virtual to Physical mapping.
> +
> +  @param[in]  PageTablesAddress  The base address of page table.
> +
> +**/
> +VOID
> +CreateIdentityMappingPageTables (
> +  IN  EFI_PHYSICAL_ADDRESS  PageTablesAddress
> +  )
> +{
> +  UINT32                          RegEax;
> +  UINT32                          RegEdx;
> +  UINT8                           PhysicalAddressBits;
> +  EFI_PHYSICAL_ADDRESS            PageAddress;
> +  UINTN                           IndexOfPml4Entries;
> +  UINTN                           IndexOfPdpEntries;
> +  UINTN                           IndexOfPageDirectoryEntries;
> +  UINT32                          NumberOfPml4EntriesNeeded;
> +  UINT32                          NumberOfPdpEntriesNeeded;
> +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
> +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMap;
> +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
> +  PAGE_TABLE_ENTRY                *PageDirectoryEntry;
> +  UINTN                           BigPageAddress;
> +  VOID                            *Hob;
> +  BOOLEAN                         Page1GSupport;
> +  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
> +
> +  Page1GSupport = FALSE;
> +  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +  if (RegEax >= 0x80000001) {
> +    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +    if ((RegEdx & BIT26) != 0) {
> +      Page1GSupport = TRUE;
> +    }
> +  }
> +
> +  //
> +  // Get physical address bits supported.
> +  //
> +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> +  if (Hob != NULL) {
> +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> +  } else {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000008) {
> +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> +      PhysicalAddressBits = (UINT8)RegEax;
> +    } else {
> +      PhysicalAddressBits = 36;
> +    }
> +  }
> +
> +  //
> +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
> +  //
> +  ASSERT (PhysicalAddressBits <= 52);
> +  if (PhysicalAddressBits > 48) {
> +    PhysicalAddressBits = 48;
> +  }
> +
> +  //
> +  // Calculate the table entries needed.
> +  //
> +  if (PhysicalAddressBits <= 39 ) {
> +    NumberOfPml4EntriesNeeded = 1;
> +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 30));
> +  } else {
> +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 39));
> +    NumberOfPdpEntriesNeeded  = 512;
> +  }
> +
> +  //
> +  // Pre-allocate big pages to avoid later allocations.
> +  //
> +  BigPageAddress = (UINTN)PageTablesAddress;
> +
> +  //
> +  // By architecture only one PageMapLevel4 exists - so lets allocate storage for
> it.
> +  //
> +  PageMap         = (VOID *)BigPageAddress;
> +  BigPageAddress += SIZE_4KB;
> +
> +  PageMapLevel4Entry = PageMap;
> +  PageAddress        = 0;
> +  for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
> +    //
> +    // Each PML4 entry points to a page of Page Directory Pointer entires.
> +    // So lets allocate space for them and fill them in in the IndexOfPdpEntries
> loop.
> +    //
> +    PageDirectoryPointerEntry = (VOID *)BigPageAddress;
> +    BigPageAddress           += SIZE_4KB;
> +
> +    //
> +    // Make a PML4 Entry
> +    //
> +    PageMapLevel4Entry->Uint64         =
> (UINT64)(UINTN)PageDirectoryPointerEntry;
> +    PageMapLevel4Entry->Bits.ReadWrite = 1;
> +    PageMapLevel4Entry->Bits.Present   = 1;
> +
> +    if (Page1GSupport) {
> +      PageDirectory1GEntry = (VOID *)PageDirectoryPointerEntry;
> +
> +      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress +=
> SIZE_1GB) {
> +        //
> +        // Fill in the Page Directory entries
> +        //
> +        PageDirectory1GEntry->Uint64         = (UINT64)PageAddress;
> +        PageDirectory1GEntry->Bits.ReadWrite = 1;
> +        PageDirectory1GEntry->Bits.Present   = 1;
> +        PageDirectory1GEntry->Bits.MustBe1   = 1;
> +      }
> +    } else {
> +      for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> NumberOfPdpEntriesNeeded; IndexOfPdpEntries++,
> PageDirectoryPointerEntry++) {
> +        //
> +        // Each Directory Pointer entries points to a page of Page Directory entires.
> +        // So allocate space for them and fill them in in the
> IndexOfPageDirectoryEntries loop.
> +        //
> +        PageDirectoryEntry = (VOID *)BigPageAddress;
> +        BigPageAddress    += SIZE_4KB;
> +
> +        //
> +        // Fill in a Page Directory Pointer Entries
> +        //
> +        PageDirectoryPointerEntry->Uint64         =
> (UINT64)(UINTN)PageDirectoryEntry;
> +        PageDirectoryPointerEntry->Bits.ReadWrite = 1;
> +        PageDirectoryPointerEntry->Bits.Present   = 1;
> +
> +        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress +=
> SIZE_2MB) {
> +          //
> +          // Fill in the Page Directory entries
> +          //
> +          PageDirectoryEntry->Uint64         = (UINT64)PageAddress;
> +          PageDirectoryEntry->Bits.ReadWrite = 1;
> +          PageDirectoryEntry->Bits.Present   = 1;
> +          PageDirectoryEntry->Bits.MustBe1   = 1;
> +        }
> +      }
> +
> +      for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++,
> PageDirectoryPointerEntry++) {
> +        ZeroMem (
> +          PageDirectoryPointerEntry,
> +          sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> +          );
> +      }
> +    }
> +  }
> +
> +  //
> +  // For the PML4 entries we are not using fill in a null entry.
> +  //
> +  for ( ; IndexOfPml4Entries < 512; IndexOfPml4Entries++,
> PageMapLevel4Entry++) {
> +    ZeroMem (
> +      PageMapLevel4Entry,
> +      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> +      );
> +  }
> +}
> +
> +/**
> +  If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @param  Context2                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully switched to long mode and execute
> coalesce.
> +  @retval Others                    Failed to execute coalesce in long mode.
> +
> +**/
> +EFI_STATUS
> +ModeSwitch (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1,
> +  IN VOID                  *Context2
> +  )
> +{
> +  UINTN            PageTableAddress;
> +  UINTN            PageTableSize;
> +  EFI_STATUS       Status;
> +  IA32_DESCRIPTOR  Gdtr;
> +
> +  DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
> +
> +  //
> +  // Save IA32 GDTR
> +  //
> +  AsmReadGdtr (&Gdtr);
> +
> +  //
> +  // Set X64 GDTR
> +  //
> +  AsmWriteGdtr (&mGdt);
> +
> +  PageTableAddress = AsmReadCr3 () & 0xFFFFF000;
> +
> +  //
> +  // If page table was created, no need to create
> +  //
> +  if (PageTableAddress == 0) {
> +    PageTableSize = CalculatePageTableSize ();
> +
> +    PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES
> (PageTableSize));
> +    ASSERT (PageTableAddress != 0);
> +
> +    CreateIdentityMappingPageTables (PageTableAddress);
> +
> +    AsmWriteCr3 ((UINTN)PageTableAddress);
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n"));
> +
> +  Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1,
> (UINT64)(UINTN)Context2, NULL);
> +  if (Status != 0) {
> +    Status = Status | MAX_BIT;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status));
> +
> +  //
> +  // Restore IA32 GDTR
> +  //
> +  AsmWriteGdtr (&Gdtr);
> +
> +  return Status;
> +}
> +
> +/**
> +  Load SMM core to dispatch other Standalone MM drivers.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> +  @retval Others                    Failed to load SMM core.
> +**/
> +EFI_STATUS
> +LoadSmmCore (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1
> +  )
> +{
> +  return ModeSwitch (Entry, Context1, NULL);
> +}
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> new file mode 100644
> index 0000000000..7fa42c32fb
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> @@ -0,0 +1,787 @@
> +/** @file
> +  SMM IPL that load the SMM Core into SMRAM at PEI stage
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <PiSmm.h>
> +#include <Ppi/SmmAccess.h>
> +#include <Ppi/SmmControl.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PeCoffLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PeiServicesTablePointerLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/PcdLib.h>
> +#include <Guid/SmramMemoryReserve.h>
> +#include <Guid/MmCoreData.h>
> +#include <StandaloneMmIplPei.h>
> +
> +//
> +// MM Core Private Data structure that contains the data shared between
> +// the SMM IPL and the Standalone MM Core.
> +//
> +MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
> +  MM_CORE_PRIVATE_DATA_SIGNATURE,     // Signature
> +  0,                                  // MmramRangeCount
> +  0,                                  // MmramRanges
> +  0,                                  // MmEntryPoint
> +  FALSE,                              // MmEntryPointRegistered
> +  FALSE,                              // InMm
> +  0,                                  // Mmst
> +  0,                                  // CommunicationBuffer
> +  0,                                  // BufferSize
> +  EFI_SUCCESS,                        // ReturnStatus
> +  0,                                  // MmCoreImageBase
> +  0,                                  // MmCoreImageSize
> +  0,                                  // MmCoreEntryPoint
> +  0,                                  // StandaloneBfvAddress
> +};
> +
> +//
> +// Global pointer used to access mMmCorePrivateData from outside and inside
> SMM
> +//
> +MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
> +
> +//
> +// SMM IPL global variables
> +//
> +PEI_SMM_ACCESS_PPI    *mSmmAccess;
> +EFI_SMRAM_DESCRIPTOR  *mCurrentSmramRange;
> +BOOLEAN               mSmmLocked = FALSE;
> +EFI_PHYSICAL_ADDRESS  mSmramCacheBase;
> +UINT64                mSmramCacheSize;
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR  mReadyToBootNotifyList = {
> +  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +  &gEfiEventReadyToBootGuid,
> +  ReadyToBootEvent
> +};
> +
> +/**
> +  This is the callback function on ready to boot.
> +
> +  Close and Lock smram range on ready to boot stage.
> +
> +  @param   PeiServices          General purpose services available to every PEIM.
> +  @param   NotifyDescriptor     The notification structure this PEIM registered on
> install.
> +  @param   Ppi                  Pointer to the PPI data associated with this function.
> +  @retval  EFI_SUCCESS          Close and lock smram ranges successfully.
> +  @retval  Other                Close and lock smram ranges failed.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadyToBootEvent (
> +  IN  EFI_PEI_SERVICES           **PeiServices,
> +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> +  IN  VOID                       *Ppi
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Close all SMRAM ranges
> +  //
> +  Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Lock all SMRAM ranges
> +  //
> +  Status = mSmmAccess->Lock ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return Status;
> +}
> +
> +/**
> +  Find the maximum SMRAM cache range that covers the range specified by
> SmramRange.
> +
> +  This function searches and joins all adjacent ranges of SmramRange into a
> range to be cached.
> +
> +  @param   SmramRange       The SMRAM range to search from.
> +  @param   SmramCacheBase   The returned cache range base.
> +  @param   SmramCacheSize   The returned cache range size.
> +**/
> +VOID
> +GetSmramCacheRange (
> +  IN  EFI_SMRAM_DESCRIPTOR  *SmramRange,
> +  OUT EFI_PHYSICAL_ADDRESS  *SmramCacheBase,
> +  OUT UINT64                *SmramCacheSize
> +  )
> +{
> +  UINTN                 Index;
> +  EFI_PHYSICAL_ADDRESS  RangeCpuStart;
> +  UINT64                RangePhysicalSize;
> +  BOOLEAN               FoundAdjacentRange;
> +  EFI_SMRAM_DESCRIPTOR  *SmramRanges;
> +
> +  *SmramCacheBase = SmramRange->CpuStart;
> +  *SmramCacheSize = SmramRange->PhysicalSize;
> +
> +  SmramRanges = (EFI_SMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges;
> +  do {
> +    FoundAdjacentRange = FALSE;
> +    for (Index = 0; Index < gMmCorePrivate->MmramRangeCount; Index++) {
> +      RangeCpuStart     = SmramRanges[Index].CpuStart;
> +      RangePhysicalSize = SmramRanges[Index].PhysicalSize;
> +      if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase ==
> (RangeCpuStart + RangePhysicalSize))) {
> +        *SmramCacheBase    = RangeCpuStart;
> +        *SmramCacheSize   += RangePhysicalSize;
> +        FoundAdjacentRange = TRUE;
> +      } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) &&
> (RangePhysicalSize > 0)) {
> +        *SmramCacheSize   += RangePhysicalSize;
> +        FoundAdjacentRange = TRUE;
> +      }
> +    }
> +  } while (FoundAdjacentRange);
> +}
> +
> +/**
> +  Get the fixed loading address from image header assigned by build tool. This
> function only be called
> +  when Loading module at Fixed address feature enabled.
> +
> +  @param  ImageContext              Pointer to the image context structure that
> describes the PE/COFF
> +                                    image that needs to be examined by this function.
> +  @retval EFI_SUCCESS               An fixed loading address is assigned to this image
> by build tools .
> +  @retval EFI_NOT_FOUND             The image has no assigned fixed loading
> address.
> +**/
> +EFI_STATUS
> +GetPeCoffImageFixLoadingAssignedAddress (
> +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> +  )
> +{
> +  UINTN                            SectionHeaderOffset;
> +  EFI_STATUS                       Status;
> +  EFI_IMAGE_SECTION_HEADER         SectionHeader;
> +  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
> +  EFI_PHYSICAL_ADDRESS             FixLoadingAddress;
> +  UINT16                           Index;
> +  UINTN                            Size;
> +  UINT16                           NumberOfSections;
> +  EFI_PHYSICAL_ADDRESS             SmramBase;
> +  UINT64                           SmmCodeSize;
> +  UINT64                           ValueInSectionHeader;
> +
> +  //
> +  // Build tool will calculate the smm code size and then patch the
> PcdLoadFixAddressSmmCodePageNumber
> +  //
> +  SmmCodeSize       = EFI_PAGES_TO_SIZE (PcdGet32
> (PcdLoadFixAddressSmmCodePageNumber));
> +  FixLoadingAddress = 0;
> +  Status            = EFI_NOT_FOUND;
> +  SmramBase         = mCurrentSmramRange->CpuStart;
> +  //
> +  // Get PeHeader pointer
> +  //
> +  ImgHdr              = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8
> *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
> +  SectionHeaderOffset = (UINTN)(
> +                                ImageContext->PeCoffHeaderOffset +
> +                                sizeof (UINT32) +
> +                                sizeof (EFI_IMAGE_FILE_HEADER) +
> +                                ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
> +                                );
> +  NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
> +
> +  //
> +  // Get base address from the first section header that doesn't point to code
> section.
> +  //
> +  for (Index = 0; Index < NumberOfSections; Index++) {
> +    //
> +    // Read section header from file
> +    //
> +    Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
> +    Status = ImageContext->ImageRead (
> +                             ImageContext->Handle,
> +                             SectionHeaderOffset,
> +                             &Size,
> +                             &SectionHeader
> +                             );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    Status = EFI_NOT_FOUND;
> +
> +    if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
> +      //
> +      // Build tool saves the offset to SMRAM base as image base in
> PointerToRelocations & PointerToLineNumbers fields in the
> +      // first section header that doesn't point to code section in image header.
> And there is an assumption that when the
> +      // feature is enabled, if a module is assigned a loading address by tools,
> PointerToRelocations & PointerToLineNumbers
> +      // fields should NOT be Zero, or else, these 2 fields should be set to Zero
> +      //
> +      ValueInSectionHeader = ReadUnaligned64 ((UINT64
> *)&SectionHeader.PointerToRelocations);
> +      if (ValueInSectionHeader != 0) {
> +        //
> +        // Found first section header that doesn't point to code section in which
> build tool saves the
> +        // offset to SMRAM base as image base in PointerToRelocations &
> PointerToLineNumbers fields
> +        //
> +        FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase +
> (INT64)ValueInSectionHeader);
> +
> +        if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <=
> FixLoadingAddress)) {
> +          //
> +          // The assigned address is valid. Return the specified loading address
> +          //
> +          ImageContext->ImageAddress = FixLoadingAddress;
> +          Status                     = EFI_SUCCESS;
> +        }
> +      }
> +
> +      break;
> +    }
> +
> +    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
> +  }
> +
> +  DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO:
> Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status));
> +  return Status;
> +}
> +
> +/**
> +  Searches all the available firmware volumes and returns the first matching FFS
> section.
> +
> +  This function searches all the firmware volumes for FFS files with FV file type
> specified by FileType
> +  The order that the firmware volumes is searched is not deterministic. For each
> available FV a search
> +  is made for FFS file of type FileType. If the FV contains more than one FFS file
> with the same FileType,
> +  the FileInstance instance will be the matched FFS file. For each FFS file found a
> search
> +  is made for FFS sections of type SectionType. If the FFS file contains at least
> SectionInstance instances
> +  of the FFS section specified by SectionType, then the SectionInstance instance
> is returned in Buffer.
> +  Buffer is allocated using AllocatePool(), and the size of the allocated buffer is
> returned in Size.
> +  It is the caller's responsibility to use FreePool() to free the allocated buffer.
> +
> +  If Buffer is NULL, then ASSERT().
> +  If Size is NULL, then ASSERT().
> +
> +  @param  FileType             Indicates the FV file type to search for within all
> available FVs.
> +  @param  FileInstance         Indicates which file instance within all available FVs
> specified by FileType.
> +                               FileInstance starts from zero.
> +  @param  SectionType          Indicates the FFS section type to search for within
> the FFS file
> +                               specified by FileType with FileInstance.
> +  @param  SectionInstance      Indicates which section instance within the FFS
> file
> +                               specified by FileType with FileInstance to retrieve.
> SectionInstance starts from zero.
> +  @param  Buffer               On output, a pointer to a callee allocated buffer
> containing the FFS file section that was found.
> +                               Is it the caller's responsibility to free this buffer using
> FreePool().
> +  @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
> +
> +  @retval  EFI_SUCCESS          The specified FFS section was returned.
> +  @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
> +  @retval  EFI_OUT_OF_RESOURCES There are not enough resources available
> to retrieve the matching FFS section.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetSectionFromAnyFvByFileType  (
> +  IN  EFI_FV_FILETYPE   FileType,
> +  IN  UINTN             FileInstance,
> +  IN  EFI_SECTION_TYPE  SectionType,
> +  IN  UINTN             SectionInstance,
> +  OUT VOID              **Buffer,
> +  OUT UINTN             *Size
> +  )
> +{
> +  EFI_STATUS           Status;
> +  UINTN                FvIndex;
> +  EFI_PEI_FV_HANDLE    VolumeHandle;
> +  EFI_PEI_FILE_HANDLE  FileHandle;
> +  EFI_PE32_SECTION     *SectionData;
> +  UINT32               SectionSize;
> +
> +  //
> +  // Search all FV
> +  //
> +  VolumeHandle = NULL;
> +  for (FvIndex = 0; ; FvIndex++) {
> +    Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    //
> +    // Search PEIM FFS
> +    //
> +    FileHandle = NULL;
> +    Status     = PeiServicesFfsFindNextFile (FileType, VolumeHandle, &FileHandle);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    //
> +    // Search Section
> +    //
> +    SectionData = NULL;
> +    Status      = PeiServicesFfsFindSectionData (SectionType, FileHandle, Buffer);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    //
> +    // Great!
> +    //
> +    SectionData = (EFI_PE32_SECTION *)((UINT8 *)*Buffer - sizeof
> (EFI_PE32_SECTION));
> +    ASSERT (SectionData->Type == SectionType);
> +    SectionSize  = *(UINT32 *)SectionData->Size;
> +    SectionSize &= 0xFFFFFF;
> +    *Size        = SectionSize - sizeof (EFI_PE32_SECTION);
> +
> +    if (FileType == EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
> +      EFI_FV_INFO  VolumeInfo;
> +      //
> +      // This is SMM BFV
> +      //
> +      Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
> +      if (!EFI_ERROR (Status)) {
> +        gMmCorePrivate->StandaloneBfvAddress =
> (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
> +      }
> +    }
> +
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Load the SMM Core image into SMRAM and executes the SMM Core from
> SMRAM.
> +
> +  @param[in, out] SmramRange            Descriptor for the range of SMRAM to
> reload the
> +                                        currently executing image, the rang of SMRAM to
> +                                        hold SMM Core will be excluded.
> +  @param[in, out] SmramRangeSmmCore     Descriptor for the range of SMRAM
> to hold SMM Core.
> +
> +  @param[in]      Context               Context to pass into SMM Core
> +
> +  @return  EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +ExecuteSmmCoreFromSmram (
> +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRange,
> +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRangeSmmCore,
> +  IN     VOID                  *Context
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  VOID                          *SourceBuffer;
> +  UINTN                         SourceSize;
> +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
> +  UINTN                         PageCount;
> +  VOID                          *HobList;
> +
> +  Status = PeiServicesGetHobList (&HobList);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Search all Firmware Volumes for a PE/COFF image in a file of type
> SMM_CORE
> +  //
> +  Status = GetSectionFromAnyFvByFileType (
> +             EFI_FV_FILETYPE_MM_CORE_STANDALONE,
> +             0,
> +             EFI_SECTION_PE32,
> +             0,
> +             &SourceBuffer,
> +             &SourceSize
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Initialize ImageContext
> +  //
> +  ImageContext.Handle    = SourceBuffer;
> +  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
> +
> +  //
> +  // Get information about the image being loaded
> +  //
> +  Status = PeCoffLoaderGetImageInfo (&ImageContext);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // if Loading module at Fixed Address feature is enabled, the SMM core driver
> will be loaded to
> +  // the address assigned by build tool.
> +  //
> +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> +    //
> +    // Get the fixed loading address assigned by Build tool
> +    //
> +    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Since the memory range to load SMM CORE will be cut out in SMM core,
> so no need to allocate and free this range
> +      //
> +      PageCount = 0;
> +      //
> +      // Reserved Smram Region for SmmCore is not used, and remove it from
> SmramRangeCount.
> +      //
> +      gMmCorePrivate->MmramRangeCount--;
> +    } else {
> +      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading module
> at fixed address at address failed\n"));
> +      //
> +      // Allocate memory for the image being loaded from the
> EFI_SRAM_DESCRIPTOR
> +      // specified by SmramRange
> +      //
> +      PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize
> + ImageContext.SectionAlignment);
> +
> +      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> +      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> +
> +      SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> +      SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> SmramRange->PhysicalSize;
> +      SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> SmramRange->PhysicalSize;
> +      SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> EFI_ALLOCATED;
> +      SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> +
> +      //
> +      // Align buffer on section boundary
> +      //
> +      ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> +    }
> +  } else {
> +    //
> +    // Allocate memory for the image being loaded from the
> EFI_SRAM_DESCRIPTOR
> +    // specified by SmramRange
> +    //
> +    PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize +
> ImageContext.SectionAlignment);
> +
> +    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> +    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> +
> +    SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> +    SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> SmramRange->PhysicalSize;
> +    SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> SmramRange->PhysicalSize;
> +    SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> EFI_ALLOCATED;
> +    SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> +
> +    //
> +    // Align buffer on section boundary
> +    //
> +    ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> +  }
> +
> +  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
> +  ImageContext.ImageAddress &=
> ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
> +
> +  //
> +  // Print debug message showing SMM Core load address.
> +  //
> +  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM
> address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
> +
> +  //
> +  // Load the image to our new buffer
> +  //
> +  Status = PeCoffLoaderLoadImage (&ImageContext);
> +  if (!EFI_ERROR (Status)) {
> +    //
> +    // Relocate the image in our new buffer
> +    //
> +    Status = PeCoffLoaderRelocateImage (&ImageContext);
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Flush the instruction cache so the image data are written before we
> execute it
> +      //
> +      InvalidateInstructionCacheRange ((VOID
> *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
> +
> +      //
> +      // Print debug message showing SMM Core entry point address.
> +      //
> +      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM
> address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
> +
> +      gMmCorePrivate->MmCoreImageBase = ImageContext.ImageAddress;
> +      gMmCorePrivate->MmCoreImageSize = ImageContext.ImageSize;
> +      DEBUG ((DEBUG_INFO, "SmmCoreImageBase - 0x%016lx\n",
> gMmCorePrivate->MmCoreImageBase));
> +      DEBUG ((DEBUG_INFO, "SmmCoreImageSize - 0x%016lx\n",
> gMmCorePrivate->MmCoreImageSize));
> +
> +      gMmCorePrivate->MmCoreEntryPoint = ImageContext.EntryPoint;
> +
> +      //
> +      // Print debug message showing Standalone MM Core entry point address.
> +      //
> +      DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM
> address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
> +
> +      //
> +      // Execute image
> +      //
> +      LoadSmmCore (ImageContext.EntryPoint, HobList);
> +    }
> +  }
> +
> +  //
> +  // If the load operation, relocate operation, or the image execution return an
> +  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR
> specified by
> +  // SmramRange
> +  //
> +  if (EFI_ERROR (Status)) {
> +    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
> +  }
> +
> +  //
> +  // Always free memory allocated by GetFileBufferByFilePath ()
> +  //
> +  FreePool (SourceBuffer);
> +
> +  return Status;
> +}
> +
> +/**
> +  Get full SMRAM ranges.
> +
> +  It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved
> ranges from
> +  SmmConfiguration protocol, split the entries if there is overlap between them.
> +  It will also reserve one entry for SMM core.
> +
> +  @param[in]  PeiServices           Describes the list of possible PEI Services.
> +  @param[out] FullSmramRangeCount   Output pointer to full SMRAM range
> count.
> +
> +  @return Pointer to full SMRAM ranges.
> +
> +**/
> +EFI_SMRAM_DESCRIPTOR *
> +GetFullSmramRanges (
> +  IN  CONST EFI_PEI_SERVICES  **PeiServices,
> +  OUT       UINTN             *FullSmramRangeCount
> +  )
> +{
> +  EFI_STATUS            Status;
> +  UINTN                 Size;
> +  EFI_SMRAM_DESCRIPTOR  *FullSmramRanges;
> +  UINTN                 AdditionSmramRangeCount;
> +  UINTN                 SmramRangeCount;
> +
> +  //
> +  // Get SMRAM information.
> +  //
> +  Size   = 0;
> +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, &Size, NULL);
> +  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
> +
> +  SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
> +
> +  //
> +  // Reserve one entry SMM Core in the full SMRAM ranges.
> +  //
> +  AdditionSmramRangeCount = 1;
> +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> +    //
> +    // Reserve two entries for all SMM drivers & SMM Core in the full SMRAM
> ranges.
> +    //
> +    AdditionSmramRangeCount = 2;
> +  }
> +
> +  *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
> +  Size                 = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);
> +  FullSmramRanges      = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
> +  ASSERT (FullSmramRanges != NULL);
> +  if (FullSmramRanges == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, &Size, FullSmramRanges);
> +
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return FullSmramRanges;
> +}
> +
> +/**
> +  The Entry Point for SMM IPL
> +
> +  Load SMM Core into SMRAM.
> +
> +  @param  FileHandle  Handle of the file being invoked.
> +  @param  PeiServices Describes the list of possible PEI Services.
> +
> +  @retval EFI_SUCCESS    The entry point is executed successfully.
> +  @retval Other          Some error occurred when executing this entry point.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmIplEntry (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  )
> +{
> +  EFI_STATUS             Status;
> +  UINTN                  Index;
> +  UINT64                 MaxSize;
> +  UINT64                 SmmCodeSize;
> +  MM_CORE_DATA_HOB_DATA  SmmCoreDataHobData;
> +  EFI_SMRAM_DESCRIPTOR   *MmramRanges;
> +  EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmDriver;
> +
> +  //
> +  // Build Hob for SMM and DXE phase
> +  //
> +  SmmCoreDataHobData.Address =
> (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES
> (sizeof (mMmCorePrivateData)));
> +  ASSERT (SmmCoreDataHobData.Address != 0);
> +  gMmCorePrivate = (VOID *)(UINTN)SmmCoreDataHobData.Address;
> +  CopyMem ((VOID *)(UINTN)SmmCoreDataHobData.Address,
> &mMmCorePrivateData, sizeof (mMmCorePrivateData));
> +  DEBUG ((DEBUG_INFO, "gMmCorePrivate - 0x%x\n", gMmCorePrivate));
> +
> +  BuildGuidDataHob (
> +    &gMmCoreDataHobGuid,
> +    (VOID *)&SmmCoreDataHobData,
> +    sizeof (SmmCoreDataHobData)
> +    );
> +
> +  //
> +  // Get SMM Access Protocol
> +  //
> +  Status = PeiServicesLocatePpi (&gPeiSmmAccessPpiGuid, 0, NULL, (VOID
> **)&mSmmAccess);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Get SMRAM information
> +  //
> +  gMmCorePrivate->MmramRanges =
> (EFI_PHYSICAL_ADDRESS)(UINTN)GetFullSmramRanges (PeiServices, (UINTN
> *)&gMmCorePrivate->MmramRangeCount);
> +  ASSERT (gMmCorePrivate->MmramRanges != 0);
> +  if (gMmCorePrivate->MmramRanges == 0) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Open all SMRAM ranges
> +  //
> +  Status = mSmmAccess->Open ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Print debug message that the SMRAM window is now open.
> +  //
> +  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
> +
> +  //
> +  // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB
> - 4K in size
> +  //
> +  mCurrentSmramRange = NULL;
> +  MmramRanges        = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges;
> +  if (MmramRanges == NULL) {
> +    DEBUG ((DEBUG_ERROR, "Fail to retrieve MmramRanges\n"));
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index <
> gMmCorePrivate->MmramRangeCount; Index++) {
> +    //
> +    // Skip any SMRAM region that is already allocated, needs testing, or needs
> ECC initialization
> +    //
> +    if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED |
> EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
> +      continue;
> +    }
> +
> +    if (MmramRanges[Index].CpuStart >= BASE_1MB) {
> +      if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize) <=
> BASE_4GB) {
> +        if (MmramRanges[Index].PhysicalSize >= MaxSize) {
> +          MaxSize            = MmramRanges[Index].PhysicalSize;
> +          mCurrentSmramRange = &MmramRanges[Index];
> +        }
> +      }
> +    }
> +  }
> +
> +  if (mCurrentSmramRange != NULL) {
> +    //
> +    // Print debug message showing SMRAM window that will be used by SMM
> IPL and SMM Core
> +    //
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "SMM IPL found SMRAM window %p - %p\n",
> +      (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
> +      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart +
> mCurrentSmramRange->PhysicalSize - 1)
> +      ));
> +
> +    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase,
> &mSmramCacheSize);
> +
> +    //
> +    // if Loading module at Fixed Address feature is enabled, save the SMRAM
> base to Load
> +    // Modules At Fixed Address Configuration Table.
> +    //
> +    if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> +      //
> +      // Build tool will calculate the smm code size and then patch the
> PcdLoadFixAddressSmmCodePageNumber
> +      //
> +      SmmCodeSize = LShiftU64 (PcdGet32
> (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
> +      //
> +      // The SMRAM available memory is assumed to be larger than SmmCodeSize
> +      //
> +      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
> +      //
> +      // Fill the Smram range for all SMM code
> +      //
> +      MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges;
> +      //
> +      // Note: SmramRanges specific for all SMM code will put in the
> gMmCorePrivate->MmramRangeCount - 2.
> +      //
> +      SmramRangeSmmDriver                = &MmramRanges[gMmCorePrivate-
> >MmramRangeCount - 2];
> +      SmramRangeSmmDriver->CpuStart      = mCurrentSmramRange->CpuStart;
> +      SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange-
> >PhysicalStart;
> +      SmramRangeSmmDriver->RegionState   = mCurrentSmramRange-
> >RegionState | EFI_ALLOCATED;
> +      SmramRangeSmmDriver->PhysicalSize  = SmmCodeSize;
> +
> +      mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
> +      mCurrentSmramRange->CpuStart      = mCurrentSmramRange->CpuStart +
> SmmCodeSize;
> +      mCurrentSmramRange->PhysicalStart = mCurrentSmramRange-
> >PhysicalStart + SmmCodeSize;
> +    }
> +
> +    //
> +    // Load SMM Core into SMRAM and execute it from SMRAM
> +    // Note: SmramRanges specific for SMM Core will put in the gMmCorePrivate-
> >MmramRangeCount - 1.
> +    //
> +    Status = ExecuteSmmCoreFromSmram (
> +               mCurrentSmramRange,
> +               &(((EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges)[gMmCorePrivate->MmramRangeCount - 1]),
> +               gMmCorePrivate
> +               );
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Print error message that the SMM Core failed to be loaded and executed.
> +      //
> +      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core
> from SMRAM\n"));
> +    }
> +  } else {
> +    //
> +    // Print error message that there are not enough SMRAM resources to load
> the SMM Core.
> +    //
> +    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM
> region to load SMM Core\n"));
> +  }
> +
> +  //
> +  // If the SMM Core could not be loaded then close SMRAM window, free
> allocated
> +  // resources, and return an error so SMM IPL will be unloaded.
> +  //
> +  if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
> +    //
> +    // Close all SMRAM ranges
> +    //
> +    Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    //
> +    // Print debug message that the SMRAM window is now closed.
> +    //
> +    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
> +
> +    //
> +    // Free all allocated resources
> +    //
> +    FreePool ((VOID *)(UINTN)gMmCorePrivate->MmramRanges);
> +
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Create ready to boot for close and lock smram ranges
> +  //
> +  Status = PeiServicesNotifyPpi (&mReadyToBootNotifyList);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> new file mode 100644
> index 0000000000..6d3497f2ea
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> @@ -0,0 +1,32 @@
> +/** @file
> +  SMM IPL that load the SMM Core into SMRAM
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <PiSmm.h>
> +#include <StandaloneMm.h>
> +
> +/**
> +  Load SMM core to dispatch other Standalone MM drivers.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> +  @retval Others                    Failed to load SMM core.
> +**/
> +EFI_STATUS
> +LoadSmmCore (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1
> +  )
> +{
> +  STANDALONE_MM_FOUNDATION_ENTRY_POINT  EntryPoint;
> +
> +  EntryPoint = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
> +  return EntryPoint (Context1);
> +}
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> new file mode 100644
> index 0000000000..7f887eb77d
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> @@ -0,0 +1,148 @@
> +;------------------------------------------------------------------------------
> +;
> +; Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> +;
> +; Module Name:
> +;
> +;    Thunk32To64.nasm
> +;
> +; Abstract:
> +;
> +;   This is the assembly code to transition from long mode to compatibility
> +;   mode to execute 32-bit code and then transit back to long mode.
> +;
> +;------------------------------------------------------------------------------
> +
> +    SECTION .text
> +
> +;------------------------------------------------------------------------------
> +; Procedure:    AsmExecute64BitCode
> +;
> +; Input:        None
> +;
> +; Output:       None
> +;
> +; Prototype:    UINT32
> +;               AsmExecute64BitCode (
> +;                 IN UINT64           Function,
> +;                 IN UINT64           Param1,
> +;                 IN UINT64           Param2,
> +;                 IN IA32_DESCRIPTOR  *InternalGdtr
> +;                 );
> +;
> +;
> +; Description:  A thunk function to execute 32-bit code in long mode.
> +;
> +;------------------------------------------------------------------------------
> +global ASM_PFX(AsmExecute64BitCode)
> +ASM_PFX(AsmExecute64BitCode):
> +;
> +; +---------+
> +; | EIP(64) |
> +; +---------+
> +; | CS (64) |
> +; +---------+
> +; | EIP(32) |
> +; +---------+
> +; | CS (32) |<-ESP (16 bytes aligned)
> +; +---------+
> +; | ...     |
> +; +---------+
> +; | ebx     |<-EBP
> +; +---------+
> +; | ebp     |<-EBP + 4
> +; +---------+
> +; | esi     |<-EBP + 8
> +; +---------+
> +; | edi     |<-EBP + 12
> +; +---------+
> +; | RFlags  |<-EBP + 16
> +; +---------+
> +; | RetAddr |<-EBP (org)
> +; +---------+
> +; | Func    |<-EBP + 24
> +; | Func    |
> +; +---------+
> +; | Param1  |<-EBP + 32
> +; | Param1  |
> +; +---------+
> +; | Param2  |<-EBP + 40
> +; | Param2  |
> +; +---------+
> +; | Gdtr    |
> +; +---------+
> +;
> +    ;
> +    ; Save general purpose register and RFlags register
> +    ;
> +    pushfd
> +    push    edi
> +    push    esi
> +    push    ebp
> +    push    ebx
> +    mov     ebp, esp
> +
> +    and     esp, 0FFFFFFF0h
> +
> +    push    010h                        ; protected mode selector on stack
> +    mov     eax, Compatible             ; offset for LongMode
> +    push    eax                         ; offset on stack
> +
> +    push    038h                        ; long mode selector on stack
> +    mov     eax, LongMode               ; offset for LongMode
> +    push    eax                         ; offset on stack
> +
> +    mov     eax, cr4
> +    or      al, 020h
> +    mov     cr4, eax                    ; enable PAE
> +    mov     ecx, 0c0000080h
> +    rdmsr
> +    or      ah, 1                       ; set LME
> +    wrmsr
> +    mov     eax, cr0
> +    bts     eax, 31                     ; set PG
> +    mov     cr0, eax                    ; enable paging
> +    retf                                ; topmost 2 dwords hold the address
> +LongMode:                               ; long mode starts here
> +
> +    ; Call long mode function
> +    DB      67h, 48h                    ; 32-bit address size, 64-bit operand size
> +    mov     eax, [ebp + 24]             ; mov rbx, [ebp + 24]
> +    DB      67h, 48h
> +    mov     ecx, [ebp + 24 + 8]         ; mov rcx, [ebp + 24 + 8]
> +    DB      67h, 48h
> +    mov     edx, [ebp + 24 + 16]        ; mov rdx, [ebp + 24 + 16]
> +
> +    DB      48h
> +    add     esp, -20h                   ; add rsp, -20h
> +    call    eax                         ; call rax
> +    DB      48h
> +    add     esp, 20h                    ; add rsp, 20h
> +
> +    ; after long mode function call
> +    mov     ebx, eax
> +
> +    retf
> +Compatible:
> +    mov     ecx, cr0
> +    btc     ecx, 31                     ; clear PG
> +    mov     cr0, ecx                    ; disable paging
> +    mov     ecx, 0C0000080h
> +    rdmsr
> +    btc     eax, 8                      ; clear LME
> +    wrmsr
> +
> +    ;
> +    ; Restore C register and eax hold the return status from 32-bit function.
> +    ; Note: Do not touch rax from now which hold the return value from IA32
> function
> +    ;
> +    mov     eax, ebx                    ; put return status to EAX
> +    mov     esp, ebp                    ; restore stack pointer
> +    pop     ebx
> +    pop     ebp
> +    pop     esi
> +    pop     edi
> +    popfd
> +
> +    ret
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> new file mode 100644
> index 0000000000..be0aae70f0
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> @@ -0,0 +1,66 @@
> +/** @file
> +  Private header with declarations and definitions specific to the Standalone
> +  MM IPL PEI driver
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef STANDALONE_MM_IPL_PEI_H_
> +#define STANDALONE_MM_IPL_PEI_H_
> +
> +/**
> +  Load SMM core to dispatch other Standalone MM drivers.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> +  @retval Others                    Failed to load SMM core.
> +**/
> +EFI_STATUS
> +LoadSmmCore (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1
> +  );
> +
> +/**
> +  Assembly function to transition from long mode to compatibility mode to
> +  execute 32-bit code and then transit back to long mode.
> +
> +  @param[in] Function     The 32bit code entry to be executed.
> +  @param[in] Param1       The first parameter to pass to 32bit code
> +  @param[in] Param2       The second parameter to pass to 32bit code
> +  @param[in] InternalGdtr The GDT and GDT descriptor used by this library
> +
> +  @retval status.
> +**/
> +UINT32
> +AsmExecute64BitCode (
> +  IN UINT64           Function,
> +  IN UINT64           Param1,
> +  IN UINT64           Param2,
> +  IN IA32_DESCRIPTOR  *InternalGdtr
> +  );
> +
> +/**
> +  This is the callback function on ready to boot.
> +
> +  Close and lock smram ranges on ready to boot stage.
> +
> +  @param   PeiServices       General purpose services available to every PEIM.
> +  @param   NotifyDescriptor  The notification structure this PEIM registered on
> install.
> +  @param   Ppi               Pointer to the PPI data associated with this function.
> +  @retval  EFI_SUCCESS       Close and lock smram ranges successfully.
> +  @retval  Other             Close and lock smram ranges failed.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadyToBootEvent (
> +  IN  EFI_PEI_SERVICES           **PeiServices,
> +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> +  IN  VOID                       *Ppi
> +  );
> +
> +#endif
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> new file mode 100644
> index 0000000000..ff4c67a92c
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> @@ -0,0 +1,75 @@
> +## @file
> +#  This module provide a Standalone SMM compliant implementation of SMM
> IPL PEIM.
> +#
> +#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = StandaloneMmIplPei
> +  FILE_GUID                      = 578A0D17-2DC0-4C7D-A121-D8D771923BB0
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  PI_SPECIFICATION_VERSION       = 0x0001000A
> +  ENTRY_POINT                    = SmmIplEntry
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  StandaloneMmIplPei.h
> +  StandaloneMmIplPei.c
> +
> +[Sources.Ia32]
> +  Ia32/LoadSmmCore.c
> +  Ia32/Thunk32To64.nasm
> +
> +[Sources.X64]
> +  X64/LoadSmmCore.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  StandaloneMmPkg/StandaloneMmPkg.dec
> +
> +[LibraryClasses]
> +  PeimEntryPoint
> +  PeiServicesTablePointerLib
> +  PeiServicesLib
> +  BaseLib
> +  BaseMemoryLib
> +  PeCoffLib
> +  CacheMaintenanceLib
> +  MemoryAllocationLib
> +  DebugLib
> +  HobLib
> +  IntrinsicLib
> +
> +[Guids]
> +  gMmCoreDataHobGuid
> +  gEfiEventReadyToBootGuid
> +
> +[Ppis]
> +  gPeiSmmAccessPpiGuid                     ## CONSUMES
> +  gPeiSmmControlPpiGuid                    ## CONSUMES
> +
> +[FeaturePcd.IA32]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ##
> CONSUMES
> +
> +[Pcd.IA32]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ##
> SOMETIMES_CONSUMES
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber
> ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable        ##
> CONSUMES
> +
> +[Depex]
> +  gPeiSmmAccessPpiGuid AND
> +  gPeiSmmControlPpiGuid
> +
> diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> index 4777532a7e..872f7958be 100644
> --- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> +++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> @@ -78,7 +78,9 @@
>      ## options defined .pytool/Plugin/SpellCheck
>      "SpellCheck": {
>          "AuditOnly": False,
> -        "IgnoreFiles": [],           # use gitignore syntax to ignore errors
> +        "IgnoreFiles": [
> +            "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm"
> +        ],           # use gitignore syntax to ignore errors
>                                       # in matching files
>          "ExtendWords": [
>              "Bsymbolic",
> diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc
> b/StandaloneMmPkg/StandaloneMmPkg.dsc
> index 8012f93b7d..d88471fe82 100644
> --- a/StandaloneMmPkg/StandaloneMmPkg.dsc
> +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc
> @@ -20,7 +20,7 @@
>    PLATFORM_VERSION               = 1.0
>    DSC_SPECIFICATION              = 0x00010011
>    OUTPUT_DIRECTORY               = Build/StandaloneMm
> -  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM
> +  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM|IA32
>    BUILD_TARGETS                  = DEBUG|RELEASE
>    SKUID_IDENTIFIER               = DEFAULT
> 
> @@ -60,6 +60,14 @@
> 
> StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoin
> t/StandaloneMmDriverEntryPoint.inf
> 
> VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/V
> ariableMmDependency.inf
> 
> +[LibraryClasses.common.PEIM]
> +  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> +  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
> +
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAlloc
> ationLib.inf
> +  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> +
> PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServic
> esTablePointerLib.inf
> +  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
> +
>  [LibraryClasses.AARCH64, LibraryClasses.ARM]
>    ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
> 
> StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStand
> aloneMmLib.inf
> @@ -104,7 +112,7 @@
>  #       generated for it, but the binary will not be put into any firmware volume.
>  #
> 
> #################################################################
> ##################################
> -[Components.common]
> +[Components.AARCH64, Components.ARM, Components.X64]
>    #
>    # MM Core
>    #
> @@ -122,6 +130,9 @@
>    StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
> 
> StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMm
> PeCoffExtraActionLib.inf
> 
> +[Components.X64, Components.IA32]
> +  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> +
> 
> #################################################################
> ##################################
>  #
>  # BuildOptions Section - Define the module specific tool chain flags that should
> be used as
> diff --git a/UefiPayloadPkg/UniversalPayloadBuild.sh
> b/UefiPayloadPkg/UniversalPayloadBuild.sh
> index 9a72eedd35..bacf5233a8 100644
> --- a/UefiPayloadPkg/UniversalPayloadBuild.sh
> +++ b/UefiPayloadPkg/UniversalPayloadBuild.sh
> @@ -1,17 +1,17 @@
> -#!/usr/bin/env bash
> -#
> -# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> -#
> -# SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
> -
> -if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> -    echo python_exe=${PYTHON_COMMAND}
> -fi
> -
> -# Get file path of UniversalPayloadBuild.sh
> -uplbld_filepath=${BASH_SOURCE:-$0}
> -# Remove ".sh" extension
> -uplbld_filepath_noext=${uplbld_filepath%.*}
> -# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> -exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> +#!/usr/bin/env bash
> +#
> +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +
> +if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> +    echo python_exe=${PYTHON_COMMAND}
> +fi
> +
> +# Get file path of UniversalPayloadBuild.sh
> +uplbld_filepath=${BASH_SOURCE:-$0}
> +# Remove ".sh" extension
> +uplbld_filepath_noext=${uplbld_filepath%.*}
> +# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> +exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> diff --git a/edksetup.sh b/edksetup.sh
> index cab3a8c113..553e1676d0 100755
> --- a/edksetup.sh
> +++ b/edksetup.sh
> @@ -1,147 +1,147 @@
> -#
> -# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> -# SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
> -# In *inux environment, the build tools's source is required and need to be
> compiled
> -# firstly, please reference
> https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-Github-
> Quick-Start
> -# to get how to setup build tool.
> -#
> -# Setup the environment for unix-like systems running a bash-like shell.
> -# This file must be "sourced" not merely executed. For example: ". edksetup.sh"
> -#
> -# CYGWIN users: Your path and filename related environment variables should
> be
> -# set up in the unix style.  This script will make the necessary conversions to
> -# windows style.
> -#
> -# Please reference edk2 user manual for more detail descriptions at
> https://github.com/tianocore-
> docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> -#
> -
> -SCRIPTNAME="edksetup.sh"
> -RECONFIG=FALSE
> -
> -HelpMsg()
> -{
> -  echo "Usage: $SCRIPTNAME [Options]"
> -  echo
> -  echo "The system environment variable, WORKSPACE, is always set to the
> current"
> -  echo "working directory."
> -  echo
> -  echo "Options: "
> -  echo "  --help, -h, -?        Print this help screen and exit."
> -  echo
> -  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with the"
> -  echo "                        template files from the BaseTools/Conf directory."
> -  echo
> -  echo Please note: This script must be \'sourced\' so the environment can be
> changed.
> -  echo ". $SCRIPTNAME"
> -  echo "source $SCRIPTNAME"
> -}
> -
> -SetWorkspace()
> -{
> -  #
> -  # If WORKSPACE is already set, then we can return right now
> -  #
> -  export PYTHONHASHSEED=1
> -  if [ -n "$WORKSPACE" ]
> -  then
> -    return 0
> -  fi
> -
> -  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> -  then
> -    echo Source this script from the base of your tree.  For example:
> -    echo "  cd /Path/To/Edk2/Clone"
> -    echo "  . $SCRIPTNAME"
> -    return 1
> -  fi
> -
> -  #
> -  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> -  #
> -  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> -  then
> -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> -    echo Please point EDK_TOOLS_PATH at the directory that contains
> -    echo the EDK2 BuildEnv script.
> -    return 1
> -  fi
> -
> -  #
> -  # Set $WORKSPACE
> -  #
> -  export WORKSPACE=$PWD
> -  return 0
> -}
> -
> -SetupEnv()
> -{
> -  if [ -n "$EDK_TOOLS_PATH" ]
> -  then
> -    . $EDK_TOOLS_PATH/BuildEnv
> -  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> -  then
> -    . $WORKSPACE/BaseTools/BuildEnv
> -  elif [ -n "$PACKAGES_PATH" ]
> -  then
> -    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> -    do
> -      if [ -f "$DIR/BaseTools/BuildEnv" ]
> -      then
> -        export EDK_TOOLS_PATH=$DIR/BaseTools
> -        . $DIR/BaseTools/BuildEnv
> -        break
> -      fi
> -    done
> -  else
> -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> -    echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly
> -    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> -    echo the EDK2 BuildEnv script.
> -    return 1
> -  fi
> -}
> -
> -SetupPython3()
> -{
> -  export PYTHON_COMMAND=python3
> -}
> -
> -SourceEnv()
> -{
> -  SetupPython3
> -  SetWorkspace
> -  SetupEnv
> -}
> -
> -I=$#
> -while [ $I -gt 0 ]
> -do
> -  case "$1" in
> -    BaseTools)
> -      # Ignore argument for backwards compatibility
> -      shift
> -    ;;
> -    --reconfig)
> -      RECONFIG=TRUE
> -      shift
> -    ;;
> -    *)
> -      HelpMsg
> -      break
> -    ;;
> -  esac
> -  I=$((I - 1))
> -done
> -
> -if [ $I -gt 0 ]
> -then
> -  return 1
> -fi
> -
> -SourceEnv
> -
> -unset SCRIPTNAME RECONFIG
> -
> -return $?
> +#
> +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +# In *inux environment, the build tools's source is required and need to be
> compiled
> +# firstly, please reference
> https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-Github-
> Quick-Start
> +# to get how to setup build tool.
> +#
> +# Setup the environment for unix-like systems running a bash-like shell.
> +# This file must be "sourced" not merely executed. For example: ". edksetup.sh"
> +#
> +# CYGWIN users: Your path and filename related environment variables should
> be
> +# set up in the unix style.  This script will make the necessary conversions to
> +# windows style.
> +#
> +# Please reference edk2 user manual for more detail descriptions at
> https://github.com/tianocore-
> docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> +#
> +
> +SCRIPTNAME="edksetup.sh"
> +RECONFIG=FALSE
> +
> +HelpMsg()
> +{
> +  echo "Usage: $SCRIPTNAME [Options]"
> +  echo
> +  echo "The system environment variable, WORKSPACE, is always set to the
> current"
> +  echo "working directory."
> +  echo
> +  echo "Options: "
> +  echo "  --help, -h, -?        Print this help screen and exit."
> +  echo
> +  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with the"
> +  echo "                        template files from the BaseTools/Conf directory."
> +  echo
> +  echo Please note: This script must be \'sourced\' so the environment can be
> changed.
> +  echo ". $SCRIPTNAME"
> +  echo "source $SCRIPTNAME"
> +}
> +
> +SetWorkspace()
> +{
> +  #
> +  # If WORKSPACE is already set, then we can return right now
> +  #
> +  export PYTHONHASHSEED=1
> +  if [ -n "$WORKSPACE" ]
> +  then
> +    return 0
> +  fi
> +
> +  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> +  then
> +    echo Source this script from the base of your tree.  For example:
> +    echo "  cd /Path/To/Edk2/Clone"
> +    echo "  . $SCRIPTNAME"
> +    return 1
> +  fi
> +
> +  #
> +  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> +  #
> +  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> +  then
> +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> +    echo Please point EDK_TOOLS_PATH at the directory that contains
> +    echo the EDK2 BuildEnv script.
> +    return 1
> +  fi
> +
> +  #
> +  # Set $WORKSPACE
> +  #
> +  export WORKSPACE=$PWD
> +  return 0
> +}
> +
> +SetupEnv()
> +{
> +  if [ -n "$EDK_TOOLS_PATH" ]
> +  then
> +    . $EDK_TOOLS_PATH/BuildEnv
> +  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> +  then
> +    . $WORKSPACE/BaseTools/BuildEnv
> +  elif [ -n "$PACKAGES_PATH" ]
> +  then
> +    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> +    do
> +      if [ -f "$DIR/BaseTools/BuildEnv" ]
> +      then
> +        export EDK_TOOLS_PATH=$DIR/BaseTools
> +        . $DIR/BaseTools/BuildEnv
> +        break
> +      fi
> +    done
> +  else
> +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> +    echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly
> +    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> +    echo the EDK2 BuildEnv script.
> +    return 1
> +  fi
> +}
> +
> +SetupPython3()
> +{
> +  export PYTHON_COMMAND=python3
> +}
> +
> +SourceEnv()
> +{
> +  SetupPython3
> +  SetWorkspace
> +  SetupEnv
> +}
> +
> +I=$#
> +while [ $I -gt 0 ]
> +do
> +  case "$1" in
> +    BaseTools)
> +      # Ignore argument for backwards compatibility
> +      shift
> +    ;;
> +    --reconfig)
> +      RECONFIG=TRUE
> +      shift
> +    ;;
> +    *)
> +      HelpMsg
> +      break
> +    ;;
> +  esac
> +  I=$((I - 1))
> +done
> +
> +if [ $I -gt 0 ]
> +then
> +  return 1
> +fi
> +
> +SourceEnv
> +
> +unset SCRIPTNAME RECONFIG
> +
> +return $?
> --
> 2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105834): https://edk2.groups.io/g/devel/message/105834
Mute This Topic: https://groups.io/mt/99079640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/3901457/1787277/102458076/xyzzy [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
Posted by Zhang, Hongbin1 10 months, 3 weeks ago
Thanks Ray.
Replied your code comments with [Hongbin].
And I will split to several patches, it will be better for reviewing.

-----Original Message-----
From: Ni, Ray <ray.ni@intel.com> 
Sent: Wednesday, June 7, 2023 10:04 AM
To: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; devel@edk2.groups.io; Yao, Jiewen <jiewen.yao@intel.com>
Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Supreeth Venkatesh <supreeth.venkatesh@arm.com>
Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.

Hongbin,
The patch is so big. Can you please split the patch to small patches? For example:
1st patch only implements the Ipl entrypoint to find the correct SMRAM range and dump it
2nd patch loads SMM CORE without mode switch if sizeof (UINTN) matches SMM core module type.
3rd patch loads SMM CORE with mode switch if sizeof (UINTN) == 4 but SMM core module type is 64bit.
4th patch Deadloop() when sizeof (UINTN) == 8 but SMM core module type is 32bit.
5th patch register ReadyToBoot callback. But is it too late from security perspective? Why not lock after SMM core exit? @Yao, Jiewen

Back to the code content, 3 comments:
1. Have you tested the flow when LoadImageAtFixedAddress is enabled? If no, I prefer you do not add the logic at all in the first version. We can enable that later.
     -- Yes, currently PcdLoadModuleAtFixAddressEnable was not used and verified, I will add later [Hongbin].
2. "EFIAPI" for GetSectionFromAnyFvByFileType should be removed. And the function prototype could be refined as below:
    EFI_STATUS
    LocateMmFvAndCore
      OUT EFI_PHYSICAL_ADDRESS  *MmFvBaseAddress,
      OUT VOID                  **MmCoreImageAddress
    Please avoid directly modifying global variables inside this function.
     -- Ok, will change that [Hongbin].
3. Can the StandaloneMmCore in open source be directly used with this IPL? 
     -- I will think about this later [Hongbin].

Thanks,
Ray


> -----Original Message-----
> From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> Sent: Monday, May 22, 2023 1:21 PM
> To: devel@edk2.groups.io
> Cc: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Yao, Jiewen
> <jiewen.yao@intel.com>; Ni, Ray <ray.ni@intel.com>; Zeng, Star
> <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar
> <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> Subject: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Add StandaloneMmIplPei IA32/X64 driver at PEI stage.
> FSP will use this driver to load Standalone MM code
> to dispatch other Standalone MM drivers.
> 
> Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> ---
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     | 456
> ++++++++++++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   | 787
> ++++++++++++++++++++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |  32 +
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  | 148
> ++++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66
> ++
>  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |  75
> ++
>  StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
>  StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
>  UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
>  edksetup.sh                                                       | 294 ++++----
>  10 files changed, 1744 insertions(+), 167 deletions(-)
> 
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> new file mode 100644
> index 0000000000..d6174d73a3
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> @@ -0,0 +1,456 @@
> +/** @file
> +  SMM IPL that load the SMM Core into SMRAM
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <PiSmm.h>
> +#include <StandaloneMm.h>
> +#include <Library/HobLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <StandaloneMmIplPei.h>
> +
> +#pragma pack(1)
> +
> +//
> +// Page-Map Level-4 Offset (PML4) and
> +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
> +//
> +
> +typedef union {
> +  struct {
> +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> memory
> +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through
> caching
> +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
> +    UINT64    Reserved             : 1;   // Reserved
> +    UINT64    MustBeZero           : 2;   // Must Be Zero
> +    UINT64    Available            : 3;   // Available for use by system software
> +    UINT64    PageTableBaseAddress : 40;  // Page Table Base Address
> +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> +    UINT64    Nx                   : 1;   // No Execute bit
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_MAP_AND_DIRECTORY_POINTER;
> +
> +//
> +// Page Table Entry 2MB
> +//
> +typedef union {
> +  struct {
> +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> memory
> +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through
> caching
> +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
> +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> access to page
> +    UINT64    MustBe1              : 1;   // Must be 1
> +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB not
> cleared on CR3 write
> +    UINT64    Available            : 3;   // Available for use by system software
> +    UINT64    Pat                  : 1;   //
> +    UINT64    MustBeZero           : 8;   // Must be zero
> +    UINT64    PageTableBaseAddress : 31;  // Page Table Base Address
> +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_ENTRY;
> +
> +//
> +// Page Table Entry 1GB
> +//
> +typedef union {
> +  struct {
> +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> memory
> +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-Through
> caching
> +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by CPU)
> +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> access to page
> +    UINT64    MustBe1              : 1;   // Must be 1
> +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB not
> cleared on CR3 write
> +    UINT64    Available            : 3;   // Available for use by system software
> +    UINT64    Pat                  : 1;   //
> +    UINT64    MustBeZero           : 17;  // Must be zero;
> +    UINT64    PageTableBaseAddress : 22;  // Page Table Base Address
> +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_1G_ENTRY;
> +
> +#pragma pack()
> +
> +//
> +// Global Descriptor Table (GDT)
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR
> mGdtEntries[] = {
> +  /* selector { Global Segment Descriptor                              } */
> +  /* 0x00 */ {
> +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> +  },                                                                      // null descriptor
> +  /* 0x08 */ {
> +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // linear data segment descriptor
> +  /* 0x10 */ {
> +    { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // linear code segment descriptor
> +  /* 0x18 */ {
> +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // system data segment descriptor
> +  /* 0x20 */ {
> +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // system code segment descriptor
> +  /* 0x28 */ {
> +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> +  },                                                                      // spare segment descriptor
> +  /* 0x30 */ {
> +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> +  },                                                                      // system data segment descriptor
> +  /* 0x38 */ {
> +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
> +  },                                                                      // system code segment descriptor
> +  /* 0x40 */ {
> +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> +  },                                                                      // spare segment descriptor
> +};
> +
> +//
> +// IA32 Gdt register
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR  mGdt = {
> +  sizeof (mGdtEntries) - 1,
> +  (UINTN)mGdtEntries
> +};
> +
> +/**
> +  Calculate the total size of page table.
> +
> +  @return The size of page table.
> +
> +**/
> +UINTN
> +CalculatePageTableSize (
> +  VOID
> +  )
> +{
> +  UINT32   RegEax;
> +  UINT32   RegEdx;
> +  UINTN    TotalPagesNum;
> +  UINT8    PhysicalAddressBits;
> +  VOID     *Hob;
> +  UINT32   NumberOfPml4EntriesNeeded;
> +  UINT32   NumberOfPdpEntriesNeeded;
> +  BOOLEAN  Page1GSupport;
> +
> +  Page1GSupport = FALSE;
> +  if (PcdGetBool (PcdUse1GPageTable)) {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000001) {
> +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +      if ((RegEdx & BIT26) != 0) {
> +        Page1GSupport = TRUE;
> +      }
> +    }
> +  }
> +
> +  //
> +  // Get physical address bits supported.
> +  //
> +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> +  if (Hob != NULL) {
> +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> +  } else {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000008) {
> +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> +      PhysicalAddressBits = (UINT8)RegEax;
> +    } else {
> +      PhysicalAddressBits = 36;
> +    }
> +  }
> +
> +  //
> +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
> +  //
> +  ASSERT (PhysicalAddressBits <= 52);
> +  if (PhysicalAddressBits > 48) {
> +    PhysicalAddressBits = 48;
> +  }
> +
> +  //
> +  // Calculate the table entries needed.
> +  //
> +  if (PhysicalAddressBits <= 39 ) {
> +    NumberOfPml4EntriesNeeded = 1;
> +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 30));
> +  } else {
> +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 39));
> +    NumberOfPdpEntriesNeeded  = 512;
> +  }
> +
> +  if (!Page1GSupport) {
> +    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) *
> NumberOfPml4EntriesNeeded + 1;
> +  } else {
> +    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
> +  }
> +
> +  return EFI_PAGES_TO_SIZE (TotalPagesNum);
> +}
> +
> +/**
> +  Allocates and fills in the Page Directory and Page Table Entries to
> +  establish a 1:1 Virtual to Physical mapping.
> +
> +  @param[in]  PageTablesAddress  The base address of page table.
> +
> +**/
> +VOID
> +CreateIdentityMappingPageTables (
> +  IN  EFI_PHYSICAL_ADDRESS  PageTablesAddress
> +  )
> +{
> +  UINT32                          RegEax;
> +  UINT32                          RegEdx;
> +  UINT8                           PhysicalAddressBits;
> +  EFI_PHYSICAL_ADDRESS            PageAddress;
> +  UINTN                           IndexOfPml4Entries;
> +  UINTN                           IndexOfPdpEntries;
> +  UINTN                           IndexOfPageDirectoryEntries;
> +  UINT32                          NumberOfPml4EntriesNeeded;
> +  UINT32                          NumberOfPdpEntriesNeeded;
> +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
> +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMap;
> +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
> +  PAGE_TABLE_ENTRY                *PageDirectoryEntry;
> +  UINTN                           BigPageAddress;
> +  VOID                            *Hob;
> +  BOOLEAN                         Page1GSupport;
> +  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
> +
> +  Page1GSupport = FALSE;
> +  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +  if (RegEax >= 0x80000001) {
> +    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +    if ((RegEdx & BIT26) != 0) {
> +      Page1GSupport = TRUE;
> +    }
> +  }
> +
> +  //
> +  // Get physical address bits supported.
> +  //
> +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> +  if (Hob != NULL) {
> +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> +  } else {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000008) {
> +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> +      PhysicalAddressBits = (UINT8)RegEax;
> +    } else {
> +      PhysicalAddressBits = 36;
> +    }
> +  }
> +
> +  //
> +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
> +  //
> +  ASSERT (PhysicalAddressBits <= 52);
> +  if (PhysicalAddressBits > 48) {
> +    PhysicalAddressBits = 48;
> +  }
> +
> +  //
> +  // Calculate the table entries needed.
> +  //
> +  if (PhysicalAddressBits <= 39 ) {
> +    NumberOfPml4EntriesNeeded = 1;
> +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 30));
> +  } else {
> +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits -
> 39));
> +    NumberOfPdpEntriesNeeded  = 512;
> +  }
> +
> +  //
> +  // Pre-allocate big pages to avoid later allocations.
> +  //
> +  BigPageAddress = (UINTN)PageTablesAddress;
> +
> +  //
> +  // By architecture only one PageMapLevel4 exists - so lets allocate storage for
> it.
> +  //
> +  PageMap         = (VOID *)BigPageAddress;
> +  BigPageAddress += SIZE_4KB;
> +
> +  PageMapLevel4Entry = PageMap;
> +  PageAddress        = 0;
> +  for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
> +    //
> +    // Each PML4 entry points to a page of Page Directory Pointer entires.
> +    // So lets allocate space for them and fill them in in the IndexOfPdpEntries
> loop.
> +    //
> +    PageDirectoryPointerEntry = (VOID *)BigPageAddress;
> +    BigPageAddress           += SIZE_4KB;
> +
> +    //
> +    // Make a PML4 Entry
> +    //
> +    PageMapLevel4Entry->Uint64         =
> (UINT64)(UINTN)PageDirectoryPointerEntry;
> +    PageMapLevel4Entry->Bits.ReadWrite = 1;
> +    PageMapLevel4Entry->Bits.Present   = 1;
> +
> +    if (Page1GSupport) {
> +      PageDirectory1GEntry = (VOID *)PageDirectoryPointerEntry;
> +
> +      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress +=
> SIZE_1GB) {
> +        //
> +        // Fill in the Page Directory entries
> +        //
> +        PageDirectory1GEntry->Uint64         = (UINT64)PageAddress;
> +        PageDirectory1GEntry->Bits.ReadWrite = 1;
> +        PageDirectory1GEntry->Bits.Present   = 1;
> +        PageDirectory1GEntry->Bits.MustBe1   = 1;
> +      }
> +    } else {
> +      for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> NumberOfPdpEntriesNeeded; IndexOfPdpEntries++,
> PageDirectoryPointerEntry++) {
> +        //
> +        // Each Directory Pointer entries points to a page of Page Directory entires.
> +        // So allocate space for them and fill them in in the
> IndexOfPageDirectoryEntries loop.
> +        //
> +        PageDirectoryEntry = (VOID *)BigPageAddress;
> +        BigPageAddress    += SIZE_4KB;
> +
> +        //
> +        // Fill in a Page Directory Pointer Entries
> +        //
> +        PageDirectoryPointerEntry->Uint64         =
> (UINT64)(UINTN)PageDirectoryEntry;
> +        PageDirectoryPointerEntry->Bits.ReadWrite = 1;
> +        PageDirectoryPointerEntry->Bits.Present   = 1;
> +
> +        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress +=
> SIZE_2MB) {
> +          //
> +          // Fill in the Page Directory entries
> +          //
> +          PageDirectoryEntry->Uint64         = (UINT64)PageAddress;
> +          PageDirectoryEntry->Bits.ReadWrite = 1;
> +          PageDirectoryEntry->Bits.Present   = 1;
> +          PageDirectoryEntry->Bits.MustBe1   = 1;
> +        }
> +      }
> +
> +      for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++,
> PageDirectoryPointerEntry++) {
> +        ZeroMem (
> +          PageDirectoryPointerEntry,
> +          sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> +          );
> +      }
> +    }
> +  }
> +
> +  //
> +  // For the PML4 entries we are not using fill in a null entry.
> +  //
> +  for ( ; IndexOfPml4Entries < 512; IndexOfPml4Entries++,
> PageMapLevel4Entry++) {
> +    ZeroMem (
> +      PageMapLevel4Entry,
> +      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> +      );
> +  }
> +}
> +
> +/**
> +  If in 32 bit protection mode, and coalesce image is of X64, switch to long mode.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @param  Context2                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully switched to long mode and execute
> coalesce.
> +  @retval Others                    Failed to execute coalesce in long mode.
> +
> +**/
> +EFI_STATUS
> +ModeSwitch (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1,
> +  IN VOID                  *Context2
> +  )
> +{
> +  UINTN            PageTableAddress;
> +  UINTN            PageTableSize;
> +  EFI_STATUS       Status;
> +  IA32_DESCRIPTOR  Gdtr;
> +
> +  DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
> +
> +  //
> +  // Save IA32 GDTR
> +  //
> +  AsmReadGdtr (&Gdtr);
> +
> +  //
> +  // Set X64 GDTR
> +  //
> +  AsmWriteGdtr (&mGdt);
> +
> +  PageTableAddress = AsmReadCr3 () & 0xFFFFF000;
> +
> +  //
> +  // If page table was created, no need to create
> +  //
> +  if (PageTableAddress == 0) {
> +    PageTableSize = CalculatePageTableSize ();
> +
> +    PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES
> (PageTableSize));
> +    ASSERT (PageTableAddress != 0);
> +
> +    CreateIdentityMappingPageTables (PageTableAddress);
> +
> +    AsmWriteCr3 ((UINTN)PageTableAddress);
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n"));
> +
> +  Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1,
> (UINT64)(UINTN)Context2, NULL);
> +  if (Status != 0) {
> +    Status = Status | MAX_BIT;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status));
> +
> +  //
> +  // Restore IA32 GDTR
> +  //
> +  AsmWriteGdtr (&Gdtr);
> +
> +  return Status;
> +}
> +
> +/**
> +  Load SMM core to dispatch other Standalone MM drivers.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> +  @retval Others                    Failed to load SMM core.
> +**/
> +EFI_STATUS
> +LoadSmmCore (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1
> +  )
> +{
> +  return ModeSwitch (Entry, Context1, NULL);
> +}
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> new file mode 100644
> index 0000000000..7fa42c32fb
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> @@ -0,0 +1,787 @@
> +/** @file
> +  SMM IPL that load the SMM Core into SMRAM at PEI stage
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <PiSmm.h>
> +#include <Ppi/SmmAccess.h>
> +#include <Ppi/SmmControl.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PeCoffLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PeiServicesTablePointerLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/PcdLib.h>
> +#include <Guid/SmramMemoryReserve.h>
> +#include <Guid/MmCoreData.h>
> +#include <StandaloneMmIplPei.h>
> +
> +//
> +// MM Core Private Data structure that contains the data shared between
> +// the SMM IPL and the Standalone MM Core.
> +//
> +MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
> +  MM_CORE_PRIVATE_DATA_SIGNATURE,     // Signature
> +  0,                                  // MmramRangeCount
> +  0,                                  // MmramRanges
> +  0,                                  // MmEntryPoint
> +  FALSE,                              // MmEntryPointRegistered
> +  FALSE,                              // InMm
> +  0,                                  // Mmst
> +  0,                                  // CommunicationBuffer
> +  0,                                  // BufferSize
> +  EFI_SUCCESS,                        // ReturnStatus
> +  0,                                  // MmCoreImageBase
> +  0,                                  // MmCoreImageSize
> +  0,                                  // MmCoreEntryPoint
> +  0,                                  // StandaloneBfvAddress
> +};
> +
> +//
> +// Global pointer used to access mMmCorePrivateData from outside and inside
> SMM
> +//
> +MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
> +
> +//
> +// SMM IPL global variables
> +//
> +PEI_SMM_ACCESS_PPI    *mSmmAccess;
> +EFI_SMRAM_DESCRIPTOR  *mCurrentSmramRange;
> +BOOLEAN               mSmmLocked = FALSE;
> +EFI_PHYSICAL_ADDRESS  mSmramCacheBase;
> +UINT64                mSmramCacheSize;
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR  mReadyToBootNotifyList = {
> +  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +  &gEfiEventReadyToBootGuid,
> +  ReadyToBootEvent
> +};
> +
> +/**
> +  This is the callback function on ready to boot.
> +
> +  Close and Lock smram range on ready to boot stage.
> +
> +  @param   PeiServices          General purpose services available to every PEIM.
> +  @param   NotifyDescriptor     The notification structure this PEIM registered on
> install.
> +  @param   Ppi                  Pointer to the PPI data associated with this function.
> +  @retval  EFI_SUCCESS          Close and lock smram ranges successfully.
> +  @retval  Other                Close and lock smram ranges failed.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadyToBootEvent (
> +  IN  EFI_PEI_SERVICES           **PeiServices,
> +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> +  IN  VOID                       *Ppi
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  //
> +  // Close all SMRAM ranges
> +  //
> +  Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Lock all SMRAM ranges
> +  //
> +  Status = mSmmAccess->Lock ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return Status;
> +}
> +
> +/**
> +  Find the maximum SMRAM cache range that covers the range specified by
> SmramRange.
> +
> +  This function searches and joins all adjacent ranges of SmramRange into a
> range to be cached.
> +
> +  @param   SmramRange       The SMRAM range to search from.
> +  @param   SmramCacheBase   The returned cache range base.
> +  @param   SmramCacheSize   The returned cache range size.
> +**/
> +VOID
> +GetSmramCacheRange (
> +  IN  EFI_SMRAM_DESCRIPTOR  *SmramRange,
> +  OUT EFI_PHYSICAL_ADDRESS  *SmramCacheBase,
> +  OUT UINT64                *SmramCacheSize
> +  )
> +{
> +  UINTN                 Index;
> +  EFI_PHYSICAL_ADDRESS  RangeCpuStart;
> +  UINT64                RangePhysicalSize;
> +  BOOLEAN               FoundAdjacentRange;
> +  EFI_SMRAM_DESCRIPTOR  *SmramRanges;
> +
> +  *SmramCacheBase = SmramRange->CpuStart;
> +  *SmramCacheSize = SmramRange->PhysicalSize;
> +
> +  SmramRanges = (EFI_SMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges;
> +  do {
> +    FoundAdjacentRange = FALSE;
> +    for (Index = 0; Index < gMmCorePrivate->MmramRangeCount; Index++) {
> +      RangeCpuStart     = SmramRanges[Index].CpuStart;
> +      RangePhysicalSize = SmramRanges[Index].PhysicalSize;
> +      if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase ==
> (RangeCpuStart + RangePhysicalSize))) {
> +        *SmramCacheBase    = RangeCpuStart;
> +        *SmramCacheSize   += RangePhysicalSize;
> +        FoundAdjacentRange = TRUE;
> +      } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) &&
> (RangePhysicalSize > 0)) {
> +        *SmramCacheSize   += RangePhysicalSize;
> +        FoundAdjacentRange = TRUE;
> +      }
> +    }
> +  } while (FoundAdjacentRange);
> +}
> +
> +/**
> +  Get the fixed loading address from image header assigned by build tool. This
> function only be called
> +  when Loading module at Fixed address feature enabled.
> +
> +  @param  ImageContext              Pointer to the image context structure that
> describes the PE/COFF
> +                                    image that needs to be examined by this function.
> +  @retval EFI_SUCCESS               An fixed loading address is assigned to this image
> by build tools .
> +  @retval EFI_NOT_FOUND             The image has no assigned fixed loading
> address.
> +**/
> +EFI_STATUS
> +GetPeCoffImageFixLoadingAssignedAddress (
> +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> +  )
> +{
> +  UINTN                            SectionHeaderOffset;
> +  EFI_STATUS                       Status;
> +  EFI_IMAGE_SECTION_HEADER         SectionHeader;
> +  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
> +  EFI_PHYSICAL_ADDRESS             FixLoadingAddress;
> +  UINT16                           Index;
> +  UINTN                            Size;
> +  UINT16                           NumberOfSections;
> +  EFI_PHYSICAL_ADDRESS             SmramBase;
> +  UINT64                           SmmCodeSize;
> +  UINT64                           ValueInSectionHeader;
> +
> +  //
> +  // Build tool will calculate the smm code size and then patch the
> PcdLoadFixAddressSmmCodePageNumber
> +  //
> +  SmmCodeSize       = EFI_PAGES_TO_SIZE (PcdGet32
> (PcdLoadFixAddressSmmCodePageNumber));
> +  FixLoadingAddress = 0;
> +  Status            = EFI_NOT_FOUND;
> +  SmramBase         = mCurrentSmramRange->CpuStart;
> +  //
> +  // Get PeHeader pointer
> +  //
> +  ImgHdr              = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8
> *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
> +  SectionHeaderOffset = (UINTN)(
> +                                ImageContext->PeCoffHeaderOffset +
> +                                sizeof (UINT32) +
> +                                sizeof (EFI_IMAGE_FILE_HEADER) +
> +                                ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
> +                                );
> +  NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
> +
> +  //
> +  // Get base address from the first section header that doesn't point to code
> section.
> +  //
> +  for (Index = 0; Index < NumberOfSections; Index++) {
> +    //
> +    // Read section header from file
> +    //
> +    Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
> +    Status = ImageContext->ImageRead (
> +                             ImageContext->Handle,
> +                             SectionHeaderOffset,
> +                             &Size,
> +                             &SectionHeader
> +                             );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    Status = EFI_NOT_FOUND;
> +
> +    if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
> +      //
> +      // Build tool saves the offset to SMRAM base as image base in
> PointerToRelocations & PointerToLineNumbers fields in the
> +      // first section header that doesn't point to code section in image header.
> And there is an assumption that when the
> +      // feature is enabled, if a module is assigned a loading address by tools,
> PointerToRelocations & PointerToLineNumbers
> +      // fields should NOT be Zero, or else, these 2 fields should be set to Zero
> +      //
> +      ValueInSectionHeader = ReadUnaligned64 ((UINT64
> *)&SectionHeader.PointerToRelocations);
> +      if (ValueInSectionHeader != 0) {
> +        //
> +        // Found first section header that doesn't point to code section in which
> build tool saves the
> +        // offset to SMRAM base as image base in PointerToRelocations &
> PointerToLineNumbers fields
> +        //
> +        FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase +
> (INT64)ValueInSectionHeader);
> +
> +        if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <=
> FixLoadingAddress)) {
> +          //
> +          // The assigned address is valid. Return the specified loading address
> +          //
> +          ImageContext->ImageAddress = FixLoadingAddress;
> +          Status                     = EFI_SUCCESS;
> +        }
> +      }
> +
> +      break;
> +    }
> +
> +    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
> +  }
> +
> +  DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO:
> Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status));
> +  return Status;
> +}
> +
> +/**
> +  Searches all the available firmware volumes and returns the first matching FFS
> section.
> +
> +  This function searches all the firmware volumes for FFS files with FV file type
> specified by FileType
> +  The order that the firmware volumes is searched is not deterministic. For each
> available FV a search
> +  is made for FFS file of type FileType. If the FV contains more than one FFS file
> with the same FileType,
> +  the FileInstance instance will be the matched FFS file. For each FFS file found a
> search
> +  is made for FFS sections of type SectionType. If the FFS file contains at least
> SectionInstance instances
> +  of the FFS section specified by SectionType, then the SectionInstance instance
> is returned in Buffer.
> +  Buffer is allocated using AllocatePool(), and the size of the allocated buffer is
> returned in Size.
> +  It is the caller's responsibility to use FreePool() to free the allocated buffer.
> +
> +  If Buffer is NULL, then ASSERT().
> +  If Size is NULL, then ASSERT().
> +
> +  @param  FileType             Indicates the FV file type to search for within all
> available FVs.
> +  @param  FileInstance         Indicates which file instance within all available FVs
> specified by FileType.
> +                               FileInstance starts from zero.
> +  @param  SectionType          Indicates the FFS section type to search for within
> the FFS file
> +                               specified by FileType with FileInstance.
> +  @param  SectionInstance      Indicates which section instance within the FFS
> file
> +                               specified by FileType with FileInstance to retrieve.
> SectionInstance starts from zero.
> +  @param  Buffer               On output, a pointer to a callee allocated buffer
> containing the FFS file section that was found.
> +                               Is it the caller's responsibility to free this buffer using
> FreePool().
> +  @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
> +
> +  @retval  EFI_SUCCESS          The specified FFS section was returned.
> +  @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
> +  @retval  EFI_OUT_OF_RESOURCES There are not enough resources available
> to retrieve the matching FFS section.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetSectionFromAnyFvByFileType  (
> +  IN  EFI_FV_FILETYPE   FileType,
> +  IN  UINTN             FileInstance,
> +  IN  EFI_SECTION_TYPE  SectionType,
> +  IN  UINTN             SectionInstance,
> +  OUT VOID              **Buffer,
> +  OUT UINTN             *Size
> +  )
> +{
> +  EFI_STATUS           Status;
> +  UINTN                FvIndex;
> +  EFI_PEI_FV_HANDLE    VolumeHandle;
> +  EFI_PEI_FILE_HANDLE  FileHandle;
> +  EFI_PE32_SECTION     *SectionData;
> +  UINT32               SectionSize;
> +
> +  //
> +  // Search all FV
> +  //
> +  VolumeHandle = NULL;
> +  for (FvIndex = 0; ; FvIndex++) {
> +    Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    //
> +    // Search PEIM FFS
> +    //
> +    FileHandle = NULL;
> +    Status     = PeiServicesFfsFindNextFile (FileType, VolumeHandle, &FileHandle);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    //
> +    // Search Section
> +    //
> +    SectionData = NULL;
> +    Status      = PeiServicesFfsFindSectionData (SectionType, FileHandle, Buffer);
> +    if (EFI_ERROR (Status)) {
> +      continue;
> +    }
> +
> +    //
> +    // Great!
> +    //
> +    SectionData = (EFI_PE32_SECTION *)((UINT8 *)*Buffer - sizeof
> (EFI_PE32_SECTION));
> +    ASSERT (SectionData->Type == SectionType);
> +    SectionSize  = *(UINT32 *)SectionData->Size;
> +    SectionSize &= 0xFFFFFF;
> +    *Size        = SectionSize - sizeof (EFI_PE32_SECTION);
> +
> +    if (FileType == EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
> +      EFI_FV_INFO  VolumeInfo;
> +      //
> +      // This is SMM BFV
> +      //
> +      Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
> +      if (!EFI_ERROR (Status)) {
> +        gMmCorePrivate->StandaloneBfvAddress =
> (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
> +      }
> +    }
> +
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Load the SMM Core image into SMRAM and executes the SMM Core from
> SMRAM.
> +
> +  @param[in, out] SmramRange            Descriptor for the range of SMRAM to
> reload the
> +                                        currently executing image, the rang of SMRAM to
> +                                        hold SMM Core will be excluded.
> +  @param[in, out] SmramRangeSmmCore     Descriptor for the range of SMRAM
> to hold SMM Core.
> +
> +  @param[in]      Context               Context to pass into SMM Core
> +
> +  @return  EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +ExecuteSmmCoreFromSmram (
> +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRange,
> +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRangeSmmCore,
> +  IN     VOID                  *Context
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  VOID                          *SourceBuffer;
> +  UINTN                         SourceSize;
> +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
> +  UINTN                         PageCount;
> +  VOID                          *HobList;
> +
> +  Status = PeiServicesGetHobList (&HobList);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Search all Firmware Volumes for a PE/COFF image in a file of type
> SMM_CORE
> +  //
> +  Status = GetSectionFromAnyFvByFileType (
> +             EFI_FV_FILETYPE_MM_CORE_STANDALONE,
> +             0,
> +             EFI_SECTION_PE32,
> +             0,
> +             &SourceBuffer,
> +             &SourceSize
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Initialize ImageContext
> +  //
> +  ImageContext.Handle    = SourceBuffer;
> +  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
> +
> +  //
> +  // Get information about the image being loaded
> +  //
> +  Status = PeCoffLoaderGetImageInfo (&ImageContext);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // if Loading module at Fixed Address feature is enabled, the SMM core driver
> will be loaded to
> +  // the address assigned by build tool.
> +  //
> +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> +    //
> +    // Get the fixed loading address assigned by Build tool
> +    //
> +    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Since the memory range to load SMM CORE will be cut out in SMM core,
> so no need to allocate and free this range
> +      //
> +      PageCount = 0;
> +      //
> +      // Reserved Smram Region for SmmCore is not used, and remove it from
> SmramRangeCount.
> +      //
> +      gMmCorePrivate->MmramRangeCount--;
> +    } else {
> +      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading module
> at fixed address at address failed\n"));
> +      //
> +      // Allocate memory for the image being loaded from the
> EFI_SRAM_DESCRIPTOR
> +      // specified by SmramRange
> +      //
> +      PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize
> + ImageContext.SectionAlignment);
> +
> +      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> +      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> +
> +      SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> +      SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> SmramRange->PhysicalSize;
> +      SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> SmramRange->PhysicalSize;
> +      SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> EFI_ALLOCATED;
> +      SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> +
> +      //
> +      // Align buffer on section boundary
> +      //
> +      ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> +    }
> +  } else {
> +    //
> +    // Allocate memory for the image being loaded from the
> EFI_SRAM_DESCRIPTOR
> +    // specified by SmramRange
> +    //
> +    PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize +
> ImageContext.SectionAlignment);
> +
> +    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> +    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> +
> +    SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> +    SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> SmramRange->PhysicalSize;
> +    SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> SmramRange->PhysicalSize;
> +    SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> EFI_ALLOCATED;
> +    SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> +
> +    //
> +    // Align buffer on section boundary
> +    //
> +    ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> +  }
> +
> +  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
> +  ImageContext.ImageAddress &=
> ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
> +
> +  //
> +  // Print debug message showing SMM Core load address.
> +  //
> +  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM
> address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
> +
> +  //
> +  // Load the image to our new buffer
> +  //
> +  Status = PeCoffLoaderLoadImage (&ImageContext);
> +  if (!EFI_ERROR (Status)) {
> +    //
> +    // Relocate the image in our new buffer
> +    //
> +    Status = PeCoffLoaderRelocateImage (&ImageContext);
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Flush the instruction cache so the image data are written before we
> execute it
> +      //
> +      InvalidateInstructionCacheRange ((VOID
> *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
> +
> +      //
> +      // Print debug message showing SMM Core entry point address.
> +      //
> +      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM
> address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
> +
> +      gMmCorePrivate->MmCoreImageBase = ImageContext.ImageAddress;
> +      gMmCorePrivate->MmCoreImageSize = ImageContext.ImageSize;
> +      DEBUG ((DEBUG_INFO, "SmmCoreImageBase - 0x%016lx\n",
> gMmCorePrivate->MmCoreImageBase));
> +      DEBUG ((DEBUG_INFO, "SmmCoreImageSize - 0x%016lx\n",
> gMmCorePrivate->MmCoreImageSize));
> +
> +      gMmCorePrivate->MmCoreEntryPoint = ImageContext.EntryPoint;
> +
> +      //
> +      // Print debug message showing Standalone MM Core entry point address.
> +      //
> +      DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM
> address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
> +
> +      //
> +      // Execute image
> +      //
> +      LoadSmmCore (ImageContext.EntryPoint, HobList);
> +    }
> +  }
> +
> +  //
> +  // If the load operation, relocate operation, or the image execution return an
> +  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR
> specified by
> +  // SmramRange
> +  //
> +  if (EFI_ERROR (Status)) {
> +    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
> +  }
> +
> +  //
> +  // Always free memory allocated by GetFileBufferByFilePath ()
> +  //
> +  FreePool (SourceBuffer);
> +
> +  return Status;
> +}
> +
> +/**
> +  Get full SMRAM ranges.
> +
> +  It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved
> ranges from
> +  SmmConfiguration protocol, split the entries if there is overlap between them.
> +  It will also reserve one entry for SMM core.
> +
> +  @param[in]  PeiServices           Describes the list of possible PEI Services.
> +  @param[out] FullSmramRangeCount   Output pointer to full SMRAM range
> count.
> +
> +  @return Pointer to full SMRAM ranges.
> +
> +**/
> +EFI_SMRAM_DESCRIPTOR *
> +GetFullSmramRanges (
> +  IN  CONST EFI_PEI_SERVICES  **PeiServices,
> +  OUT       UINTN             *FullSmramRangeCount
> +  )
> +{
> +  EFI_STATUS            Status;
> +  UINTN                 Size;
> +  EFI_SMRAM_DESCRIPTOR  *FullSmramRanges;
> +  UINTN                 AdditionSmramRangeCount;
> +  UINTN                 SmramRangeCount;
> +
> +  //
> +  // Get SMRAM information.
> +  //
> +  Size   = 0;
> +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, &Size, NULL);
> +  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
> +
> +  SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
> +
> +  //
> +  // Reserve one entry SMM Core in the full SMRAM ranges.
> +  //
> +  AdditionSmramRangeCount = 1;
> +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> +    //
> +    // Reserve two entries for all SMM drivers & SMM Core in the full SMRAM
> ranges.
> +    //
> +    AdditionSmramRangeCount = 2;
> +  }
> +
> +  *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
> +  Size                 = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);
> +  FullSmramRanges      = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
> +  ASSERT (FullSmramRanges != NULL);
> +  if (FullSmramRanges == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, &Size, FullSmramRanges);
> +
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return FullSmramRanges;
> +}
> +
> +/**
> +  The Entry Point for SMM IPL
> +
> +  Load SMM Core into SMRAM.
> +
> +  @param  FileHandle  Handle of the file being invoked.
> +  @param  PeiServices Describes the list of possible PEI Services.
> +
> +  @retval EFI_SUCCESS    The entry point is executed successfully.
> +  @retval Other          Some error occurred when executing this entry point.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmIplEntry (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  )
> +{
> +  EFI_STATUS             Status;
> +  UINTN                  Index;
> +  UINT64                 MaxSize;
> +  UINT64                 SmmCodeSize;
> +  MM_CORE_DATA_HOB_DATA  SmmCoreDataHobData;
> +  EFI_SMRAM_DESCRIPTOR   *MmramRanges;
> +  EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmDriver;
> +
> +  //
> +  // Build Hob for SMM and DXE phase
> +  //
> +  SmmCoreDataHobData.Address =
> (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES
> (sizeof (mMmCorePrivateData)));
> +  ASSERT (SmmCoreDataHobData.Address != 0);
> +  gMmCorePrivate = (VOID *)(UINTN)SmmCoreDataHobData.Address;
> +  CopyMem ((VOID *)(UINTN)SmmCoreDataHobData.Address,
> &mMmCorePrivateData, sizeof (mMmCorePrivateData));
> +  DEBUG ((DEBUG_INFO, "gMmCorePrivate - 0x%x\n", gMmCorePrivate));
> +
> +  BuildGuidDataHob (
> +    &gMmCoreDataHobGuid,
> +    (VOID *)&SmmCoreDataHobData,
> +    sizeof (SmmCoreDataHobData)
> +    );
> +
> +  //
> +  // Get SMM Access Protocol
> +  //
> +  Status = PeiServicesLocatePpi (&gPeiSmmAccessPpiGuid, 0, NULL, (VOID
> **)&mSmmAccess);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Get SMRAM information
> +  //
> +  gMmCorePrivate->MmramRanges =
> (EFI_PHYSICAL_ADDRESS)(UINTN)GetFullSmramRanges (PeiServices, (UINTN
> *)&gMmCorePrivate->MmramRangeCount);
> +  ASSERT (gMmCorePrivate->MmramRanges != 0);
> +  if (gMmCorePrivate->MmramRanges == 0) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Open all SMRAM ranges
> +  //
> +  Status = mSmmAccess->Open ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Print debug message that the SMRAM window is now open.
> +  //
> +  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
> +
> +  //
> +  // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB
> - 4K in size
> +  //
> +  mCurrentSmramRange = NULL;
> +  MmramRanges        = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges;
> +  if (MmramRanges == NULL) {
> +    DEBUG ((DEBUG_ERROR, "Fail to retrieve MmramRanges\n"));
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index <
> gMmCorePrivate->MmramRangeCount; Index++) {
> +    //
> +    // Skip any SMRAM region that is already allocated, needs testing, or needs
> ECC initialization
> +    //
> +    if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED |
> EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
> +      continue;
> +    }
> +
> +    if (MmramRanges[Index].CpuStart >= BASE_1MB) {
> +      if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize) <=
> BASE_4GB) {
> +        if (MmramRanges[Index].PhysicalSize >= MaxSize) {
> +          MaxSize            = MmramRanges[Index].PhysicalSize;
> +          mCurrentSmramRange = &MmramRanges[Index];
> +        }
> +      }
> +    }
> +  }
> +
> +  if (mCurrentSmramRange != NULL) {
> +    //
> +    // Print debug message showing SMRAM window that will be used by SMM
> IPL and SMM Core
> +    //
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "SMM IPL found SMRAM window %p - %p\n",
> +      (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
> +      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart +
> mCurrentSmramRange->PhysicalSize - 1)
> +      ));
> +
> +    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase,
> &mSmramCacheSize);
> +
> +    //
> +    // if Loading module at Fixed Address feature is enabled, save the SMRAM
> base to Load
> +    // Modules At Fixed Address Configuration Table.
> +    //
> +    if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> +      //
> +      // Build tool will calculate the smm code size and then patch the
> PcdLoadFixAddressSmmCodePageNumber
> +      //
> +      SmmCodeSize = LShiftU64 (PcdGet32
> (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
> +      //
> +      // The SMRAM available memory is assumed to be larger than SmmCodeSize
> +      //
> +      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
> +      //
> +      // Fill the Smram range for all SMM code
> +      //
> +      MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges;
> +      //
> +      // Note: SmramRanges specific for all SMM code will put in the
> gMmCorePrivate->MmramRangeCount - 2.
> +      //
> +      SmramRangeSmmDriver                = &MmramRanges[gMmCorePrivate-
> >MmramRangeCount - 2];
> +      SmramRangeSmmDriver->CpuStart      = mCurrentSmramRange->CpuStart;
> +      SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange-
> >PhysicalStart;
> +      SmramRangeSmmDriver->RegionState   = mCurrentSmramRange-
> >RegionState | EFI_ALLOCATED;
> +      SmramRangeSmmDriver->PhysicalSize  = SmmCodeSize;
> +
> +      mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
> +      mCurrentSmramRange->CpuStart      = mCurrentSmramRange->CpuStart +
> SmmCodeSize;
> +      mCurrentSmramRange->PhysicalStart = mCurrentSmramRange-
> >PhysicalStart + SmmCodeSize;
> +    }
> +
> +    //
> +    // Load SMM Core into SMRAM and execute it from SMRAM
> +    // Note: SmramRanges specific for SMM Core will put in the gMmCorePrivate-
> >MmramRangeCount - 1.
> +    //
> +    Status = ExecuteSmmCoreFromSmram (
> +               mCurrentSmramRange,
> +               &(((EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> >MmramRanges)[gMmCorePrivate->MmramRangeCount - 1]),
> +               gMmCorePrivate
> +               );
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Print error message that the SMM Core failed to be loaded and executed.
> +      //
> +      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core
> from SMRAM\n"));
> +    }
> +  } else {
> +    //
> +    // Print error message that there are not enough SMRAM resources to load
> the SMM Core.
> +    //
> +    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM
> region to load SMM Core\n"));
> +  }
> +
> +  //
> +  // If the SMM Core could not be loaded then close SMRAM window, free
> allocated
> +  // resources, and return an error so SMM IPL will be unloaded.
> +  //
> +  if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
> +    //
> +    // Close all SMRAM ranges
> +    //
> +    Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> mSmmAccess, 0);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    //
> +    // Print debug message that the SMRAM window is now closed.
> +    //
> +    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
> +
> +    //
> +    // Free all allocated resources
> +    //
> +    FreePool ((VOID *)(UINTN)gMmCorePrivate->MmramRanges);
> +
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Create ready to boot for close and lock smram ranges
> +  //
> +  Status = PeiServicesNotifyPpi (&mReadyToBootNotifyList);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> new file mode 100644
> index 0000000000..6d3497f2ea
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> @@ -0,0 +1,32 @@
> +/** @file
> +  SMM IPL that load the SMM Core into SMRAM
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <PiSmm.h>
> +#include <StandaloneMm.h>
> +
> +/**
> +  Load SMM core to dispatch other Standalone MM drivers.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> +  @retval Others                    Failed to load SMM core.
> +**/
> +EFI_STATUS
> +LoadSmmCore (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1
> +  )
> +{
> +  STANDALONE_MM_FOUNDATION_ENTRY_POINT  EntryPoint;
> +
> +  EntryPoint = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
> +  return EntryPoint (Context1);
> +}
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> new file mode 100644
> index 0000000000..7f887eb77d
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> @@ -0,0 +1,148 @@
> +;------------------------------------------------------------------------------
> +;
> +; Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> +;
> +; Module Name:
> +;
> +;    Thunk32To64.nasm
> +;
> +; Abstract:
> +;
> +;   This is the assembly code to transition from long mode to compatibility
> +;   mode to execute 32-bit code and then transit back to long mode.
> +;
> +;------------------------------------------------------------------------------
> +
> +    SECTION .text
> +
> +;------------------------------------------------------------------------------
> +; Procedure:    AsmExecute64BitCode
> +;
> +; Input:        None
> +;
> +; Output:       None
> +;
> +; Prototype:    UINT32
> +;               AsmExecute64BitCode (
> +;                 IN UINT64           Function,
> +;                 IN UINT64           Param1,
> +;                 IN UINT64           Param2,
> +;                 IN IA32_DESCRIPTOR  *InternalGdtr
> +;                 );
> +;
> +;
> +; Description:  A thunk function to execute 32-bit code in long mode.
> +;
> +;------------------------------------------------------------------------------
> +global ASM_PFX(AsmExecute64BitCode)
> +ASM_PFX(AsmExecute64BitCode):
> +;
> +; +---------+
> +; | EIP(64) |
> +; +---------+
> +; | CS (64) |
> +; +---------+
> +; | EIP(32) |
> +; +---------+
> +; | CS (32) |<-ESP (16 bytes aligned)
> +; +---------+
> +; | ...     |
> +; +---------+
> +; | ebx     |<-EBP
> +; +---------+
> +; | ebp     |<-EBP + 4
> +; +---------+
> +; | esi     |<-EBP + 8
> +; +---------+
> +; | edi     |<-EBP + 12
> +; +---------+
> +; | RFlags  |<-EBP + 16
> +; +---------+
> +; | RetAddr |<-EBP (org)
> +; +---------+
> +; | Func    |<-EBP + 24
> +; | Func    |
> +; +---------+
> +; | Param1  |<-EBP + 32
> +; | Param1  |
> +; +---------+
> +; | Param2  |<-EBP + 40
> +; | Param2  |
> +; +---------+
> +; | Gdtr    |
> +; +---------+
> +;
> +    ;
> +    ; Save general purpose register and RFlags register
> +    ;
> +    pushfd
> +    push    edi
> +    push    esi
> +    push    ebp
> +    push    ebx
> +    mov     ebp, esp
> +
> +    and     esp, 0FFFFFFF0h
> +
> +    push    010h                        ; protected mode selector on stack
> +    mov     eax, Compatible             ; offset for LongMode
> +    push    eax                         ; offset on stack
> +
> +    push    038h                        ; long mode selector on stack
> +    mov     eax, LongMode               ; offset for LongMode
> +    push    eax                         ; offset on stack
> +
> +    mov     eax, cr4
> +    or      al, 020h
> +    mov     cr4, eax                    ; enable PAE
> +    mov     ecx, 0c0000080h
> +    rdmsr
> +    or      ah, 1                       ; set LME
> +    wrmsr
> +    mov     eax, cr0
> +    bts     eax, 31                     ; set PG
> +    mov     cr0, eax                    ; enable paging
> +    retf                                ; topmost 2 dwords hold the address
> +LongMode:                               ; long mode starts here
> +
> +    ; Call long mode function
> +    DB      67h, 48h                    ; 32-bit address size, 64-bit operand size
> +    mov     eax, [ebp + 24]             ; mov rbx, [ebp + 24]
> +    DB      67h, 48h
> +    mov     ecx, [ebp + 24 + 8]         ; mov rcx, [ebp + 24 + 8]
> +    DB      67h, 48h
> +    mov     edx, [ebp + 24 + 16]        ; mov rdx, [ebp + 24 + 16]
> +
> +    DB      48h
> +    add     esp, -20h                   ; add rsp, -20h
> +    call    eax                         ; call rax
> +    DB      48h
> +    add     esp, 20h                    ; add rsp, 20h
> +
> +    ; after long mode function call
> +    mov     ebx, eax
> +
> +    retf
> +Compatible:
> +    mov     ecx, cr0
> +    btc     ecx, 31                     ; clear PG
> +    mov     cr0, ecx                    ; disable paging
> +    mov     ecx, 0C0000080h
> +    rdmsr
> +    btc     eax, 8                      ; clear LME
> +    wrmsr
> +
> +    ;
> +    ; Restore C register and eax hold the return status from 32-bit function.
> +    ; Note: Do not touch rax from now which hold the return value from IA32
> function
> +    ;
> +    mov     eax, ebx                    ; put return status to EAX
> +    mov     esp, ebp                    ; restore stack pointer
> +    pop     ebx
> +    pop     ebp
> +    pop     esi
> +    pop     edi
> +    popfd
> +
> +    ret
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> new file mode 100644
> index 0000000000..be0aae70f0
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> @@ -0,0 +1,66 @@
> +/** @file
> +  Private header with declarations and definitions specific to the Standalone
> +  MM IPL PEI driver
> +
> +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef STANDALONE_MM_IPL_PEI_H_
> +#define STANDALONE_MM_IPL_PEI_H_
> +
> +/**
> +  Load SMM core to dispatch other Standalone MM drivers.
> +
> +  @param  Entry                     Entry of Standalone MM Foundation.
> +  @param  Context1                  A pointer to the context to pass into the
> EntryPoint
> +                                    function.
> +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> +  @retval Others                    Failed to load SMM core.
> +**/
> +EFI_STATUS
> +LoadSmmCore (
> +  IN EFI_PHYSICAL_ADDRESS  Entry,
> +  IN VOID                  *Context1
> +  );
> +
> +/**
> +  Assembly function to transition from long mode to compatibility mode to
> +  execute 32-bit code and then transit back to long mode.
> +
> +  @param[in] Function     The 32bit code entry to be executed.
> +  @param[in] Param1       The first parameter to pass to 32bit code
> +  @param[in] Param2       The second parameter to pass to 32bit code
> +  @param[in] InternalGdtr The GDT and GDT descriptor used by this library
> +
> +  @retval status.
> +**/
> +UINT32
> +AsmExecute64BitCode (
> +  IN UINT64           Function,
> +  IN UINT64           Param1,
> +  IN UINT64           Param2,
> +  IN IA32_DESCRIPTOR  *InternalGdtr
> +  );
> +
> +/**
> +  This is the callback function on ready to boot.
> +
> +  Close and lock smram ranges on ready to boot stage.
> +
> +  @param   PeiServices       General purpose services available to every PEIM.
> +  @param   NotifyDescriptor  The notification structure this PEIM registered on
> install.
> +  @param   Ppi               Pointer to the PPI data associated with this function.
> +  @retval  EFI_SUCCESS       Close and lock smram ranges successfully.
> +  @retval  Other             Close and lock smram ranges failed.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ReadyToBootEvent (
> +  IN  EFI_PEI_SERVICES           **PeiServices,
> +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> +  IN  VOID                       *Ppi
> +  );
> +
> +#endif
> diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> new file mode 100644
> index 0000000000..ff4c67a92c
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> @@ -0,0 +1,75 @@
> +## @file
> +#  This module provide a Standalone SMM compliant implementation of SMM
> IPL PEIM.
> +#
> +#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = StandaloneMmIplPei
> +  FILE_GUID                      = 578A0D17-2DC0-4C7D-A121-D8D771923BB0
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  PI_SPECIFICATION_VERSION       = 0x0001000A
> +  ENTRY_POINT                    = SmmIplEntry
> +
> +#
> +# The following information is for reference only and not required by the build
> tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  StandaloneMmIplPei.h
> +  StandaloneMmIplPei.c
> +
> +[Sources.Ia32]
> +  Ia32/LoadSmmCore.c
> +  Ia32/Thunk32To64.nasm
> +
> +[Sources.X64]
> +  X64/LoadSmmCore.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  StandaloneMmPkg/StandaloneMmPkg.dec
> +
> +[LibraryClasses]
> +  PeimEntryPoint
> +  PeiServicesTablePointerLib
> +  PeiServicesLib
> +  BaseLib
> +  BaseMemoryLib
> +  PeCoffLib
> +  CacheMaintenanceLib
> +  MemoryAllocationLib
> +  DebugLib
> +  HobLib
> +  IntrinsicLib
> +
> +[Guids]
> +  gMmCoreDataHobGuid
> +  gEfiEventReadyToBootGuid
> +
> +[Ppis]
> +  gPeiSmmAccessPpiGuid                     ## CONSUMES
> +  gPeiSmmControlPpiGuid                    ## CONSUMES
> +
> +[FeaturePcd.IA32]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ##
> CONSUMES
> +
> +[Pcd.IA32]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ##
> SOMETIMES_CONSUMES
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber
> ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable        ##
> CONSUMES
> +
> +[Depex]
> +  gPeiSmmAccessPpiGuid AND
> +  gPeiSmmControlPpiGuid
> +
> diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> index 4777532a7e..872f7958be 100644
> --- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> +++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> @@ -78,7 +78,9 @@
>      ## options defined .pytool/Plugin/SpellCheck
>      "SpellCheck": {
>          "AuditOnly": False,
> -        "IgnoreFiles": [],           # use gitignore syntax to ignore errors
> +        "IgnoreFiles": [
> +            "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm"
> +        ],           # use gitignore syntax to ignore errors
>                                       # in matching files
>          "ExtendWords": [
>              "Bsymbolic",
> diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc
> b/StandaloneMmPkg/StandaloneMmPkg.dsc
> index 8012f93b7d..d88471fe82 100644
> --- a/StandaloneMmPkg/StandaloneMmPkg.dsc
> +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc
> @@ -20,7 +20,7 @@
>    PLATFORM_VERSION               = 1.0
>    DSC_SPECIFICATION              = 0x00010011
>    OUTPUT_DIRECTORY               = Build/StandaloneMm
> -  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM
> +  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM|IA32
>    BUILD_TARGETS                  = DEBUG|RELEASE
>    SKUID_IDENTIFIER               = DEFAULT
> 
> @@ -60,6 +60,14 @@
> 
> StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoin
> t/StandaloneMmDriverEntryPoint.inf
> 
> VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/V
> ariableMmDependency.inf
> 
> +[LibraryClasses.common.PEIM]
> +  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> +  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
> +
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAlloc
> ationLib.inf
> +  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> +
> PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServic
> esTablePointerLib.inf
> +  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
> +
>  [LibraryClasses.AARCH64, LibraryClasses.ARM]
>    ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
> 
> StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStand
> aloneMmLib.inf
> @@ -104,7 +112,7 @@
>  #       generated for it, but the binary will not be put into any firmware volume.
>  #
> 
> #################################################################
> ##################################
> -[Components.common]
> +[Components.AARCH64, Components.ARM, Components.X64]
>    #
>    # MM Core
>    #
> @@ -122,6 +130,9 @@
>    StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
> 
> StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMm
> PeCoffExtraActionLib.inf
> 
> +[Components.X64, Components.IA32]
> +  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> +
> 
> #################################################################
> ##################################
>  #
>  # BuildOptions Section - Define the module specific tool chain flags that should
> be used as
> diff --git a/UefiPayloadPkg/UniversalPayloadBuild.sh
> b/UefiPayloadPkg/UniversalPayloadBuild.sh
> index 9a72eedd35..bacf5233a8 100644
> --- a/UefiPayloadPkg/UniversalPayloadBuild.sh
> +++ b/UefiPayloadPkg/UniversalPayloadBuild.sh
> @@ -1,17 +1,17 @@
> -#!/usr/bin/env bash
> -#
> -# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> -#
> -# SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
> -
> -if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> -    echo python_exe=${PYTHON_COMMAND}
> -fi
> -
> -# Get file path of UniversalPayloadBuild.sh
> -uplbld_filepath=${BASH_SOURCE:-$0}
> -# Remove ".sh" extension
> -uplbld_filepath_noext=${uplbld_filepath%.*}
> -# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> -exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> +#!/usr/bin/env bash
> +#
> +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +
> +if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> +    echo python_exe=${PYTHON_COMMAND}
> +fi
> +
> +# Get file path of UniversalPayloadBuild.sh
> +uplbld_filepath=${BASH_SOURCE:-$0}
> +# Remove ".sh" extension
> +uplbld_filepath_noext=${uplbld_filepath%.*}
> +# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> +exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> diff --git a/edksetup.sh b/edksetup.sh
> index cab3a8c113..553e1676d0 100755
> --- a/edksetup.sh
> +++ b/edksetup.sh
> @@ -1,147 +1,147 @@
> -#
> -# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> -# SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
> -# In *inux environment, the build tools's source is required and need to be
> compiled
> -# firstly, please reference
> https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-Github-
> Quick-Start
> -# to get how to setup build tool.
> -#
> -# Setup the environment for unix-like systems running a bash-like shell.
> -# This file must be "sourced" not merely executed. For example: ". edksetup.sh"
> -#
> -# CYGWIN users: Your path and filename related environment variables should
> be
> -# set up in the unix style.  This script will make the necessary conversions to
> -# windows style.
> -#
> -# Please reference edk2 user manual for more detail descriptions at
> https://github.com/tianocore-
> docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> -#
> -
> -SCRIPTNAME="edksetup.sh"
> -RECONFIG=FALSE
> -
> -HelpMsg()
> -{
> -  echo "Usage: $SCRIPTNAME [Options]"
> -  echo
> -  echo "The system environment variable, WORKSPACE, is always set to the
> current"
> -  echo "working directory."
> -  echo
> -  echo "Options: "
> -  echo "  --help, -h, -?        Print this help screen and exit."
> -  echo
> -  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with the"
> -  echo "                        template files from the BaseTools/Conf directory."
> -  echo
> -  echo Please note: This script must be \'sourced\' so the environment can be
> changed.
> -  echo ". $SCRIPTNAME"
> -  echo "source $SCRIPTNAME"
> -}
> -
> -SetWorkspace()
> -{
> -  #
> -  # If WORKSPACE is already set, then we can return right now
> -  #
> -  export PYTHONHASHSEED=1
> -  if [ -n "$WORKSPACE" ]
> -  then
> -    return 0
> -  fi
> -
> -  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> -  then
> -    echo Source this script from the base of your tree.  For example:
> -    echo "  cd /Path/To/Edk2/Clone"
> -    echo "  . $SCRIPTNAME"
> -    return 1
> -  fi
> -
> -  #
> -  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> -  #
> -  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> -  then
> -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> -    echo Please point EDK_TOOLS_PATH at the directory that contains
> -    echo the EDK2 BuildEnv script.
> -    return 1
> -  fi
> -
> -  #
> -  # Set $WORKSPACE
> -  #
> -  export WORKSPACE=$PWD
> -  return 0
> -}
> -
> -SetupEnv()
> -{
> -  if [ -n "$EDK_TOOLS_PATH" ]
> -  then
> -    . $EDK_TOOLS_PATH/BuildEnv
> -  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> -  then
> -    . $WORKSPACE/BaseTools/BuildEnv
> -  elif [ -n "$PACKAGES_PATH" ]
> -  then
> -    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> -    do
> -      if [ -f "$DIR/BaseTools/BuildEnv" ]
> -      then
> -        export EDK_TOOLS_PATH=$DIR/BaseTools
> -        . $DIR/BaseTools/BuildEnv
> -        break
> -      fi
> -    done
> -  else
> -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> -    echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly
> -    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> -    echo the EDK2 BuildEnv script.
> -    return 1
> -  fi
> -}
> -
> -SetupPython3()
> -{
> -  export PYTHON_COMMAND=python3
> -}
> -
> -SourceEnv()
> -{
> -  SetupPython3
> -  SetWorkspace
> -  SetupEnv
> -}
> -
> -I=$#
> -while [ $I -gt 0 ]
> -do
> -  case "$1" in
> -    BaseTools)
> -      # Ignore argument for backwards compatibility
> -      shift
> -    ;;
> -    --reconfig)
> -      RECONFIG=TRUE
> -      shift
> -    ;;
> -    *)
> -      HelpMsg
> -      break
> -    ;;
> -  esac
> -  I=$((I - 1))
> -done
> -
> -if [ $I -gt 0 ]
> -then
> -  return 1
> -fi
> -
> -SourceEnv
> -
> -unset SCRIPTNAME RECONFIG
> -
> -return $?
> +#
> +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +# In *inux environment, the build tools's source is required and need to be
> compiled
> +# firstly, please reference
> https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-Github-
> Quick-Start
> +# to get how to setup build tool.
> +#
> +# Setup the environment for unix-like systems running a bash-like shell.
> +# This file must be "sourced" not merely executed. For example: ". edksetup.sh"
> +#
> +# CYGWIN users: Your path and filename related environment variables should
> be
> +# set up in the unix style.  This script will make the necessary conversions to
> +# windows style.
> +#
> +# Please reference edk2 user manual for more detail descriptions at
> https://github.com/tianocore-
> docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> +#
> +
> +SCRIPTNAME="edksetup.sh"
> +RECONFIG=FALSE
> +
> +HelpMsg()
> +{
> +  echo "Usage: $SCRIPTNAME [Options]"
> +  echo
> +  echo "The system environment variable, WORKSPACE, is always set to the
> current"
> +  echo "working directory."
> +  echo
> +  echo "Options: "
> +  echo "  --help, -h, -?        Print this help screen and exit."
> +  echo
> +  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with the"
> +  echo "                        template files from the BaseTools/Conf directory."
> +  echo
> +  echo Please note: This script must be \'sourced\' so the environment can be
> changed.
> +  echo ". $SCRIPTNAME"
> +  echo "source $SCRIPTNAME"
> +}
> +
> +SetWorkspace()
> +{
> +  #
> +  # If WORKSPACE is already set, then we can return right now
> +  #
> +  export PYTHONHASHSEED=1
> +  if [ -n "$WORKSPACE" ]
> +  then
> +    return 0
> +  fi
> +
> +  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> +  then
> +    echo Source this script from the base of your tree.  For example:
> +    echo "  cd /Path/To/Edk2/Clone"
> +    echo "  . $SCRIPTNAME"
> +    return 1
> +  fi
> +
> +  #
> +  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> +  #
> +  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> +  then
> +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> +    echo Please point EDK_TOOLS_PATH at the directory that contains
> +    echo the EDK2 BuildEnv script.
> +    return 1
> +  fi
> +
> +  #
> +  # Set $WORKSPACE
> +  #
> +  export WORKSPACE=$PWD
> +  return 0
> +}
> +
> +SetupEnv()
> +{
> +  if [ -n "$EDK_TOOLS_PATH" ]
> +  then
> +    . $EDK_TOOLS_PATH/BuildEnv
> +  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> +  then
> +    . $WORKSPACE/BaseTools/BuildEnv
> +  elif [ -n "$PACKAGES_PATH" ]
> +  then
> +    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> +    do
> +      if [ -f "$DIR/BaseTools/BuildEnv" ]
> +      then
> +        export EDK_TOOLS_PATH=$DIR/BaseTools
> +        . $DIR/BaseTools/BuildEnv
> +        break
> +      fi
> +    done
> +  else
> +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> +    echo Please check that WORKSPACE or PACKAGES_PATH is not set incorrectly
> +    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> +    echo the EDK2 BuildEnv script.
> +    return 1
> +  fi
> +}
> +
> +SetupPython3()
> +{
> +  export PYTHON_COMMAND=python3
> +}
> +
> +SourceEnv()
> +{
> +  SetupPython3
> +  SetWorkspace
> +  SetupEnv
> +}
> +
> +I=$#
> +while [ $I -gt 0 ]
> +do
> +  case "$1" in
> +    BaseTools)
> +      # Ignore argument for backwards compatibility
> +      shift
> +    ;;
> +    --reconfig)
> +      RECONFIG=TRUE
> +      shift
> +    ;;
> +    *)
> +      HelpMsg
> +      break
> +    ;;
> +  esac
> +  I=$((I - 1))
> +done
> +
> +if [ $I -gt 0 ]
> +then
> +  return 1
> +fi
> +
> +SourceEnv
> +
> +unset SCRIPTNAME RECONFIG
> +
> +return $?
> --
> 2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105858): https://edk2.groups.io/g/devel/message/105858
Mute This Topic: https://groups.io/mt/99079640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
Posted by Yao, Jiewen 10 months, 3 weeks ago
> 5th patch register ReadyToBoot callback. But is it too late from security perspective? Why not lock after SMM core exit? @Yao, Jiewen

Agree with Ray. ReadyToBoot is too late.



> -----Original Message-----
> From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> Sent: Wednesday, June 7, 2023 10:29 AM
> To: Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io; Yao, Jiewen
> <jiewen.yao@intel.com>
> Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami
> Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Supreeth Venkatesh
> <supreeth.venkatesh@arm.com>; Bu, Daocheng <daocheng.bu@intel.com>;
> Chen, Bo <bo.chen@intel.com>
> Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Thanks Ray.
> Replied your code comments with [Hongbin].
> And I will split to several patches, it will be better for reviewing.
> 
> -----Original Message-----
> From: Ni, Ray <ray.ni@intel.com>
> Sent: Wednesday, June 7, 2023 10:04 AM
> To: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; devel@edk2.groups.io; Yao,
> Jiewen <jiewen.yao@intel.com>
> Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami
> Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Supreeth Venkatesh
> <supreeth.venkatesh@arm.com>
> Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Hongbin,
> The patch is so big. Can you please split the patch to small patches? For example:
> 1st patch only implements the Ipl entrypoint to find the correct SMRAM range
> and dump it
> 2nd patch loads SMM CORE without mode switch if sizeof (UINTN) matches
> SMM core module type.
> 3rd patch loads SMM CORE with mode switch if sizeof (UINTN) == 4 but SMM
> core module type is 64bit.
> 4th patch Deadloop() when sizeof (UINTN) == 8 but SMM core module type is
> 32bit.
> 5th patch register ReadyToBoot callback. But is it too late from security
> perspective? Why not lock after SMM core exit? @Yao, Jiewen
> 
> Back to the code content, 3 comments:
> 1. Have you tested the flow when LoadImageAtFixedAddress is enabled? If no, I
> prefer you do not add the logic at all in the first version. We can enable that
> later.
>      -- Yes, currently PcdLoadModuleAtFixAddressEnable was not used and
> verified, I will add later [Hongbin].
> 2. "EFIAPI" for GetSectionFromAnyFvByFileType should be removed. And the
> function prototype could be refined as below:
>     EFI_STATUS
>     LocateMmFvAndCore
>       OUT EFI_PHYSICAL_ADDRESS  *MmFvBaseAddress,
>       OUT VOID                  **MmCoreImageAddress
>     Please avoid directly modifying global variables inside this function.
>      -- Ok, will change that [Hongbin].
> 3. Can the StandaloneMmCore in open source be directly used with this IPL?
>      -- I will think about this later [Hongbin].
> 
> Thanks,
> Ray
> 
> 
> > -----Original Message-----
> > From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> > Sent: Monday, May 22, 2023 1:21 PM
> > To: devel@edk2.groups.io
> > Cc: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Yao, Jiewen
> > <jiewen.yao@intel.com>; Ni, Ray <ray.ni@intel.com>; Zeng, Star
> > <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar
> > <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> > Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> > Subject: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> >
> > Add StandaloneMmIplPei IA32/X64 driver at PEI stage.
> > FSP will use this driver to load Standalone MM code
> > to dispatch other Standalone MM drivers.
> >
> > Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> > Cc: Sami Mujawar <sami.mujawar@arm.com>
> > Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> > Cc: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> > ---
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     |
> 456
> > ++++++++++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   |
> 787
> > ++++++++++++++++++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |
> 32 +
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  |
> 148
> > ++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66
> > ++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |
> 75
> > ++
> >  StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
> >  StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
> >  UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
> >  edksetup.sh                                                       | 294 ++++----
> >  10 files changed, 1744 insertions(+), 167 deletions(-)
> >
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > new file mode 100644
> > index 0000000000..d6174d73a3
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > @@ -0,0 +1,456 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <StandaloneMm.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <StandaloneMmIplPei.h>
> > +
> > +#pragma pack(1)
> > +
> > +//
> > +// Page-Map Level-4 Offset (PML4) and
> > +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
> > +//
> > +
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Reserved             : 1;   // Reserved
> > +    UINT64    MustBeZero           : 2;   // Must Be Zero
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    PageTableBaseAddress : 40;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // No Execute bit
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_MAP_AND_DIRECTORY_POINTER;
> > +
> > +//
> > +// Page Table Entry 2MB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> > access to page
> > +    UINT64    MustBe1              : 1;   // Must be 1
> > +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB
> not
> > cleared on CR3 write
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    Pat                  : 1;   //
> > +    UINT64    MustBeZero           : 8;   // Must be zero
> > +    UINT64    PageTableBaseAddress : 31;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_ENTRY;
> > +
> > +//
> > +// Page Table Entry 1GB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> > access to page
> > +    UINT64    MustBe1              : 1;   // Must be 1
> > +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB
> not
> > cleared on CR3 write
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    Pat                  : 1;   //
> > +    UINT64    MustBeZero           : 17;  // Must be zero;
> > +    UINT64    PageTableBaseAddress : 22;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_1G_ENTRY;
> > +
> > +#pragma pack()
> > +
> > +//
> > +// Global Descriptor Table (GDT)
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR
> > mGdtEntries[] = {
> > +  /* selector { Global Segment Descriptor                              } */
> > +  /* 0x00 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // null descriptor
> > +  /* 0x08 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // linear data segment descriptor
> > +  /* 0x10 */ {
> > +    { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // linear code segment descriptor
> > +  /* 0x18 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system data segment descriptor
> > +  /* 0x20 */ {
> > +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system code segment descriptor
> > +  /* 0x28 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // spare segment descriptor
> > +  /* 0x30 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system data segment descriptor
> > +  /* 0x38 */ {
> > +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
> > +  },                                                                      // system code segment descriptor
> > +  /* 0x40 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // spare segment descriptor
> > +};
> > +
> > +//
> > +// IA32 Gdt register
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR  mGdt = {
> > +  sizeof (mGdtEntries) - 1,
> > +  (UINTN)mGdtEntries
> > +};
> > +
> > +/**
> > +  Calculate the total size of page table.
> > +
> > +  @return The size of page table.
> > +
> > +**/
> > +UINTN
> > +CalculatePageTableSize (
> > +  VOID
> > +  )
> > +{
> > +  UINT32   RegEax;
> > +  UINT32   RegEdx;
> > +  UINTN    TotalPagesNum;
> > +  UINT8    PhysicalAddressBits;
> > +  VOID     *Hob;
> > +  UINT32   NumberOfPml4EntriesNeeded;
> > +  UINT32   NumberOfPdpEntriesNeeded;
> > +  BOOLEAN  Page1GSupport;
> > +
> > +  Page1GSupport = FALSE;
> > +  if (PcdGetBool (PcdUse1GPageTable)) {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000001) {
> > +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> > +      if ((RegEdx & BIT26) != 0) {
> > +        Page1GSupport = TRUE;
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8)RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +
> > +  //
> > +  // Calculate the table entries needed.
> > +  //
> > +  if (PhysicalAddressBits <= 39 ) {
> > +    NumberOfPml4EntriesNeeded = 1;
> > +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 30));
> > +  } else {
> > +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 39));
> > +    NumberOfPdpEntriesNeeded  = 512;
> > +  }
> > +
> > +  if (!Page1GSupport) {
> > +    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) *
> > NumberOfPml4EntriesNeeded + 1;
> > +  } else {
> > +    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
> > +  }
> > +
> > +  return EFI_PAGES_TO_SIZE (TotalPagesNum);
> > +}
> > +
> > +/**
> > +  Allocates and fills in the Page Directory and Page Table Entries to
> > +  establish a 1:1 Virtual to Physical mapping.
> > +
> > +  @param[in]  PageTablesAddress  The base address of page table.
> > +
> > +**/
> > +VOID
> > +CreateIdentityMappingPageTables (
> > +  IN  EFI_PHYSICAL_ADDRESS  PageTablesAddress
> > +  )
> > +{
> > +  UINT32                          RegEax;
> > +  UINT32                          RegEdx;
> > +  UINT8                           PhysicalAddressBits;
> > +  EFI_PHYSICAL_ADDRESS            PageAddress;
> > +  UINTN                           IndexOfPml4Entries;
> > +  UINTN                           IndexOfPdpEntries;
> > +  UINTN                           IndexOfPageDirectoryEntries;
> > +  UINT32                          NumberOfPml4EntriesNeeded;
> > +  UINT32                          NumberOfPdpEntriesNeeded;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMap;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
> > +  PAGE_TABLE_ENTRY                *PageDirectoryEntry;
> > +  UINTN                           BigPageAddress;
> > +  VOID                            *Hob;
> > +  BOOLEAN                         Page1GSupport;
> > +  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
> > +
> > +  Page1GSupport = FALSE;
> > +  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +  if (RegEax >= 0x80000001) {
> > +    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> > +    if ((RegEdx & BIT26) != 0) {
> > +      Page1GSupport = TRUE;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8)RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +
> > +  //
> > +  // Calculate the table entries needed.
> > +  //
> > +  if (PhysicalAddressBits <= 39 ) {
> > +    NumberOfPml4EntriesNeeded = 1;
> > +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 30));
> > +  } else {
> > +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 39));
> > +    NumberOfPdpEntriesNeeded  = 512;
> > +  }
> > +
> > +  //
> > +  // Pre-allocate big pages to avoid later allocations.
> > +  //
> > +  BigPageAddress = (UINTN)PageTablesAddress;
> > +
> > +  //
> > +  // By architecture only one PageMapLevel4 exists - so lets allocate storage
> for
> > it.
> > +  //
> > +  PageMap         = (VOID *)BigPageAddress;
> > +  BigPageAddress += SIZE_4KB;
> > +
> > +  PageMapLevel4Entry = PageMap;
> > +  PageAddress        = 0;
> > +  for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> > NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++)
> {
> > +    //
> > +    // Each PML4 entry points to a page of Page Directory Pointer entires.
> > +    // So lets allocate space for them and fill them in in the IndexOfPdpEntries
> > loop.
> > +    //
> > +    PageDirectoryPointerEntry = (VOID *)BigPageAddress;
> > +    BigPageAddress           += SIZE_4KB;
> > +
> > +    //
> > +    // Make a PML4 Entry
> > +    //
> > +    PageMapLevel4Entry->Uint64         =
> > (UINT64)(UINTN)PageDirectoryPointerEntry;
> > +    PageMapLevel4Entry->Bits.ReadWrite = 1;
> > +    PageMapLevel4Entry->Bits.Present   = 1;
> > +
> > +    if (Page1GSupport) {
> > +      PageDirectory1GEntry = (VOID *)PageDirectoryPointerEntry;
> > +
> > +      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress +=
> > SIZE_1GB) {
> > +        //
> > +        // Fill in the Page Directory entries
> > +        //
> > +        PageDirectory1GEntry->Uint64         = (UINT64)PageAddress;
> > +        PageDirectory1GEntry->Bits.ReadWrite = 1;
> > +        PageDirectory1GEntry->Bits.Present   = 1;
> > +        PageDirectory1GEntry->Bits.MustBe1   = 1;
> > +      }
> > +    } else {
> > +      for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> > NumberOfPdpEntriesNeeded; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > +        //
> > +        // Each Directory Pointer entries points to a page of Page Directory
> entires.
> > +        // So allocate space for them and fill them in in the
> > IndexOfPageDirectoryEntries loop.
> > +        //
> > +        PageDirectoryEntry = (VOID *)BigPageAddress;
> > +        BigPageAddress    += SIZE_4KB;
> > +
> > +        //
> > +        // Fill in a Page Directory Pointer Entries
> > +        //
> > +        PageDirectoryPointerEntry->Uint64         =
> > (UINT64)(UINTN)PageDirectoryEntry;
> > +        PageDirectoryPointerEntry->Bits.ReadWrite = 1;
> > +        PageDirectoryPointerEntry->Bits.Present   = 1;
> > +
> > +        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress +=
> > SIZE_2MB) {
> > +          //
> > +          // Fill in the Page Directory entries
> > +          //
> > +          PageDirectoryEntry->Uint64         = (UINT64)PageAddress;
> > +          PageDirectoryEntry->Bits.ReadWrite = 1;
> > +          PageDirectoryEntry->Bits.Present   = 1;
> > +          PageDirectoryEntry->Bits.MustBe1   = 1;
> > +        }
> > +      }
> > +
> > +      for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > +        ZeroMem (
> > +          PageDirectoryPointerEntry,
> > +          sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> > +          );
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // For the PML4 entries we are not using fill in a null entry.
> > +  //
> > +  for ( ; IndexOfPml4Entries < 512; IndexOfPml4Entries++,
> > PageMapLevel4Entry++) {
> > +    ZeroMem (
> > +      PageMapLevel4Entry,
> > +      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> > +      );
> > +  }
> > +}
> > +
> > +/**
> > +  If in 32 bit protection mode, and coalesce image is of X64, switch to long
> mode.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @param  Context2                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully switched to long mode and
> execute
> > coalesce.
> > +  @retval Others                    Failed to execute coalesce in long mode.
> > +
> > +**/
> > +EFI_STATUS
> > +ModeSwitch (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1,
> > +  IN VOID                  *Context2
> > +  )
> > +{
> > +  UINTN            PageTableAddress;
> > +  UINTN            PageTableSize;
> > +  EFI_STATUS       Status;
> > +  IA32_DESCRIPTOR  Gdtr;
> > +
> > +  DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
> > +
> > +  //
> > +  // Save IA32 GDTR
> > +  //
> > +  AsmReadGdtr (&Gdtr);
> > +
> > +  //
> > +  // Set X64 GDTR
> > +  //
> > +  AsmWriteGdtr (&mGdt);
> > +
> > +  PageTableAddress = AsmReadCr3 () & 0xFFFFF000;
> > +
> > +  //
> > +  // If page table was created, no need to create
> > +  //
> > +  if (PageTableAddress == 0) {
> > +    PageTableSize = CalculatePageTableSize ();
> > +
> > +    PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES
> > (PageTableSize));
> > +    ASSERT (PageTableAddress != 0);
> > +
> > +    CreateIdentityMappingPageTables (PageTableAddress);
> > +
> > +    AsmWriteCr3 ((UINTN)PageTableAddress);
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n"));
> > +
> > +  Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1,
> > (UINT64)(UINTN)Context2, NULL);
> > +  if (Status != 0) {
> > +    Status = Status | MAX_BIT;
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status));
> > +
> > +  //
> > +  // Restore IA32 GDTR
> > +  //
> > +  AsmWriteGdtr (&Gdtr);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  )
> > +{
> > +  return ModeSwitch (Entry, Context1, NULL);
> > +}
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > new file mode 100644
> > index 0000000000..7fa42c32fb
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > @@ -0,0 +1,787 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM at PEI stage
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <Ppi/SmmAccess.h>
> > +#include <Ppi/SmmControl.h>
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/PeCoffLib.h>
> > +#include <Library/CacheMaintenanceLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/PeiServicesTablePointerLib.h>
> > +#include <Library/PeiServicesLib.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Guid/SmramMemoryReserve.h>
> > +#include <Guid/MmCoreData.h>
> > +#include <StandaloneMmIplPei.h>
> > +
> > +//
> > +// MM Core Private Data structure that contains the data shared between
> > +// the SMM IPL and the Standalone MM Core.
> > +//
> > +MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
> > +  MM_CORE_PRIVATE_DATA_SIGNATURE,     // Signature
> > +  0,                                  // MmramRangeCount
> > +  0,                                  // MmramRanges
> > +  0,                                  // MmEntryPoint
> > +  FALSE,                              // MmEntryPointRegistered
> > +  FALSE,                              // InMm
> > +  0,                                  // Mmst
> > +  0,                                  // CommunicationBuffer
> > +  0,                                  // BufferSize
> > +  EFI_SUCCESS,                        // ReturnStatus
> > +  0,                                  // MmCoreImageBase
> > +  0,                                  // MmCoreImageSize
> > +  0,                                  // MmCoreEntryPoint
> > +  0,                                  // StandaloneBfvAddress
> > +};
> > +
> > +//
> > +// Global pointer used to access mMmCorePrivateData from outside and
> inside
> > SMM
> > +//
> > +MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
> > +
> > +//
> > +// SMM IPL global variables
> > +//
> > +PEI_SMM_ACCESS_PPI    *mSmmAccess;
> > +EFI_SMRAM_DESCRIPTOR  *mCurrentSmramRange;
> > +BOOLEAN               mSmmLocked = FALSE;
> > +EFI_PHYSICAL_ADDRESS  mSmramCacheBase;
> > +UINT64                mSmramCacheSize;
> > +
> > +EFI_PEI_NOTIFY_DESCRIPTOR  mReadyToBootNotifyList = {
> > +  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> > +  &gEfiEventReadyToBootGuid,
> > +  ReadyToBootEvent
> > +};
> > +
> > +/**
> > +  This is the callback function on ready to boot.
> > +
> > +  Close and Lock smram range on ready to boot stage.
> > +
> > +  @param   PeiServices          General purpose services available to every PEIM.
> > +  @param   NotifyDescriptor     The notification structure this PEIM registered
> on
> > install.
> > +  @param   Ppi                  Pointer to the PPI data associated with this function.
> > +  @retval  EFI_SUCCESS          Close and lock smram ranges successfully.
> > +  @retval  Other                Close and lock smram ranges failed.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadyToBootEvent (
> > +  IN  EFI_PEI_SERVICES           **PeiServices,
> > +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> > +  IN  VOID                       *Ppi
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +
> > +  //
> > +  // Close all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Lock all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Lock ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Find the maximum SMRAM cache range that covers the range specified by
> > SmramRange.
> > +
> > +  This function searches and joins all adjacent ranges of SmramRange into a
> > range to be cached.
> > +
> > +  @param   SmramRange       The SMRAM range to search from.
> > +  @param   SmramCacheBase   The returned cache range base.
> > +  @param   SmramCacheSize   The returned cache range size.
> > +**/
> > +VOID
> > +GetSmramCacheRange (
> > +  IN  EFI_SMRAM_DESCRIPTOR  *SmramRange,
> > +  OUT EFI_PHYSICAL_ADDRESS  *SmramCacheBase,
> > +  OUT UINT64                *SmramCacheSize
> > +  )
> > +{
> > +  UINTN                 Index;
> > +  EFI_PHYSICAL_ADDRESS  RangeCpuStart;
> > +  UINT64                RangePhysicalSize;
> > +  BOOLEAN               FoundAdjacentRange;
> > +  EFI_SMRAM_DESCRIPTOR  *SmramRanges;
> > +
> > +  *SmramCacheBase = SmramRange->CpuStart;
> > +  *SmramCacheSize = SmramRange->PhysicalSize;
> > +
> > +  SmramRanges = (EFI_SMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +  do {
> > +    FoundAdjacentRange = FALSE;
> > +    for (Index = 0; Index < gMmCorePrivate->MmramRangeCount; Index++) {
> > +      RangeCpuStart     = SmramRanges[Index].CpuStart;
> > +      RangePhysicalSize = SmramRanges[Index].PhysicalSize;
> > +      if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase ==
> > (RangeCpuStart + RangePhysicalSize))) {
> > +        *SmramCacheBase    = RangeCpuStart;
> > +        *SmramCacheSize   += RangePhysicalSize;
> > +        FoundAdjacentRange = TRUE;
> > +      } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) &&
> > (RangePhysicalSize > 0)) {
> > +        *SmramCacheSize   += RangePhysicalSize;
> > +        FoundAdjacentRange = TRUE;
> > +      }
> > +    }
> > +  } while (FoundAdjacentRange);
> > +}
> > +
> > +/**
> > +  Get the fixed loading address from image header assigned by build tool. This
> > function only be called
> > +  when Loading module at Fixed address feature enabled.
> > +
> > +  @param  ImageContext              Pointer to the image context structure that
> > describes the PE/COFF
> > +                                    image that needs to be examined by this function.
> > +  @retval EFI_SUCCESS               An fixed loading address is assigned to this
> image
> > by build tools .
> > +  @retval EFI_NOT_FOUND             The image has no assigned fixed loading
> > address.
> > +**/
> > +EFI_STATUS
> > +GetPeCoffImageFixLoadingAssignedAddress (
> > +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> > +  )
> > +{
> > +  UINTN                            SectionHeaderOffset;
> > +  EFI_STATUS                       Status;
> > +  EFI_IMAGE_SECTION_HEADER         SectionHeader;
> > +  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
> > +  EFI_PHYSICAL_ADDRESS             FixLoadingAddress;
> > +  UINT16                           Index;
> > +  UINTN                            Size;
> > +  UINT16                           NumberOfSections;
> > +  EFI_PHYSICAL_ADDRESS             SmramBase;
> > +  UINT64                           SmmCodeSize;
> > +  UINT64                           ValueInSectionHeader;
> > +
> > +  //
> > +  // Build tool will calculate the smm code size and then patch the
> > PcdLoadFixAddressSmmCodePageNumber
> > +  //
> > +  SmmCodeSize       = EFI_PAGES_TO_SIZE (PcdGet32
> > (PcdLoadFixAddressSmmCodePageNumber));
> > +  FixLoadingAddress = 0;
> > +  Status            = EFI_NOT_FOUND;
> > +  SmramBase         = mCurrentSmramRange->CpuStart;
> > +  //
> > +  // Get PeHeader pointer
> > +  //
> > +  ImgHdr              = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8
> > *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
> > +  SectionHeaderOffset = (UINTN)(
> > +                                ImageContext->PeCoffHeaderOffset +
> > +                                sizeof (UINT32) +
> > +                                sizeof (EFI_IMAGE_FILE_HEADER) +
> > +                                ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
> > +                                );
> > +  NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
> > +
> > +  //
> > +  // Get base address from the first section header that doesn't point to code
> > section.
> > +  //
> > +  for (Index = 0; Index < NumberOfSections; Index++) {
> > +    //
> > +    // Read section header from file
> > +    //
> > +    Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
> > +    Status = ImageContext->ImageRead (
> > +                             ImageContext->Handle,
> > +                             SectionHeaderOffset,
> > +                             &Size,
> > +                             &SectionHeader
> > +                             );
> > +    if (EFI_ERROR (Status)) {
> > +      return Status;
> > +    }
> > +
> > +    Status = EFI_NOT_FOUND;
> > +
> > +    if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
> > +      //
> > +      // Build tool saves the offset to SMRAM base as image base in
> > PointerToRelocations & PointerToLineNumbers fields in the
> > +      // first section header that doesn't point to code section in image header.
> > And there is an assumption that when the
> > +      // feature is enabled, if a module is assigned a loading address by tools,
> > PointerToRelocations & PointerToLineNumbers
> > +      // fields should NOT be Zero, or else, these 2 fields should be set to Zero
> > +      //
> > +      ValueInSectionHeader = ReadUnaligned64 ((UINT64
> > *)&SectionHeader.PointerToRelocations);
> > +      if (ValueInSectionHeader != 0) {
> > +        //
> > +        // Found first section header that doesn't point to code section in which
> > build tool saves the
> > +        // offset to SMRAM base as image base in PointerToRelocations &
> > PointerToLineNumbers fields
> > +        //
> > +        FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase +
> > (INT64)ValueInSectionHeader);
> > +
> > +        if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <=
> > FixLoadingAddress)) {
> > +          //
> > +          // The assigned address is valid. Return the specified loading address
> > +          //
> > +          ImageContext->ImageAddress = FixLoadingAddress;
> > +          Status                     = EFI_SUCCESS;
> > +        }
> > +      }
> > +
> > +      break;
> > +    }
> > +
> > +    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO:
> > Loading module at fixed address %x, Status = %r \n", FixLoadingAddress,
> Status));
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Searches all the available firmware volumes and returns the first matching
> FFS
> > section.
> > +
> > +  This function searches all the firmware volumes for FFS files with FV file type
> > specified by FileType
> > +  The order that the firmware volumes is searched is not deterministic. For
> each
> > available FV a search
> > +  is made for FFS file of type FileType. If the FV contains more than one FFS
> file
> > with the same FileType,
> > +  the FileInstance instance will be the matched FFS file. For each FFS file found
> a
> > search
> > +  is made for FFS sections of type SectionType. If the FFS file contains at least
> > SectionInstance instances
> > +  of the FFS section specified by SectionType, then the SectionInstance
> instance
> > is returned in Buffer.
> > +  Buffer is allocated using AllocatePool(), and the size of the allocated buffer
> is
> > returned in Size.
> > +  It is the caller's responsibility to use FreePool() to free the allocated buffer.
> > +
> > +  If Buffer is NULL, then ASSERT().
> > +  If Size is NULL, then ASSERT().
> > +
> > +  @param  FileType             Indicates the FV file type to search for within all
> > available FVs.
> > +  @param  FileInstance         Indicates which file instance within all available
> FVs
> > specified by FileType.
> > +                               FileInstance starts from zero.
> > +  @param  SectionType          Indicates the FFS section type to search for
> within
> > the FFS file
> > +                               specified by FileType with FileInstance.
> > +  @param  SectionInstance      Indicates which section instance within the FFS
> > file
> > +                               specified by FileType with FileInstance to retrieve.
> > SectionInstance starts from zero.
> > +  @param  Buffer               On output, a pointer to a callee allocated buffer
> > containing the FFS file section that was found.
> > +                               Is it the caller's responsibility to free this buffer using
> > FreePool().
> > +  @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
> > +
> > +  @retval  EFI_SUCCESS          The specified FFS section was returned.
> > +  @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
> > +  @retval  EFI_OUT_OF_RESOURCES There are not enough resources
> available
> > to retrieve the matching FFS section.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetSectionFromAnyFvByFileType  (
> > +  IN  EFI_FV_FILETYPE   FileType,
> > +  IN  UINTN             FileInstance,
> > +  IN  EFI_SECTION_TYPE  SectionType,
> > +  IN  UINTN             SectionInstance,
> > +  OUT VOID              **Buffer,
> > +  OUT UINTN             *Size
> > +  )
> > +{
> > +  EFI_STATUS           Status;
> > +  UINTN                FvIndex;
> > +  EFI_PEI_FV_HANDLE    VolumeHandle;
> > +  EFI_PEI_FILE_HANDLE  FileHandle;
> > +  EFI_PE32_SECTION     *SectionData;
> > +  UINT32               SectionSize;
> > +
> > +  //
> > +  // Search all FV
> > +  //
> > +  VolumeHandle = NULL;
> > +  for (FvIndex = 0; ; FvIndex++) {
> > +    Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
> > +    if (EFI_ERROR (Status)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Search PEIM FFS
> > +    //
> > +    FileHandle = NULL;
> > +    Status     = PeiServicesFfsFindNextFile (FileType, VolumeHandle,
> &FileHandle);
> > +    if (EFI_ERROR (Status)) {
> > +      continue;
> > +    }
> > +
> > +    //
> > +    // Search Section
> > +    //
> > +    SectionData = NULL;
> > +    Status      = PeiServicesFfsFindSectionData (SectionType, FileHandle, Buffer);
> > +    if (EFI_ERROR (Status)) {
> > +      continue;
> > +    }
> > +
> > +    //
> > +    // Great!
> > +    //
> > +    SectionData = (EFI_PE32_SECTION *)((UINT8 *)*Buffer - sizeof
> > (EFI_PE32_SECTION));
> > +    ASSERT (SectionData->Type == SectionType);
> > +    SectionSize  = *(UINT32 *)SectionData->Size;
> > +    SectionSize &= 0xFFFFFF;
> > +    *Size        = SectionSize - sizeof (EFI_PE32_SECTION);
> > +
> > +    if (FileType == EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
> > +      EFI_FV_INFO  VolumeInfo;
> > +      //
> > +      // This is SMM BFV
> > +      //
> > +      Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
> > +      if (!EFI_ERROR (Status)) {
> > +        gMmCorePrivate->StandaloneBfvAddress =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
> > +      }
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +  Load the SMM Core image into SMRAM and executes the SMM Core from
> > SMRAM.
> > +
> > +  @param[in, out] SmramRange            Descriptor for the range of SMRAM to
> > reload the
> > +                                        currently executing image, the rang of SMRAM to
> > +                                        hold SMM Core will be excluded.
> > +  @param[in, out] SmramRangeSmmCore     Descriptor for the range of
> SMRAM
> > to hold SMM Core.
> > +
> > +  @param[in]      Context               Context to pass into SMM Core
> > +
> > +  @return  EFI_STATUS
> > +
> > +**/
> > +EFI_STATUS
> > +ExecuteSmmCoreFromSmram (
> > +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRange,
> > +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRangeSmmCore,
> > +  IN     VOID                  *Context
> > +  )
> > +{
> > +  EFI_STATUS                    Status;
> > +  VOID                          *SourceBuffer;
> > +  UINTN                         SourceSize;
> > +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
> > +  UINTN                         PageCount;
> > +  VOID                          *HobList;
> > +
> > +  Status = PeiServicesGetHobList (&HobList);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Search all Firmware Volumes for a PE/COFF image in a file of type
> > SMM_CORE
> > +  //
> > +  Status = GetSectionFromAnyFvByFileType (
> > +             EFI_FV_FILETYPE_MM_CORE_STANDALONE,
> > +             0,
> > +             EFI_SECTION_PE32,
> > +             0,
> > +             &SourceBuffer,
> > +             &SourceSize
> > +             );
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // Initialize ImageContext
> > +  //
> > +  ImageContext.Handle    = SourceBuffer;
> > +  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
> > +
> > +  //
> > +  // Get information about the image being loaded
> > +  //
> > +  Status = PeCoffLoaderGetImageInfo (&ImageContext);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // if Loading module at Fixed Address feature is enabled, the SMM core
> driver
> > will be loaded to
> > +  // the address assigned by build tool.
> > +  //
> > +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +    //
> > +    // Get the fixed loading address assigned by Build tool
> > +    //
> > +    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
> > +    if (!EFI_ERROR (Status)) {
> > +      //
> > +      // Since the memory range to load SMM CORE will be cut out in SMM core,
> > so no need to allocate and free this range
> > +      //
> > +      PageCount = 0;
> > +      //
> > +      // Reserved Smram Region for SmmCore is not used, and remove it from
> > SmramRangeCount.
> > +      //
> > +      gMmCorePrivate->MmramRangeCount--;
> > +    } else {
> > +      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading
> module
> > at fixed address at address failed\n"));
> > +      //
> > +      // Allocate memory for the image being loaded from the
> > EFI_SRAM_DESCRIPTOR
> > +      // specified by SmramRange
> > +      //
> > +      PageCount = (UINTN)EFI_SIZE_TO_PAGES
> ((UINTN)ImageContext.ImageSize
> > + ImageContext.SectionAlignment);
> > +
> > +      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> > +      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> > +
> > +      SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> > +      SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> > SmramRange->PhysicalSize;
> > +      SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> > SmramRange->PhysicalSize;
> > +      SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> > EFI_ALLOCATED;
> > +      SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> > +
> > +      //
> > +      // Align buffer on section boundary
> > +      //
> > +      ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> > +    }
> > +  } else {
> > +    //
> > +    // Allocate memory for the image being loaded from the
> > EFI_SRAM_DESCRIPTOR
> > +    // specified by SmramRange
> > +    //
> > +    PageCount = (UINTN)EFI_SIZE_TO_PAGES
> ((UINTN)ImageContext.ImageSize +
> > ImageContext.SectionAlignment);
> > +
> > +    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> > +    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> > +
> > +    SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> > +    SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> > SmramRange->PhysicalSize;
> > +    SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> > SmramRange->PhysicalSize;
> > +    SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> > EFI_ALLOCATED;
> > +    SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> > +
> > +    //
> > +    // Align buffer on section boundary
> > +    //
> > +    ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> > +  }
> > +
> > +  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
> > +  ImageContext.ImageAddress &=
> > ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
> > +
> > +  //
> > +  // Print debug message showing SMM Core load address.
> > +  //
> > +  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM
> > address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
> > +
> > +  //
> > +  // Load the image to our new buffer
> > +  //
> > +  Status = PeCoffLoaderLoadImage (&ImageContext);
> > +  if (!EFI_ERROR (Status)) {
> > +    //
> > +    // Relocate the image in our new buffer
> > +    //
> > +    Status = PeCoffLoaderRelocateImage (&ImageContext);
> > +    if (!EFI_ERROR (Status)) {
> > +      //
> > +      // Flush the instruction cache so the image data are written before we
> > execute it
> > +      //
> > +      InvalidateInstructionCacheRange ((VOID
> > *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
> > +
> > +      //
> > +      // Print debug message showing SMM Core entry point address.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM
> > address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
> > +
> > +      gMmCorePrivate->MmCoreImageBase = ImageContext.ImageAddress;
> > +      gMmCorePrivate->MmCoreImageSize = ImageContext.ImageSize;
> > +      DEBUG ((DEBUG_INFO, "SmmCoreImageBase - 0x%016lx\n",
> > gMmCorePrivate->MmCoreImageBase));
> > +      DEBUG ((DEBUG_INFO, "SmmCoreImageSize - 0x%016lx\n",
> > gMmCorePrivate->MmCoreImageSize));
> > +
> > +      gMmCorePrivate->MmCoreEntryPoint = ImageContext.EntryPoint;
> > +
> > +      //
> > +      // Print debug message showing Standalone MM Core entry point address.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM
> > address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
> > +
> > +      //
> > +      // Execute image
> > +      //
> > +      LoadSmmCore (ImageContext.EntryPoint, HobList);
> > +    }
> > +  }
> > +
> > +  //
> > +  // If the load operation, relocate operation, or the image execution return
> an
> > +  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR
> > specified by
> > +  // SmramRange
> > +  //
> > +  if (EFI_ERROR (Status)) {
> > +    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
> > +  }
> > +
> > +  //
> > +  // Always free memory allocated by GetFileBufferByFilePath ()
> > +  //
> > +  FreePool (SourceBuffer);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Get full SMRAM ranges.
> > +
> > +  It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved
> > ranges from
> > +  SmmConfiguration protocol, split the entries if there is overlap between
> them.
> > +  It will also reserve one entry for SMM core.
> > +
> > +  @param[in]  PeiServices           Describes the list of possible PEI Services.
> > +  @param[out] FullSmramRangeCount   Output pointer to full SMRAM range
> > count.
> > +
> > +  @return Pointer to full SMRAM ranges.
> > +
> > +**/
> > +EFI_SMRAM_DESCRIPTOR *
> > +GetFullSmramRanges (
> > +  IN  CONST EFI_PEI_SERVICES  **PeiServices,
> > +  OUT       UINTN             *FullSmramRangeCount
> > +  )
> > +{
> > +  EFI_STATUS            Status;
> > +  UINTN                 Size;
> > +  EFI_SMRAM_DESCRIPTOR  *FullSmramRanges;
> > +  UINTN                 AdditionSmramRangeCount;
> > +  UINTN                 SmramRangeCount;
> > +
> > +  //
> > +  // Get SMRAM information.
> > +  //
> > +  Size   = 0;
> > +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, &Size, NULL);
> > +  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
> > +
> > +  SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
> > +
> > +  //
> > +  // Reserve one entry SMM Core in the full SMRAM ranges.
> > +  //
> > +  AdditionSmramRangeCount = 1;
> > +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +    //
> > +    // Reserve two entries for all SMM drivers & SMM Core in the full SMRAM
> > ranges.
> > +    //
> > +    AdditionSmramRangeCount = 2;
> > +  }
> > +
> > +  *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
> > +  Size                 = (*FullSmramRangeCount) * sizeof
> (EFI_SMRAM_DESCRIPTOR);
> > +  FullSmramRanges      = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
> > +  ASSERT (FullSmramRanges != NULL);
> > +  if (FullSmramRanges == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, &Size, FullSmramRanges);
> > +
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return FullSmramRanges;
> > +}
> > +
> > +/**
> > +  The Entry Point for SMM IPL
> > +
> > +  Load SMM Core into SMRAM.
> > +
> > +  @param  FileHandle  Handle of the file being invoked.
> > +  @param  PeiServices Describes the list of possible PEI Services.
> > +
> > +  @retval EFI_SUCCESS    The entry point is executed successfully.
> > +  @retval Other          Some error occurred when executing this entry point.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmIplEntry (
> > +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> > +  IN CONST EFI_PEI_SERVICES     **PeiServices
> > +  )
> > +{
> > +  EFI_STATUS             Status;
> > +  UINTN                  Index;
> > +  UINT64                 MaxSize;
> > +  UINT64                 SmmCodeSize;
> > +  MM_CORE_DATA_HOB_DATA  SmmCoreDataHobData;
> > +  EFI_SMRAM_DESCRIPTOR   *MmramRanges;
> > +  EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmDriver;
> > +
> > +  //
> > +  // Build Hob for SMM and DXE phase
> > +  //
> > +  SmmCoreDataHobData.Address =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES
> > (sizeof (mMmCorePrivateData)));
> > +  ASSERT (SmmCoreDataHobData.Address != 0);
> > +  gMmCorePrivate = (VOID *)(UINTN)SmmCoreDataHobData.Address;
> > +  CopyMem ((VOID *)(UINTN)SmmCoreDataHobData.Address,
> > &mMmCorePrivateData, sizeof (mMmCorePrivateData));
> > +  DEBUG ((DEBUG_INFO, "gMmCorePrivate - 0x%x\n", gMmCorePrivate));
> > +
> > +  BuildGuidDataHob (
> > +    &gMmCoreDataHobGuid,
> > +    (VOID *)&SmmCoreDataHobData,
> > +    sizeof (SmmCoreDataHobData)
> > +    );
> > +
> > +  //
> > +  // Get SMM Access Protocol
> > +  //
> > +  Status = PeiServicesLocatePpi (&gPeiSmmAccessPpiGuid, 0, NULL, (VOID
> > **)&mSmmAccess);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Get SMRAM information
> > +  //
> > +  gMmCorePrivate->MmramRanges =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)GetFullSmramRanges (PeiServices, (UINTN
> > *)&gMmCorePrivate->MmramRangeCount);
> > +  ASSERT (gMmCorePrivate->MmramRanges != 0);
> > +  if (gMmCorePrivate->MmramRanges == 0) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  //
> > +  // Open all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Open ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Print debug message that the SMRAM window is now open.
> > +  //
> > +  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
> > +
> > +  //
> > +  // Find the largest SMRAM range between 1MB and 4GB that is at least
> 256KB
> > - 4K in size
> > +  //
> > +  mCurrentSmramRange = NULL;
> > +  MmramRanges        = (EFI_MMRAM_DESCRIPTOR
> *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +  if (MmramRanges == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "Fail to retrieve MmramRanges\n"));
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index <
> > gMmCorePrivate->MmramRangeCount; Index++) {
> > +    //
> > +    // Skip any SMRAM region that is already allocated, needs testing, or needs
> > ECC initialization
> > +    //
> > +    if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED |
> > EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
> > +      continue;
> > +    }
> > +
> > +    if (MmramRanges[Index].CpuStart >= BASE_1MB) {
> > +      if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize)
> <=
> > BASE_4GB) {
> > +        if (MmramRanges[Index].PhysicalSize >= MaxSize) {
> > +          MaxSize            = MmramRanges[Index].PhysicalSize;
> > +          mCurrentSmramRange = &MmramRanges[Index];
> > +        }
> > +      }
> > +    }
> > +  }
> > +
> > +  if (mCurrentSmramRange != NULL) {
> > +    //
> > +    // Print debug message showing SMRAM window that will be used by SMM
> > IPL and SMM Core
> > +    //
> > +    DEBUG ((
> > +      DEBUG_INFO,
> > +      "SMM IPL found SMRAM window %p - %p\n",
> > +      (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
> > +      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart +
> > mCurrentSmramRange->PhysicalSize - 1)
> > +      ));
> > +
> > +    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase,
> > &mSmramCacheSize);
> > +
> > +    //
> > +    // if Loading module at Fixed Address feature is enabled, save the SMRAM
> > base to Load
> > +    // Modules At Fixed Address Configuration Table.
> > +    //
> > +    if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +      //
> > +      // Build tool will calculate the smm code size and then patch the
> > PcdLoadFixAddressSmmCodePageNumber
> > +      //
> > +      SmmCodeSize = LShiftU64 (PcdGet32
> > (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
> > +      //
> > +      // The SMRAM available memory is assumed to be larger than
> SmmCodeSize
> > +      //
> > +      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
> > +      //
> > +      // Fill the Smram range for all SMM code
> > +      //
> > +      MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +      //
> > +      // Note: SmramRanges specific for all SMM code will put in the
> > gMmCorePrivate->MmramRangeCount - 2.
> > +      //
> > +      SmramRangeSmmDriver                = &MmramRanges[gMmCorePrivate-
> > >MmramRangeCount - 2];
> > +      SmramRangeSmmDriver->CpuStart      = mCurrentSmramRange->CpuStart;
> > +      SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange-
> > >PhysicalStart;
> > +      SmramRangeSmmDriver->RegionState   = mCurrentSmramRange-
> > >RegionState | EFI_ALLOCATED;
> > +      SmramRangeSmmDriver->PhysicalSize  = SmmCodeSize;
> > +
> > +      mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
> > +      mCurrentSmramRange->CpuStart      = mCurrentSmramRange->CpuStart +
> > SmmCodeSize;
> > +      mCurrentSmramRange->PhysicalStart = mCurrentSmramRange-
> > >PhysicalStart + SmmCodeSize;
> > +    }
> > +
> > +    //
> > +    // Load SMM Core into SMRAM and execute it from SMRAM
> > +    // Note: SmramRanges specific for SMM Core will put in the
> gMmCorePrivate-
> > >MmramRangeCount - 1.
> > +    //
> > +    Status = ExecuteSmmCoreFromSmram (
> > +               mCurrentSmramRange,
> > +               &(((EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges)[gMmCorePrivate->MmramRangeCount - 1]),
> > +               gMmCorePrivate
> > +               );
> > +    if (EFI_ERROR (Status)) {
> > +      //
> > +      // Print error message that the SMM Core failed to be loaded and
> executed.
> > +      //
> > +      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM
> Core
> > from SMRAM\n"));
> > +    }
> > +  } else {
> > +    //
> > +    // Print error message that there are not enough SMRAM resources to load
> > the SMM Core.
> > +    //
> > +    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM
> > region to load SMM Core\n"));
> > +  }
> > +
> > +  //
> > +  // If the SMM Core could not be loaded then close SMRAM window, free
> > allocated
> > +  // resources, and return an error so SMM IPL will be unloaded.
> > +  //
> > +  if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
> > +    //
> > +    // Close all SMRAM ranges
> > +    //
> > +    Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +    ASSERT_EFI_ERROR (Status);
> > +
> > +    //
> > +    // Print debug message that the SMRAM window is now closed.
> > +    //
> > +    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
> > +
> > +    //
> > +    // Free all allocated resources
> > +    //
> > +    FreePool ((VOID *)(UINTN)gMmCorePrivate->MmramRanges);
> > +
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  //
> > +  // Create ready to boot for close and lock smram ranges
> > +  //
> > +  Status = PeiServicesNotifyPpi (&mReadyToBootNotifyList);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > new file mode 100644
> > index 0000000000..6d3497f2ea
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > @@ -0,0 +1,32 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <StandaloneMm.h>
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  )
> > +{
> > +  STANDALONE_MM_FOUNDATION_ENTRY_POINT  EntryPoint;
> > +
> > +  EntryPoint =
> (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
> > +  return EntryPoint (Context1);
> > +}
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > new file mode 100644
> > index 0000000000..7f887eb77d
> > --- /dev/null
> > +++
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > @@ -0,0 +1,148 @@
> > +;------------------------------------------------------------------------------
> > +;
> > +; Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +; SPDX-License-Identifier: BSD-2-Clause-Patent
> > +;
> > +; Module Name:
> > +;
> > +;    Thunk32To64.nasm
> > +;
> > +; Abstract:
> > +;
> > +;   This is the assembly code to transition from long mode to compatibility
> > +;   mode to execute 32-bit code and then transit back to long mode.
> > +;
> > +;------------------------------------------------------------------------------
> > +
> > +    SECTION .text
> > +
> > +;------------------------------------------------------------------------------
> > +; Procedure:    AsmExecute64BitCode
> > +;
> > +; Input:        None
> > +;
> > +; Output:       None
> > +;
> > +; Prototype:    UINT32
> > +;               AsmExecute64BitCode (
> > +;                 IN UINT64           Function,
> > +;                 IN UINT64           Param1,
> > +;                 IN UINT64           Param2,
> > +;                 IN IA32_DESCRIPTOR  *InternalGdtr
> > +;                 );
> > +;
> > +;
> > +; Description:  A thunk function to execute 32-bit code in long mode.
> > +;
> > +;------------------------------------------------------------------------------
> > +global ASM_PFX(AsmExecute64BitCode)
> > +ASM_PFX(AsmExecute64BitCode):
> > +;
> > +; +---------+
> > +; | EIP(64) |
> > +; +---------+
> > +; | CS (64) |
> > +; +---------+
> > +; | EIP(32) |
> > +; +---------+
> > +; | CS (32) |<-ESP (16 bytes aligned)
> > +; +---------+
> > +; | ...     |
> > +; +---------+
> > +; | ebx     |<-EBP
> > +; +---------+
> > +; | ebp     |<-EBP + 4
> > +; +---------+
> > +; | esi     |<-EBP + 8
> > +; +---------+
> > +; | edi     |<-EBP + 12
> > +; +---------+
> > +; | RFlags  |<-EBP + 16
> > +; +---------+
> > +; | RetAddr |<-EBP (org)
> > +; +---------+
> > +; | Func    |<-EBP + 24
> > +; | Func    |
> > +; +---------+
> > +; | Param1  |<-EBP + 32
> > +; | Param1  |
> > +; +---------+
> > +; | Param2  |<-EBP + 40
> > +; | Param2  |
> > +; +---------+
> > +; | Gdtr    |
> > +; +---------+
> > +;
> > +    ;
> > +    ; Save general purpose register and RFlags register
> > +    ;
> > +    pushfd
> > +    push    edi
> > +    push    esi
> > +    push    ebp
> > +    push    ebx
> > +    mov     ebp, esp
> > +
> > +    and     esp, 0FFFFFFF0h
> > +
> > +    push    010h                        ; protected mode selector on stack
> > +    mov     eax, Compatible             ; offset for LongMode
> > +    push    eax                         ; offset on stack
> > +
> > +    push    038h                        ; long mode selector on stack
> > +    mov     eax, LongMode               ; offset for LongMode
> > +    push    eax                         ; offset on stack
> > +
> > +    mov     eax, cr4
> > +    or      al, 020h
> > +    mov     cr4, eax                    ; enable PAE
> > +    mov     ecx, 0c0000080h
> > +    rdmsr
> > +    or      ah, 1                       ; set LME
> > +    wrmsr
> > +    mov     eax, cr0
> > +    bts     eax, 31                     ; set PG
> > +    mov     cr0, eax                    ; enable paging
> > +    retf                                ; topmost 2 dwords hold the address
> > +LongMode:                               ; long mode starts here
> > +
> > +    ; Call long mode function
> > +    DB      67h, 48h                    ; 32-bit address size, 64-bit operand size
> > +    mov     eax, [ebp + 24]             ; mov rbx, [ebp + 24]
> > +    DB      67h, 48h
> > +    mov     ecx, [ebp + 24 + 8]         ; mov rcx, [ebp + 24 + 8]
> > +    DB      67h, 48h
> > +    mov     edx, [ebp + 24 + 16]        ; mov rdx, [ebp + 24 + 16]
> > +
> > +    DB      48h
> > +    add     esp, -20h                   ; add rsp, -20h
> > +    call    eax                         ; call rax
> > +    DB      48h
> > +    add     esp, 20h                    ; add rsp, 20h
> > +
> > +    ; after long mode function call
> > +    mov     ebx, eax
> > +
> > +    retf
> > +Compatible:
> > +    mov     ecx, cr0
> > +    btc     ecx, 31                     ; clear PG
> > +    mov     cr0, ecx                    ; disable paging
> > +    mov     ecx, 0C0000080h
> > +    rdmsr
> > +    btc     eax, 8                      ; clear LME
> > +    wrmsr
> > +
> > +    ;
> > +    ; Restore C register and eax hold the return status from 32-bit function.
> > +    ; Note: Do not touch rax from now which hold the return value from IA32
> > function
> > +    ;
> > +    mov     eax, ebx                    ; put return status to EAX
> > +    mov     esp, ebp                    ; restore stack pointer
> > +    pop     ebx
> > +    pop     ebp
> > +    pop     esi
> > +    pop     edi
> > +    popfd
> > +
> > +    ret
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > new file mode 100644
> > index 0000000000..be0aae70f0
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > @@ -0,0 +1,66 @@
> > +/** @file
> > +  Private header with declarations and definitions specific to the Standalone
> > +  MM IPL PEI driver
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef STANDALONE_MM_IPL_PEI_H_
> > +#define STANDALONE_MM_IPL_PEI_H_
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  );
> > +
> > +/**
> > +  Assembly function to transition from long mode to compatibility mode to
> > +  execute 32-bit code and then transit back to long mode.
> > +
> > +  @param[in] Function     The 32bit code entry to be executed.
> > +  @param[in] Param1       The first parameter to pass to 32bit code
> > +  @param[in] Param2       The second parameter to pass to 32bit code
> > +  @param[in] InternalGdtr The GDT and GDT descriptor used by this library
> > +
> > +  @retval status.
> > +**/
> > +UINT32
> > +AsmExecute64BitCode (
> > +  IN UINT64           Function,
> > +  IN UINT64           Param1,
> > +  IN UINT64           Param2,
> > +  IN IA32_DESCRIPTOR  *InternalGdtr
> > +  );
> > +
> > +/**
> > +  This is the callback function on ready to boot.
> > +
> > +  Close and lock smram ranges on ready to boot stage.
> > +
> > +  @param   PeiServices       General purpose services available to every PEIM.
> > +  @param   NotifyDescriptor  The notification structure this PEIM registered
> on
> > install.
> > +  @param   Ppi               Pointer to the PPI data associated with this function.
> > +  @retval  EFI_SUCCESS       Close and lock smram ranges successfully.
> > +  @retval  Other             Close and lock smram ranges failed.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadyToBootEvent (
> > +  IN  EFI_PEI_SERVICES           **PeiServices,
> > +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> > +  IN  VOID                       *Ppi
> > +  );
> > +
> > +#endif
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > new file mode 100644
> > index 0000000000..ff4c67a92c
> > --- /dev/null
> > +++
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > @@ -0,0 +1,75 @@
> > +## @file
> > +#  This module provide a Standalone SMM compliant implementation of SMM
> > IPL PEIM.
> > +#
> > +#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x00010005
> > +  BASE_NAME                      = StandaloneMmIplPei
> > +  FILE_GUID                      = 578A0D17-2DC0-4C7D-A121-D8D771923BB0
> > +  MODULE_TYPE                    = PEIM
> > +  VERSION_STRING                 = 1.0
> > +  PI_SPECIFICATION_VERSION       = 0x0001000A
> > +  ENTRY_POINT                    = SmmIplEntry
> > +
> > +#
> > +# The following information is for reference only and not required by the
> build
> > tools.
> > +#
> > +#  VALID_ARCHITECTURES           = IA32 X64
> > +#
> > +
> > +[Sources]
> > +  StandaloneMmIplPei.h
> > +  StandaloneMmIplPei.c
> > +
> > +[Sources.Ia32]
> > +  Ia32/LoadSmmCore.c
> > +  Ia32/Thunk32To64.nasm
> > +
> > +[Sources.X64]
> > +  X64/LoadSmmCore.c
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +  StandaloneMmPkg/StandaloneMmPkg.dec
> > +
> > +[LibraryClasses]
> > +  PeimEntryPoint
> > +  PeiServicesTablePointerLib
> > +  PeiServicesLib
> > +  BaseLib
> > +  BaseMemoryLib
> > +  PeCoffLib
> > +  CacheMaintenanceLib
> > +  MemoryAllocationLib
> > +  DebugLib
> > +  HobLib
> > +  IntrinsicLib
> > +
> > +[Guids]
> > +  gMmCoreDataHobGuid
> > +  gEfiEventReadyToBootGuid
> > +
> > +[Ppis]
> > +  gPeiSmmAccessPpiGuid                     ## CONSUMES
> > +  gPeiSmmControlPpiGuid                    ## CONSUMES
> > +
> > +[FeaturePcd.IA32]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ##
> > CONSUMES
> > +
> > +[Pcd.IA32]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ##
> > SOMETIMES_CONSUMES
> > +
> > +[Pcd]
> > +
> gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber
> > ## SOMETIMES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable
> ##
> > CONSUMES
> > +
> > +[Depex]
> > +  gPeiSmmAccessPpiGuid AND
> > +  gPeiSmmControlPpiGuid
> > +
> > diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > index 4777532a7e..872f7958be 100644
> > --- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > +++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > @@ -78,7 +78,9 @@
> >      ## options defined .pytool/Plugin/SpellCheck
> >      "SpellCheck": {
> >          "AuditOnly": False,
> > -        "IgnoreFiles": [],           # use gitignore syntax to ignore errors
> > +        "IgnoreFiles": [
> > +            "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm"
> > +        ],           # use gitignore syntax to ignore errors
> >                                       # in matching files
> >          "ExtendWords": [
> >              "Bsymbolic",
> > diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc
> > b/StandaloneMmPkg/StandaloneMmPkg.dsc
> > index 8012f93b7d..d88471fe82 100644
> > --- a/StandaloneMmPkg/StandaloneMmPkg.dsc
> > +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc
> > @@ -20,7 +20,7 @@
> >    PLATFORM_VERSION               = 1.0
> >    DSC_SPECIFICATION              = 0x00010011
> >    OUTPUT_DIRECTORY               = Build/StandaloneMm
> > -  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM
> > +  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM|IA32
> >    BUILD_TARGETS                  = DEBUG|RELEASE
> >    SKUID_IDENTIFIER               = DEFAULT
> >
> > @@ -60,6 +60,14 @@
> >
> >
> StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoin
> > t/StandaloneMmDriverEntryPoint.inf
> >
> >
> VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/V
> > ariableMmDependency.inf
> >
> > +[LibraryClasses.common.PEIM]
> > +  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> > +  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
> > +
> >
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllo
> c
> > ationLib.inf
> > +  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> > +
> >
> PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServi
> c
> > esTablePointerLib.inf
> > +  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
> > +
> >  [LibraryClasses.AARCH64, LibraryClasses.ARM]
> >    ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
> >
> >
> StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStand
> > aloneMmLib.inf
> > @@ -104,7 +112,7 @@
> >  #       generated for it, but the binary will not be put into any firmware volume.
> >  #
> >
> >
> #################################################################
> > ##################################
> > -[Components.common]
> > +[Components.AARCH64, Components.ARM, Components.X64]
> >    #
> >    # MM Core
> >    #
> > @@ -122,6 +130,9 @@
> >    StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
> >
> >
> StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMm
> > PeCoffExtraActionLib.inf
> >
> > +[Components.X64, Components.IA32]
> > +  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > +
> >
> >
> #################################################################
> > ##################################
> >  #
> >  # BuildOptions Section - Define the module specific tool chain flags that
> should
> > be used as
> > diff --git a/UefiPayloadPkg/UniversalPayloadBuild.sh
> > b/UefiPayloadPkg/UniversalPayloadBuild.sh
> > index 9a72eedd35..bacf5233a8 100644
> > --- a/UefiPayloadPkg/UniversalPayloadBuild.sh
> > +++ b/UefiPayloadPkg/UniversalPayloadBuild.sh
> > @@ -1,17 +1,17 @@
> > -#!/usr/bin/env bash
> > -#
> > -# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > -#
> > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > -#
> > -
> > -if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> > -    echo python_exe=${PYTHON_COMMAND}
> > -fi
> > -
> > -# Get file path of UniversalPayloadBuild.sh
> > -uplbld_filepath=${BASH_SOURCE:-$0}
> > -# Remove ".sh" extension
> > -uplbld_filepath_noext=${uplbld_filepath%.*}
> > -# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> > -exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> > +#!/usr/bin/env bash
> > +#
> > +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +
> > +if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> > +    echo python_exe=${PYTHON_COMMAND}
> > +fi
> > +
> > +# Get file path of UniversalPayloadBuild.sh
> > +uplbld_filepath=${BASH_SOURCE:-$0}
> > +# Remove ".sh" extension
> > +uplbld_filepath_noext=${uplbld_filepath%.*}
> > +# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> > +exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> > diff --git a/edksetup.sh b/edksetup.sh
> > index cab3a8c113..553e1676d0 100755
> > --- a/edksetup.sh
> > +++ b/edksetup.sh
> > @@ -1,147 +1,147 @@
> > -#
> > -# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> > -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > -#
> > -# In *inux environment, the build tools's source is required and need to be
> > compiled
> > -# firstly, please reference
> > https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-
> Github-
> > Quick-Start
> > -# to get how to setup build tool.
> > -#
> > -# Setup the environment for unix-like systems running a bash-like shell.
> > -# This file must be "sourced" not merely executed. For example: ".
> edksetup.sh"
> > -#
> > -# CYGWIN users: Your path and filename related environment variables
> should
> > be
> > -# set up in the unix style.  This script will make the necessary conversions to
> > -# windows style.
> > -#
> > -# Please reference edk2 user manual for more detail descriptions at
> > https://github.com/tianocore-
> > docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> > -#
> > -
> > -SCRIPTNAME="edksetup.sh"
> > -RECONFIG=FALSE
> > -
> > -HelpMsg()
> > -{
> > -  echo "Usage: $SCRIPTNAME [Options]"
> > -  echo
> > -  echo "The system environment variable, WORKSPACE, is always set to the
> > current"
> > -  echo "working directory."
> > -  echo
> > -  echo "Options: "
> > -  echo "  --help, -h, -?        Print this help screen and exit."
> > -  echo
> > -  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with
> the"
> > -  echo "                        template files from the BaseTools/Conf directory."
> > -  echo
> > -  echo Please note: This script must be \'sourced\' so the environment can be
> > changed.
> > -  echo ". $SCRIPTNAME"
> > -  echo "source $SCRIPTNAME"
> > -}
> > -
> > -SetWorkspace()
> > -{
> > -  #
> > -  # If WORKSPACE is already set, then we can return right now
> > -  #
> > -  export PYTHONHASHSEED=1
> > -  if [ -n "$WORKSPACE" ]
> > -  then
> > -    return 0
> > -  fi
> > -
> > -  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> > -  then
> > -    echo Source this script from the base of your tree.  For example:
> > -    echo "  cd /Path/To/Edk2/Clone"
> > -    echo "  . $SCRIPTNAME"
> > -    return 1
> > -  fi
> > -
> > -  #
> > -  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> > -  #
> > -  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> > -  then
> > -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > -    echo Please point EDK_TOOLS_PATH at the directory that contains
> > -    echo the EDK2 BuildEnv script.
> > -    return 1
> > -  fi
> > -
> > -  #
> > -  # Set $WORKSPACE
> > -  #
> > -  export WORKSPACE=$PWD
> > -  return 0
> > -}
> > -
> > -SetupEnv()
> > -{
> > -  if [ -n "$EDK_TOOLS_PATH" ]
> > -  then
> > -    . $EDK_TOOLS_PATH/BuildEnv
> > -  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> > -  then
> > -    . $WORKSPACE/BaseTools/BuildEnv
> > -  elif [ -n "$PACKAGES_PATH" ]
> > -  then
> > -    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> > -    do
> > -      if [ -f "$DIR/BaseTools/BuildEnv" ]
> > -      then
> > -        export EDK_TOOLS_PATH=$DIR/BaseTools
> > -        . $DIR/BaseTools/BuildEnv
> > -        break
> > -      fi
> > -    done
> > -  else
> > -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > -    echo Please check that WORKSPACE or PACKAGES_PATH is not set
> incorrectly
> > -    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> > -    echo the EDK2 BuildEnv script.
> > -    return 1
> > -  fi
> > -}
> > -
> > -SetupPython3()
> > -{
> > -  export PYTHON_COMMAND=python3
> > -}
> > -
> > -SourceEnv()
> > -{
> > -  SetupPython3
> > -  SetWorkspace
> > -  SetupEnv
> > -}
> > -
> > -I=$#
> > -while [ $I -gt 0 ]
> > -do
> > -  case "$1" in
> > -    BaseTools)
> > -      # Ignore argument for backwards compatibility
> > -      shift
> > -    ;;
> > -    --reconfig)
> > -      RECONFIG=TRUE
> > -      shift
> > -    ;;
> > -    *)
> > -      HelpMsg
> > -      break
> > -    ;;
> > -  esac
> > -  I=$((I - 1))
> > -done
> > -
> > -if [ $I -gt 0 ]
> > -then
> > -  return 1
> > -fi
> > -
> > -SourceEnv
> > -
> > -unset SCRIPTNAME RECONFIG
> > -
> > -return $?
> > +#
> > +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +# In *inux environment, the build tools's source is required and need to be
> > compiled
> > +# firstly, please reference
> > https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-
> Github-
> > Quick-Start
> > +# to get how to setup build tool.
> > +#
> > +# Setup the environment for unix-like systems running a bash-like shell.
> > +# This file must be "sourced" not merely executed. For example: ".
> edksetup.sh"
> > +#
> > +# CYGWIN users: Your path and filename related environment variables
> should
> > be
> > +# set up in the unix style.  This script will make the necessary conversions to
> > +# windows style.
> > +#
> > +# Please reference edk2 user manual for more detail descriptions at
> > https://github.com/tianocore-
> > docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> > +#
> > +
> > +SCRIPTNAME="edksetup.sh"
> > +RECONFIG=FALSE
> > +
> > +HelpMsg()
> > +{
> > +  echo "Usage: $SCRIPTNAME [Options]"
> > +  echo
> > +  echo "The system environment variable, WORKSPACE, is always set to the
> > current"
> > +  echo "working directory."
> > +  echo
> > +  echo "Options: "
> > +  echo "  --help, -h, -?        Print this help screen and exit."
> > +  echo
> > +  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with
> the"
> > +  echo "                        template files from the BaseTools/Conf directory."
> > +  echo
> > +  echo Please note: This script must be \'sourced\' so the environment can be
> > changed.
> > +  echo ". $SCRIPTNAME"
> > +  echo "source $SCRIPTNAME"
> > +}
> > +
> > +SetWorkspace()
> > +{
> > +  #
> > +  # If WORKSPACE is already set, then we can return right now
> > +  #
> > +  export PYTHONHASHSEED=1
> > +  if [ -n "$WORKSPACE" ]
> > +  then
> > +    return 0
> > +  fi
> > +
> > +  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> > +  then
> > +    echo Source this script from the base of your tree.  For example:
> > +    echo "  cd /Path/To/Edk2/Clone"
> > +    echo "  . $SCRIPTNAME"
> > +    return 1
> > +  fi
> > +
> > +  #
> > +  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> > +  #
> > +  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> > +  then
> > +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > +    echo Please point EDK_TOOLS_PATH at the directory that contains
> > +    echo the EDK2 BuildEnv script.
> > +    return 1
> > +  fi
> > +
> > +  #
> > +  # Set $WORKSPACE
> > +  #
> > +  export WORKSPACE=$PWD
> > +  return 0
> > +}
> > +
> > +SetupEnv()
> > +{
> > +  if [ -n "$EDK_TOOLS_PATH" ]
> > +  then
> > +    . $EDK_TOOLS_PATH/BuildEnv
> > +  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> > +  then
> > +    . $WORKSPACE/BaseTools/BuildEnv
> > +  elif [ -n "$PACKAGES_PATH" ]
> > +  then
> > +    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> > +    do
> > +      if [ -f "$DIR/BaseTools/BuildEnv" ]
> > +      then
> > +        export EDK_TOOLS_PATH=$DIR/BaseTools
> > +        . $DIR/BaseTools/BuildEnv
> > +        break
> > +      fi
> > +    done
> > +  else
> > +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > +    echo Please check that WORKSPACE or PACKAGES_PATH is not set
> incorrectly
> > +    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> > +    echo the EDK2 BuildEnv script.
> > +    return 1
> > +  fi
> > +}
> > +
> > +SetupPython3()
> > +{
> > +  export PYTHON_COMMAND=python3
> > +}
> > +
> > +SourceEnv()
> > +{
> > +  SetupPython3
> > +  SetWorkspace
> > +  SetupEnv
> > +}
> > +
> > +I=$#
> > +while [ $I -gt 0 ]
> > +do
> > +  case "$1" in
> > +    BaseTools)
> > +      # Ignore argument for backwards compatibility
> > +      shift
> > +    ;;
> > +    --reconfig)
> > +      RECONFIG=TRUE
> > +      shift
> > +    ;;
> > +    *)
> > +      HelpMsg
> > +      break
> > +    ;;
> > +  esac
> > +  I=$((I - 1))
> > +done
> > +
> > +if [ $I -gt 0 ]
> > +then
> > +  return 1
> > +fi
> > +
> > +SourceEnv
> > +
> > +unset SCRIPTNAME RECONFIG
> > +
> > +return $?
> > --
> > 2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105835): https://edk2.groups.io/g/devel/message/105835
Mute This Topic: https://groups.io/mt/99079640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
Posted by Zhang, Hongbin1 10 months, 3 weeks ago
Thanks Jiewen.
I will change this.

-----Original Message-----
From: Yao, Jiewen <jiewen.yao@intel.com> 
Sent: Wednesday, June 7, 2023 10:31 AM
To: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io
Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Supreeth Venkatesh <supreeth.venkatesh@arm.com>; Bu, Daocheng <daocheng.bu@intel.com>; Chen, Bo <bo.chen@intel.com>
Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.

> 5th patch register ReadyToBoot callback. But is it too late from security perspective? Why not lock after SMM core exit? @Yao, Jiewen

Agree with Ray. ReadyToBoot is too late.



> -----Original Message-----
> From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> Sent: Wednesday, June 7, 2023 10:29 AM
> To: Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io; Yao, Jiewen
> <jiewen.yao@intel.com>
> Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami
> Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Supreeth Venkatesh
> <supreeth.venkatesh@arm.com>; Bu, Daocheng <daocheng.bu@intel.com>;
> Chen, Bo <bo.chen@intel.com>
> Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Thanks Ray.
> Replied your code comments with [Hongbin].
> And I will split to several patches, it will be better for reviewing.
> 
> -----Original Message-----
> From: Ni, Ray <ray.ni@intel.com>
> Sent: Wednesday, June 7, 2023 10:04 AM
> To: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; devel@edk2.groups.io; Yao,
> Jiewen <jiewen.yao@intel.com>
> Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami
> Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Supreeth Venkatesh
> <supreeth.venkatesh@arm.com>
> Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Hongbin,
> The patch is so big. Can you please split the patch to small patches? For example:
> 1st patch only implements the Ipl entrypoint to find the correct SMRAM range
> and dump it
> 2nd patch loads SMM CORE without mode switch if sizeof (UINTN) matches
> SMM core module type.
> 3rd patch loads SMM CORE with mode switch if sizeof (UINTN) == 4 but SMM
> core module type is 64bit.
> 4th patch Deadloop() when sizeof (UINTN) == 8 but SMM core module type is
> 32bit.
> 5th patch register ReadyToBoot callback. But is it too late from security
> perspective? Why not lock after SMM core exit? @Yao, Jiewen
> 
> Back to the code content, 3 comments:
> 1. Have you tested the flow when LoadImageAtFixedAddress is enabled? If no, I
> prefer you do not add the logic at all in the first version. We can enable that
> later.
>      -- Yes, currently PcdLoadModuleAtFixAddressEnable was not used and
> verified, I will add later [Hongbin].
> 2. "EFIAPI" for GetSectionFromAnyFvByFileType should be removed. And the
> function prototype could be refined as below:
>     EFI_STATUS
>     LocateMmFvAndCore
>       OUT EFI_PHYSICAL_ADDRESS  *MmFvBaseAddress,
>       OUT VOID                  **MmCoreImageAddress
>     Please avoid directly modifying global variables inside this function.
>      -- Ok, will change that [Hongbin].
> 3. Can the StandaloneMmCore in open source be directly used with this IPL?
>      -- I will think about this later [Hongbin].
> 
> Thanks,
> Ray
> 
> 
> > -----Original Message-----
> > From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> > Sent: Monday, May 22, 2023 1:21 PM
> > To: devel@edk2.groups.io
> > Cc: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Yao, Jiewen
> > <jiewen.yao@intel.com>; Ni, Ray <ray.ni@intel.com>; Zeng, Star
> > <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar
> > <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> > Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> > Subject: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> >
> > Add StandaloneMmIplPei IA32/X64 driver at PEI stage.
> > FSP will use this driver to load Standalone MM code
> > to dispatch other Standalone MM drivers.
> >
> > Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> > Cc: Sami Mujawar <sami.mujawar@arm.com>
> > Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> > Cc: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> > ---
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     |
> 456
> > ++++++++++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   |
> 787
> > ++++++++++++++++++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |
> 32 +
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  |
> 148
> > ++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66
> > ++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |
> 75
> > ++
> >  StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
> >  StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
> >  UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
> >  edksetup.sh                                                       | 294 ++++----
> >  10 files changed, 1744 insertions(+), 167 deletions(-)
> >
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > new file mode 100644
> > index 0000000000..d6174d73a3
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > @@ -0,0 +1,456 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <StandaloneMm.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <StandaloneMmIplPei.h>
> > +
> > +#pragma pack(1)
> > +
> > +//
> > +// Page-Map Level-4 Offset (PML4) and
> > +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
> > +//
> > +
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Reserved             : 1;   // Reserved
> > +    UINT64    MustBeZero           : 2;   // Must Be Zero
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    PageTableBaseAddress : 40;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // No Execute bit
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_MAP_AND_DIRECTORY_POINTER;
> > +
> > +//
> > +// Page Table Entry 2MB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> > access to page
> > +    UINT64    MustBe1              : 1;   // Must be 1
> > +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB
> not
> > cleared on CR3 write
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    Pat                  : 1;   //
> > +    UINT64    MustBeZero           : 8;   // Must be zero
> > +    UINT64    PageTableBaseAddress : 31;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_ENTRY;
> > +
> > +//
> > +// Page Table Entry 1GB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> > access to page
> > +    UINT64    MustBe1              : 1;   // Must be 1
> > +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB
> not
> > cleared on CR3 write
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    Pat                  : 1;   //
> > +    UINT64    MustBeZero           : 17;  // Must be zero;
> > +    UINT64    PageTableBaseAddress : 22;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_1G_ENTRY;
> > +
> > +#pragma pack()
> > +
> > +//
> > +// Global Descriptor Table (GDT)
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR
> > mGdtEntries[] = {
> > +  /* selector { Global Segment Descriptor                              } */
> > +  /* 0x00 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // null descriptor
> > +  /* 0x08 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // linear data segment descriptor
> > +  /* 0x10 */ {
> > +    { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // linear code segment descriptor
> > +  /* 0x18 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system data segment descriptor
> > +  /* 0x20 */ {
> > +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system code segment descriptor
> > +  /* 0x28 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // spare segment descriptor
> > +  /* 0x30 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system data segment descriptor
> > +  /* 0x38 */ {
> > +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
> > +  },                                                                      // system code segment descriptor
> > +  /* 0x40 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // spare segment descriptor
> > +};
> > +
> > +//
> > +// IA32 Gdt register
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR  mGdt = {
> > +  sizeof (mGdtEntries) - 1,
> > +  (UINTN)mGdtEntries
> > +};
> > +
> > +/**
> > +  Calculate the total size of page table.
> > +
> > +  @return The size of page table.
> > +
> > +**/
> > +UINTN
> > +CalculatePageTableSize (
> > +  VOID
> > +  )
> > +{
> > +  UINT32   RegEax;
> > +  UINT32   RegEdx;
> > +  UINTN    TotalPagesNum;
> > +  UINT8    PhysicalAddressBits;
> > +  VOID     *Hob;
> > +  UINT32   NumberOfPml4EntriesNeeded;
> > +  UINT32   NumberOfPdpEntriesNeeded;
> > +  BOOLEAN  Page1GSupport;
> > +
> > +  Page1GSupport = FALSE;
> > +  if (PcdGetBool (PcdUse1GPageTable)) {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000001) {
> > +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> > +      if ((RegEdx & BIT26) != 0) {
> > +        Page1GSupport = TRUE;
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8)RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +
> > +  //
> > +  // Calculate the table entries needed.
> > +  //
> > +  if (PhysicalAddressBits <= 39 ) {
> > +    NumberOfPml4EntriesNeeded = 1;
> > +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 30));
> > +  } else {
> > +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 39));
> > +    NumberOfPdpEntriesNeeded  = 512;
> > +  }
> > +
> > +  if (!Page1GSupport) {
> > +    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) *
> > NumberOfPml4EntriesNeeded + 1;
> > +  } else {
> > +    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
> > +  }
> > +
> > +  return EFI_PAGES_TO_SIZE (TotalPagesNum);
> > +}
> > +
> > +/**
> > +  Allocates and fills in the Page Directory and Page Table Entries to
> > +  establish a 1:1 Virtual to Physical mapping.
> > +
> > +  @param[in]  PageTablesAddress  The base address of page table.
> > +
> > +**/
> > +VOID
> > +CreateIdentityMappingPageTables (
> > +  IN  EFI_PHYSICAL_ADDRESS  PageTablesAddress
> > +  )
> > +{
> > +  UINT32                          RegEax;
> > +  UINT32                          RegEdx;
> > +  UINT8                           PhysicalAddressBits;
> > +  EFI_PHYSICAL_ADDRESS            PageAddress;
> > +  UINTN                           IndexOfPml4Entries;
> > +  UINTN                           IndexOfPdpEntries;
> > +  UINTN                           IndexOfPageDirectoryEntries;
> > +  UINT32                          NumberOfPml4EntriesNeeded;
> > +  UINT32                          NumberOfPdpEntriesNeeded;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMap;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
> > +  PAGE_TABLE_ENTRY                *PageDirectoryEntry;
> > +  UINTN                           BigPageAddress;
> > +  VOID                            *Hob;
> > +  BOOLEAN                         Page1GSupport;
> > +  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
> > +
> > +  Page1GSupport = FALSE;
> > +  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +  if (RegEax >= 0x80000001) {
> > +    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> > +    if ((RegEdx & BIT26) != 0) {
> > +      Page1GSupport = TRUE;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8)RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +
> > +  //
> > +  // Calculate the table entries needed.
> > +  //
> > +  if (PhysicalAddressBits <= 39 ) {
> > +    NumberOfPml4EntriesNeeded = 1;
> > +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 30));
> > +  } else {
> > +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 39));
> > +    NumberOfPdpEntriesNeeded  = 512;
> > +  }
> > +
> > +  //
> > +  // Pre-allocate big pages to avoid later allocations.
> > +  //
> > +  BigPageAddress = (UINTN)PageTablesAddress;
> > +
> > +  //
> > +  // By architecture only one PageMapLevel4 exists - so lets allocate storage
> for
> > it.
> > +  //
> > +  PageMap         = (VOID *)BigPageAddress;
> > +  BigPageAddress += SIZE_4KB;
> > +
> > +  PageMapLevel4Entry = PageMap;
> > +  PageAddress        = 0;
> > +  for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> > NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++)
> {
> > +    //
> > +    // Each PML4 entry points to a page of Page Directory Pointer entires.
> > +    // So lets allocate space for them and fill them in in the IndexOfPdpEntries
> > loop.
> > +    //
> > +    PageDirectoryPointerEntry = (VOID *)BigPageAddress;
> > +    BigPageAddress           += SIZE_4KB;
> > +
> > +    //
> > +    // Make a PML4 Entry
> > +    //
> > +    PageMapLevel4Entry->Uint64         =
> > (UINT64)(UINTN)PageDirectoryPointerEntry;
> > +    PageMapLevel4Entry->Bits.ReadWrite = 1;
> > +    PageMapLevel4Entry->Bits.Present   = 1;
> > +
> > +    if (Page1GSupport) {
> > +      PageDirectory1GEntry = (VOID *)PageDirectoryPointerEntry;
> > +
> > +      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress +=
> > SIZE_1GB) {
> > +        //
> > +        // Fill in the Page Directory entries
> > +        //
> > +        PageDirectory1GEntry->Uint64         = (UINT64)PageAddress;
> > +        PageDirectory1GEntry->Bits.ReadWrite = 1;
> > +        PageDirectory1GEntry->Bits.Present   = 1;
> > +        PageDirectory1GEntry->Bits.MustBe1   = 1;
> > +      }
> > +    } else {
> > +      for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> > NumberOfPdpEntriesNeeded; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > +        //
> > +        // Each Directory Pointer entries points to a page of Page Directory
> entires.
> > +        // So allocate space for them and fill them in in the
> > IndexOfPageDirectoryEntries loop.
> > +        //
> > +        PageDirectoryEntry = (VOID *)BigPageAddress;
> > +        BigPageAddress    += SIZE_4KB;
> > +
> > +        //
> > +        // Fill in a Page Directory Pointer Entries
> > +        //
> > +        PageDirectoryPointerEntry->Uint64         =
> > (UINT64)(UINTN)PageDirectoryEntry;
> > +        PageDirectoryPointerEntry->Bits.ReadWrite = 1;
> > +        PageDirectoryPointerEntry->Bits.Present   = 1;
> > +
> > +        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress +=
> > SIZE_2MB) {
> > +          //
> > +          // Fill in the Page Directory entries
> > +          //
> > +          PageDirectoryEntry->Uint64         = (UINT64)PageAddress;
> > +          PageDirectoryEntry->Bits.ReadWrite = 1;
> > +          PageDirectoryEntry->Bits.Present   = 1;
> > +          PageDirectoryEntry->Bits.MustBe1   = 1;
> > +        }
> > +      }
> > +
> > +      for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > +        ZeroMem (
> > +          PageDirectoryPointerEntry,
> > +          sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> > +          );
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // For the PML4 entries we are not using fill in a null entry.
> > +  //
> > +  for ( ; IndexOfPml4Entries < 512; IndexOfPml4Entries++,
> > PageMapLevel4Entry++) {
> > +    ZeroMem (
> > +      PageMapLevel4Entry,
> > +      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> > +      );
> > +  }
> > +}
> > +
> > +/**
> > +  If in 32 bit protection mode, and coalesce image is of X64, switch to long
> mode.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @param  Context2                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully switched to long mode and
> execute
> > coalesce.
> > +  @retval Others                    Failed to execute coalesce in long mode.
> > +
> > +**/
> > +EFI_STATUS
> > +ModeSwitch (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1,
> > +  IN VOID                  *Context2
> > +  )
> > +{
> > +  UINTN            PageTableAddress;
> > +  UINTN            PageTableSize;
> > +  EFI_STATUS       Status;
> > +  IA32_DESCRIPTOR  Gdtr;
> > +
> > +  DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
> > +
> > +  //
> > +  // Save IA32 GDTR
> > +  //
> > +  AsmReadGdtr (&Gdtr);
> > +
> > +  //
> > +  // Set X64 GDTR
> > +  //
> > +  AsmWriteGdtr (&mGdt);
> > +
> > +  PageTableAddress = AsmReadCr3 () & 0xFFFFF000;
> > +
> > +  //
> > +  // If page table was created, no need to create
> > +  //
> > +  if (PageTableAddress == 0) {
> > +    PageTableSize = CalculatePageTableSize ();
> > +
> > +    PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES
> > (PageTableSize));
> > +    ASSERT (PageTableAddress != 0);
> > +
> > +    CreateIdentityMappingPageTables (PageTableAddress);
> > +
> > +    AsmWriteCr3 ((UINTN)PageTableAddress);
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n"));
> > +
> > +  Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1,
> > (UINT64)(UINTN)Context2, NULL);
> > +  if (Status != 0) {
> > +    Status = Status | MAX_BIT;
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status));
> > +
> > +  //
> > +  // Restore IA32 GDTR
> > +  //
> > +  AsmWriteGdtr (&Gdtr);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  )
> > +{
> > +  return ModeSwitch (Entry, Context1, NULL);
> > +}
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > new file mode 100644
> > index 0000000000..7fa42c32fb
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > @@ -0,0 +1,787 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM at PEI stage
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <Ppi/SmmAccess.h>
> > +#include <Ppi/SmmControl.h>
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/PeCoffLib.h>
> > +#include <Library/CacheMaintenanceLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/PeiServicesTablePointerLib.h>
> > +#include <Library/PeiServicesLib.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Guid/SmramMemoryReserve.h>
> > +#include <Guid/MmCoreData.h>
> > +#include <StandaloneMmIplPei.h>
> > +
> > +//
> > +// MM Core Private Data structure that contains the data shared between
> > +// the SMM IPL and the Standalone MM Core.
> > +//
> > +MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
> > +  MM_CORE_PRIVATE_DATA_SIGNATURE,     // Signature
> > +  0,                                  // MmramRangeCount
> > +  0,                                  // MmramRanges
> > +  0,                                  // MmEntryPoint
> > +  FALSE,                              // MmEntryPointRegistered
> > +  FALSE,                              // InMm
> > +  0,                                  // Mmst
> > +  0,                                  // CommunicationBuffer
> > +  0,                                  // BufferSize
> > +  EFI_SUCCESS,                        // ReturnStatus
> > +  0,                                  // MmCoreImageBase
> > +  0,                                  // MmCoreImageSize
> > +  0,                                  // MmCoreEntryPoint
> > +  0,                                  // StandaloneBfvAddress
> > +};
> > +
> > +//
> > +// Global pointer used to access mMmCorePrivateData from outside and
> inside
> > SMM
> > +//
> > +MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
> > +
> > +//
> > +// SMM IPL global variables
> > +//
> > +PEI_SMM_ACCESS_PPI    *mSmmAccess;
> > +EFI_SMRAM_DESCRIPTOR  *mCurrentSmramRange;
> > +BOOLEAN               mSmmLocked = FALSE;
> > +EFI_PHYSICAL_ADDRESS  mSmramCacheBase;
> > +UINT64                mSmramCacheSize;
> > +
> > +EFI_PEI_NOTIFY_DESCRIPTOR  mReadyToBootNotifyList = {
> > +  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> > +  &gEfiEventReadyToBootGuid,
> > +  ReadyToBootEvent
> > +};
> > +
> > +/**
> > +  This is the callback function on ready to boot.
> > +
> > +  Close and Lock smram range on ready to boot stage.
> > +
> > +  @param   PeiServices          General purpose services available to every PEIM.
> > +  @param   NotifyDescriptor     The notification structure this PEIM registered
> on
> > install.
> > +  @param   Ppi                  Pointer to the PPI data associated with this function.
> > +  @retval  EFI_SUCCESS          Close and lock smram ranges successfully.
> > +  @retval  Other                Close and lock smram ranges failed.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadyToBootEvent (
> > +  IN  EFI_PEI_SERVICES           **PeiServices,
> > +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> > +  IN  VOID                       *Ppi
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +
> > +  //
> > +  // Close all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Lock all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Lock ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Find the maximum SMRAM cache range that covers the range specified by
> > SmramRange.
> > +
> > +  This function searches and joins all adjacent ranges of SmramRange into a
> > range to be cached.
> > +
> > +  @param   SmramRange       The SMRAM range to search from.
> > +  @param   SmramCacheBase   The returned cache range base.
> > +  @param   SmramCacheSize   The returned cache range size.
> > +**/
> > +VOID
> > +GetSmramCacheRange (
> > +  IN  EFI_SMRAM_DESCRIPTOR  *SmramRange,
> > +  OUT EFI_PHYSICAL_ADDRESS  *SmramCacheBase,
> > +  OUT UINT64                *SmramCacheSize
> > +  )
> > +{
> > +  UINTN                 Index;
> > +  EFI_PHYSICAL_ADDRESS  RangeCpuStart;
> > +  UINT64                RangePhysicalSize;
> > +  BOOLEAN               FoundAdjacentRange;
> > +  EFI_SMRAM_DESCRIPTOR  *SmramRanges;
> > +
> > +  *SmramCacheBase = SmramRange->CpuStart;
> > +  *SmramCacheSize = SmramRange->PhysicalSize;
> > +
> > +  SmramRanges = (EFI_SMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +  do {
> > +    FoundAdjacentRange = FALSE;
> > +    for (Index = 0; Index < gMmCorePrivate->MmramRangeCount; Index++) {
> > +      RangeCpuStart     = SmramRanges[Index].CpuStart;
> > +      RangePhysicalSize = SmramRanges[Index].PhysicalSize;
> > +      if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase ==
> > (RangeCpuStart + RangePhysicalSize))) {
> > +        *SmramCacheBase    = RangeCpuStart;
> > +        *SmramCacheSize   += RangePhysicalSize;
> > +        FoundAdjacentRange = TRUE;
> > +      } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) &&
> > (RangePhysicalSize > 0)) {
> > +        *SmramCacheSize   += RangePhysicalSize;
> > +        FoundAdjacentRange = TRUE;
> > +      }
> > +    }
> > +  } while (FoundAdjacentRange);
> > +}
> > +
> > +/**
> > +  Get the fixed loading address from image header assigned by build tool. This
> > function only be called
> > +  when Loading module at Fixed address feature enabled.
> > +
> > +  @param  ImageContext              Pointer to the image context structure that
> > describes the PE/COFF
> > +                                    image that needs to be examined by this function.
> > +  @retval EFI_SUCCESS               An fixed loading address is assigned to this
> image
> > by build tools .
> > +  @retval EFI_NOT_FOUND             The image has no assigned fixed loading
> > address.
> > +**/
> > +EFI_STATUS
> > +GetPeCoffImageFixLoadingAssignedAddress (
> > +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> > +  )
> > +{
> > +  UINTN                            SectionHeaderOffset;
> > +  EFI_STATUS                       Status;
> > +  EFI_IMAGE_SECTION_HEADER         SectionHeader;
> > +  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
> > +  EFI_PHYSICAL_ADDRESS             FixLoadingAddress;
> > +  UINT16                           Index;
> > +  UINTN                            Size;
> > +  UINT16                           NumberOfSections;
> > +  EFI_PHYSICAL_ADDRESS             SmramBase;
> > +  UINT64                           SmmCodeSize;
> > +  UINT64                           ValueInSectionHeader;
> > +
> > +  //
> > +  // Build tool will calculate the smm code size and then patch the
> > PcdLoadFixAddressSmmCodePageNumber
> > +  //
> > +  SmmCodeSize       = EFI_PAGES_TO_SIZE (PcdGet32
> > (PcdLoadFixAddressSmmCodePageNumber));
> > +  FixLoadingAddress = 0;
> > +  Status            = EFI_NOT_FOUND;
> > +  SmramBase         = mCurrentSmramRange->CpuStart;
> > +  //
> > +  // Get PeHeader pointer
> > +  //
> > +  ImgHdr              = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8
> > *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
> > +  SectionHeaderOffset = (UINTN)(
> > +                                ImageContext->PeCoffHeaderOffset +
> > +                                sizeof (UINT32) +
> > +                                sizeof (EFI_IMAGE_FILE_HEADER) +
> > +                                ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
> > +                                );
> > +  NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
> > +
> > +  //
> > +  // Get base address from the first section header that doesn't point to code
> > section.
> > +  //
> > +  for (Index = 0; Index < NumberOfSections; Index++) {
> > +    //
> > +    // Read section header from file
> > +    //
> > +    Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
> > +    Status = ImageContext->ImageRead (
> > +                             ImageContext->Handle,
> > +                             SectionHeaderOffset,
> > +                             &Size,
> > +                             &SectionHeader
> > +                             );
> > +    if (EFI_ERROR (Status)) {
> > +      return Status;
> > +    }
> > +
> > +    Status = EFI_NOT_FOUND;
> > +
> > +    if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
> > +      //
> > +      // Build tool saves the offset to SMRAM base as image base in
> > PointerToRelocations & PointerToLineNumbers fields in the
> > +      // first section header that doesn't point to code section in image header.
> > And there is an assumption that when the
> > +      // feature is enabled, if a module is assigned a loading address by tools,
> > PointerToRelocations & PointerToLineNumbers
> > +      // fields should NOT be Zero, or else, these 2 fields should be set to Zero
> > +      //
> > +      ValueInSectionHeader = ReadUnaligned64 ((UINT64
> > *)&SectionHeader.PointerToRelocations);
> > +      if (ValueInSectionHeader != 0) {
> > +        //
> > +        // Found first section header that doesn't point to code section in which
> > build tool saves the
> > +        // offset to SMRAM base as image base in PointerToRelocations &
> > PointerToLineNumbers fields
> > +        //
> > +        FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase +
> > (INT64)ValueInSectionHeader);
> > +
> > +        if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <=
> > FixLoadingAddress)) {
> > +          //
> > +          // The assigned address is valid. Return the specified loading address
> > +          //
> > +          ImageContext->ImageAddress = FixLoadingAddress;
> > +          Status                     = EFI_SUCCESS;
> > +        }
> > +      }
> > +
> > +      break;
> > +    }
> > +
> > +    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO:
> > Loading module at fixed address %x, Status = %r \n", FixLoadingAddress,
> Status));
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Searches all the available firmware volumes and returns the first matching
> FFS
> > section.
> > +
> > +  This function searches all the firmware volumes for FFS files with FV file type
> > specified by FileType
> > +  The order that the firmware volumes is searched is not deterministic. For
> each
> > available FV a search
> > +  is made for FFS file of type FileType. If the FV contains more than one FFS
> file
> > with the same FileType,
> > +  the FileInstance instance will be the matched FFS file. For each FFS file found
> a
> > search
> > +  is made for FFS sections of type SectionType. If the FFS file contains at least
> > SectionInstance instances
> > +  of the FFS section specified by SectionType, then the SectionInstance
> instance
> > is returned in Buffer.
> > +  Buffer is allocated using AllocatePool(), and the size of the allocated buffer
> is
> > returned in Size.
> > +  It is the caller's responsibility to use FreePool() to free the allocated buffer.
> > +
> > +  If Buffer is NULL, then ASSERT().
> > +  If Size is NULL, then ASSERT().
> > +
> > +  @param  FileType             Indicates the FV file type to search for within all
> > available FVs.
> > +  @param  FileInstance         Indicates which file instance within all available
> FVs
> > specified by FileType.
> > +                               FileInstance starts from zero.
> > +  @param  SectionType          Indicates the FFS section type to search for
> within
> > the FFS file
> > +                               specified by FileType with FileInstance.
> > +  @param  SectionInstance      Indicates which section instance within the FFS
> > file
> > +                               specified by FileType with FileInstance to retrieve.
> > SectionInstance starts from zero.
> > +  @param  Buffer               On output, a pointer to a callee allocated buffer
> > containing the FFS file section that was found.
> > +                               Is it the caller's responsibility to free this buffer using
> > FreePool().
> > +  @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
> > +
> > +  @retval  EFI_SUCCESS          The specified FFS section was returned.
> > +  @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
> > +  @retval  EFI_OUT_OF_RESOURCES There are not enough resources
> available
> > to retrieve the matching FFS section.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetSectionFromAnyFvByFileType  (
> > +  IN  EFI_FV_FILETYPE   FileType,
> > +  IN  UINTN             FileInstance,
> > +  IN  EFI_SECTION_TYPE  SectionType,
> > +  IN  UINTN             SectionInstance,
> > +  OUT VOID              **Buffer,
> > +  OUT UINTN             *Size
> > +  )
> > +{
> > +  EFI_STATUS           Status;
> > +  UINTN                FvIndex;
> > +  EFI_PEI_FV_HANDLE    VolumeHandle;
> > +  EFI_PEI_FILE_HANDLE  FileHandle;
> > +  EFI_PE32_SECTION     *SectionData;
> > +  UINT32               SectionSize;
> > +
> > +  //
> > +  // Search all FV
> > +  //
> > +  VolumeHandle = NULL;
> > +  for (FvIndex = 0; ; FvIndex++) {
> > +    Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
> > +    if (EFI_ERROR (Status)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Search PEIM FFS
> > +    //
> > +    FileHandle = NULL;
> > +    Status     = PeiServicesFfsFindNextFile (FileType, VolumeHandle,
> &FileHandle);
> > +    if (EFI_ERROR (Status)) {
> > +      continue;
> > +    }
> > +
> > +    //
> > +    // Search Section
> > +    //
> > +    SectionData = NULL;
> > +    Status      = PeiServicesFfsFindSectionData (SectionType, FileHandle, Buffer);
> > +    if (EFI_ERROR (Status)) {
> > +      continue;
> > +    }
> > +
> > +    //
> > +    // Great!
> > +    //
> > +    SectionData = (EFI_PE32_SECTION *)((UINT8 *)*Buffer - sizeof
> > (EFI_PE32_SECTION));
> > +    ASSERT (SectionData->Type == SectionType);
> > +    SectionSize  = *(UINT32 *)SectionData->Size;
> > +    SectionSize &= 0xFFFFFF;
> > +    *Size        = SectionSize - sizeof (EFI_PE32_SECTION);
> > +
> > +    if (FileType == EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
> > +      EFI_FV_INFO  VolumeInfo;
> > +      //
> > +      // This is SMM BFV
> > +      //
> > +      Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
> > +      if (!EFI_ERROR (Status)) {
> > +        gMmCorePrivate->StandaloneBfvAddress =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
> > +      }
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +  Load the SMM Core image into SMRAM and executes the SMM Core from
> > SMRAM.
> > +
> > +  @param[in, out] SmramRange            Descriptor for the range of SMRAM to
> > reload the
> > +                                        currently executing image, the rang of SMRAM to
> > +                                        hold SMM Core will be excluded.
> > +  @param[in, out] SmramRangeSmmCore     Descriptor for the range of
> SMRAM
> > to hold SMM Core.
> > +
> > +  @param[in]      Context               Context to pass into SMM Core
> > +
> > +  @return  EFI_STATUS
> > +
> > +**/
> > +EFI_STATUS
> > +ExecuteSmmCoreFromSmram (
> > +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRange,
> > +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRangeSmmCore,
> > +  IN     VOID                  *Context
> > +  )
> > +{
> > +  EFI_STATUS                    Status;
> > +  VOID                          *SourceBuffer;
> > +  UINTN                         SourceSize;
> > +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
> > +  UINTN                         PageCount;
> > +  VOID                          *HobList;
> > +
> > +  Status = PeiServicesGetHobList (&HobList);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Search all Firmware Volumes for a PE/COFF image in a file of type
> > SMM_CORE
> > +  //
> > +  Status = GetSectionFromAnyFvByFileType (
> > +             EFI_FV_FILETYPE_MM_CORE_STANDALONE,
> > +             0,
> > +             EFI_SECTION_PE32,
> > +             0,
> > +             &SourceBuffer,
> > +             &SourceSize
> > +             );
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // Initialize ImageContext
> > +  //
> > +  ImageContext.Handle    = SourceBuffer;
> > +  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
> > +
> > +  //
> > +  // Get information about the image being loaded
> > +  //
> > +  Status = PeCoffLoaderGetImageInfo (&ImageContext);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // if Loading module at Fixed Address feature is enabled, the SMM core
> driver
> > will be loaded to
> > +  // the address assigned by build tool.
> > +  //
> > +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +    //
> > +    // Get the fixed loading address assigned by Build tool
> > +    //
> > +    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
> > +    if (!EFI_ERROR (Status)) {
> > +      //
> > +      // Since the memory range to load SMM CORE will be cut out in SMM core,
> > so no need to allocate and free this range
> > +      //
> > +      PageCount = 0;
> > +      //
> > +      // Reserved Smram Region for SmmCore is not used, and remove it from
> > SmramRangeCount.
> > +      //
> > +      gMmCorePrivate->MmramRangeCount--;
> > +    } else {
> > +      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading
> module
> > at fixed address at address failed\n"));
> > +      //
> > +      // Allocate memory for the image being loaded from the
> > EFI_SRAM_DESCRIPTOR
> > +      // specified by SmramRange
> > +      //
> > +      PageCount = (UINTN)EFI_SIZE_TO_PAGES
> ((UINTN)ImageContext.ImageSize
> > + ImageContext.SectionAlignment);
> > +
> > +      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> > +      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> > +
> > +      SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> > +      SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> > SmramRange->PhysicalSize;
> > +      SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> > SmramRange->PhysicalSize;
> > +      SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> > EFI_ALLOCATED;
> > +      SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> > +
> > +      //
> > +      // Align buffer on section boundary
> > +      //
> > +      ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> > +    }
> > +  } else {
> > +    //
> > +    // Allocate memory for the image being loaded from the
> > EFI_SRAM_DESCRIPTOR
> > +    // specified by SmramRange
> > +    //
> > +    PageCount = (UINTN)EFI_SIZE_TO_PAGES
> ((UINTN)ImageContext.ImageSize +
> > ImageContext.SectionAlignment);
> > +
> > +    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> > +    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> > +
> > +    SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> > +    SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> > SmramRange->PhysicalSize;
> > +    SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> > SmramRange->PhysicalSize;
> > +    SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> > EFI_ALLOCATED;
> > +    SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> > +
> > +    //
> > +    // Align buffer on section boundary
> > +    //
> > +    ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> > +  }
> > +
> > +  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
> > +  ImageContext.ImageAddress &=
> > ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
> > +
> > +  //
> > +  // Print debug message showing SMM Core load address.
> > +  //
> > +  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM
> > address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
> > +
> > +  //
> > +  // Load the image to our new buffer
> > +  //
> > +  Status = PeCoffLoaderLoadImage (&ImageContext);
> > +  if (!EFI_ERROR (Status)) {
> > +    //
> > +    // Relocate the image in our new buffer
> > +    //
> > +    Status = PeCoffLoaderRelocateImage (&ImageContext);
> > +    if (!EFI_ERROR (Status)) {
> > +      //
> > +      // Flush the instruction cache so the image data are written before we
> > execute it
> > +      //
> > +      InvalidateInstructionCacheRange ((VOID
> > *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
> > +
> > +      //
> > +      // Print debug message showing SMM Core entry point address.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM
> > address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
> > +
> > +      gMmCorePrivate->MmCoreImageBase = ImageContext.ImageAddress;
> > +      gMmCorePrivate->MmCoreImageSize = ImageContext.ImageSize;
> > +      DEBUG ((DEBUG_INFO, "SmmCoreImageBase - 0x%016lx\n",
> > gMmCorePrivate->MmCoreImageBase));
> > +      DEBUG ((DEBUG_INFO, "SmmCoreImageSize - 0x%016lx\n",
> > gMmCorePrivate->MmCoreImageSize));
> > +
> > +      gMmCorePrivate->MmCoreEntryPoint = ImageContext.EntryPoint;
> > +
> > +      //
> > +      // Print debug message showing Standalone MM Core entry point address.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM
> > address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
> > +
> > +      //
> > +      // Execute image
> > +      //
> > +      LoadSmmCore (ImageContext.EntryPoint, HobList);
> > +    }
> > +  }
> > +
> > +  //
> > +  // If the load operation, relocate operation, or the image execution return
> an
> > +  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR
> > specified by
> > +  // SmramRange
> > +  //
> > +  if (EFI_ERROR (Status)) {
> > +    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
> > +  }
> > +
> > +  //
> > +  // Always free memory allocated by GetFileBufferByFilePath ()
> > +  //
> > +  FreePool (SourceBuffer);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Get full SMRAM ranges.
> > +
> > +  It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved
> > ranges from
> > +  SmmConfiguration protocol, split the entries if there is overlap between
> them.
> > +  It will also reserve one entry for SMM core.
> > +
> > +  @param[in]  PeiServices           Describes the list of possible PEI Services.
> > +  @param[out] FullSmramRangeCount   Output pointer to full SMRAM range
> > count.
> > +
> > +  @return Pointer to full SMRAM ranges.
> > +
> > +**/
> > +EFI_SMRAM_DESCRIPTOR *
> > +GetFullSmramRanges (
> > +  IN  CONST EFI_PEI_SERVICES  **PeiServices,
> > +  OUT       UINTN             *FullSmramRangeCount
> > +  )
> > +{
> > +  EFI_STATUS            Status;
> > +  UINTN                 Size;
> > +  EFI_SMRAM_DESCRIPTOR  *FullSmramRanges;
> > +  UINTN                 AdditionSmramRangeCount;
> > +  UINTN                 SmramRangeCount;
> > +
> > +  //
> > +  // Get SMRAM information.
> > +  //
> > +  Size   = 0;
> > +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, &Size, NULL);
> > +  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
> > +
> > +  SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
> > +
> > +  //
> > +  // Reserve one entry SMM Core in the full SMRAM ranges.
> > +  //
> > +  AdditionSmramRangeCount = 1;
> > +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +    //
> > +    // Reserve two entries for all SMM drivers & SMM Core in the full SMRAM
> > ranges.
> > +    //
> > +    AdditionSmramRangeCount = 2;
> > +  }
> > +
> > +  *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
> > +  Size                 = (*FullSmramRangeCount) * sizeof
> (EFI_SMRAM_DESCRIPTOR);
> > +  FullSmramRanges      = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
> > +  ASSERT (FullSmramRanges != NULL);
> > +  if (FullSmramRanges == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, &Size, FullSmramRanges);
> > +
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return FullSmramRanges;
> > +}
> > +
> > +/**
> > +  The Entry Point for SMM IPL
> > +
> > +  Load SMM Core into SMRAM.
> > +
> > +  @param  FileHandle  Handle of the file being invoked.
> > +  @param  PeiServices Describes the list of possible PEI Services.
> > +
> > +  @retval EFI_SUCCESS    The entry point is executed successfully.
> > +  @retval Other          Some error occurred when executing this entry point.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmIplEntry (
> > +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> > +  IN CONST EFI_PEI_SERVICES     **PeiServices
> > +  )
> > +{
> > +  EFI_STATUS             Status;
> > +  UINTN                  Index;
> > +  UINT64                 MaxSize;
> > +  UINT64                 SmmCodeSize;
> > +  MM_CORE_DATA_HOB_DATA  SmmCoreDataHobData;
> > +  EFI_SMRAM_DESCRIPTOR   *MmramRanges;
> > +  EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmDriver;
> > +
> > +  //
> > +  // Build Hob for SMM and DXE phase
> > +  //
> > +  SmmCoreDataHobData.Address =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES
> > (sizeof (mMmCorePrivateData)));
> > +  ASSERT (SmmCoreDataHobData.Address != 0);
> > +  gMmCorePrivate = (VOID *)(UINTN)SmmCoreDataHobData.Address;
> > +  CopyMem ((VOID *)(UINTN)SmmCoreDataHobData.Address,
> > &mMmCorePrivateData, sizeof (mMmCorePrivateData));
> > +  DEBUG ((DEBUG_INFO, "gMmCorePrivate - 0x%x\n", gMmCorePrivate));
> > +
> > +  BuildGuidDataHob (
> > +    &gMmCoreDataHobGuid,
> > +    (VOID *)&SmmCoreDataHobData,
> > +    sizeof (SmmCoreDataHobData)
> > +    );
> > +
> > +  //
> > +  // Get SMM Access Protocol
> > +  //
> > +  Status = PeiServicesLocatePpi (&gPeiSmmAccessPpiGuid, 0, NULL, (VOID
> > **)&mSmmAccess);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Get SMRAM information
> > +  //
> > +  gMmCorePrivate->MmramRanges =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)GetFullSmramRanges (PeiServices, (UINTN
> > *)&gMmCorePrivate->MmramRangeCount);
> > +  ASSERT (gMmCorePrivate->MmramRanges != 0);
> > +  if (gMmCorePrivate->MmramRanges == 0) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  //
> > +  // Open all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Open ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Print debug message that the SMRAM window is now open.
> > +  //
> > +  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
> > +
> > +  //
> > +  // Find the largest SMRAM range between 1MB and 4GB that is at least
> 256KB
> > - 4K in size
> > +  //
> > +  mCurrentSmramRange = NULL;
> > +  MmramRanges        = (EFI_MMRAM_DESCRIPTOR
> *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +  if (MmramRanges == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "Fail to retrieve MmramRanges\n"));
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index <
> > gMmCorePrivate->MmramRangeCount; Index++) {
> > +    //
> > +    // Skip any SMRAM region that is already allocated, needs testing, or needs
> > ECC initialization
> > +    //
> > +    if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED |
> > EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
> > +      continue;
> > +    }
> > +
> > +    if (MmramRanges[Index].CpuStart >= BASE_1MB) {
> > +      if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize)
> <=
> > BASE_4GB) {
> > +        if (MmramRanges[Index].PhysicalSize >= MaxSize) {
> > +          MaxSize            = MmramRanges[Index].PhysicalSize;
> > +          mCurrentSmramRange = &MmramRanges[Index];
> > +        }
> > +      }
> > +    }
> > +  }
> > +
> > +  if (mCurrentSmramRange != NULL) {
> > +    //
> > +    // Print debug message showing SMRAM window that will be used by SMM
> > IPL and SMM Core
> > +    //
> > +    DEBUG ((
> > +      DEBUG_INFO,
> > +      "SMM IPL found SMRAM window %p - %p\n",
> > +      (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
> > +      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart +
> > mCurrentSmramRange->PhysicalSize - 1)
> > +      ));
> > +
> > +    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase,
> > &mSmramCacheSize);
> > +
> > +    //
> > +    // if Loading module at Fixed Address feature is enabled, save the SMRAM
> > base to Load
> > +    // Modules At Fixed Address Configuration Table.
> > +    //
> > +    if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +      //
> > +      // Build tool will calculate the smm code size and then patch the
> > PcdLoadFixAddressSmmCodePageNumber
> > +      //
> > +      SmmCodeSize = LShiftU64 (PcdGet32
> > (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
> > +      //
> > +      // The SMRAM available memory is assumed to be larger than
> SmmCodeSize
> > +      //
> > +      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
> > +      //
> > +      // Fill the Smram range for all SMM code
> > +      //
> > +      MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +      //
> > +      // Note: SmramRanges specific for all SMM code will put in the
> > gMmCorePrivate->MmramRangeCount - 2.
> > +      //
> > +      SmramRangeSmmDriver                = &MmramRanges[gMmCorePrivate-
> > >MmramRangeCount - 2];
> > +      SmramRangeSmmDriver->CpuStart      = mCurrentSmramRange->CpuStart;
> > +      SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange-
> > >PhysicalStart;
> > +      SmramRangeSmmDriver->RegionState   = mCurrentSmramRange-
> > >RegionState | EFI_ALLOCATED;
> > +      SmramRangeSmmDriver->PhysicalSize  = SmmCodeSize;
> > +
> > +      mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
> > +      mCurrentSmramRange->CpuStart      = mCurrentSmramRange->CpuStart +
> > SmmCodeSize;
> > +      mCurrentSmramRange->PhysicalStart = mCurrentSmramRange-
> > >PhysicalStart + SmmCodeSize;
> > +    }
> > +
> > +    //
> > +    // Load SMM Core into SMRAM and execute it from SMRAM
> > +    // Note: SmramRanges specific for SMM Core will put in the
> gMmCorePrivate-
> > >MmramRangeCount - 1.
> > +    //
> > +    Status = ExecuteSmmCoreFromSmram (
> > +               mCurrentSmramRange,
> > +               &(((EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges)[gMmCorePrivate->MmramRangeCount - 1]),
> > +               gMmCorePrivate
> > +               );
> > +    if (EFI_ERROR (Status)) {
> > +      //
> > +      // Print error message that the SMM Core failed to be loaded and
> executed.
> > +      //
> > +      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM
> Core
> > from SMRAM\n"));
> > +    }
> > +  } else {
> > +    //
> > +    // Print error message that there are not enough SMRAM resources to load
> > the SMM Core.
> > +    //
> > +    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM
> > region to load SMM Core\n"));
> > +  }
> > +
> > +  //
> > +  // If the SMM Core could not be loaded then close SMRAM window, free
> > allocated
> > +  // resources, and return an error so SMM IPL will be unloaded.
> > +  //
> > +  if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
> > +    //
> > +    // Close all SMRAM ranges
> > +    //
> > +    Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +    ASSERT_EFI_ERROR (Status);
> > +
> > +    //
> > +    // Print debug message that the SMRAM window is now closed.
> > +    //
> > +    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
> > +
> > +    //
> > +    // Free all allocated resources
> > +    //
> > +    FreePool ((VOID *)(UINTN)gMmCorePrivate->MmramRanges);
> > +
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  //
> > +  // Create ready to boot for close and lock smram ranges
> > +  //
> > +  Status = PeiServicesNotifyPpi (&mReadyToBootNotifyList);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > new file mode 100644
> > index 0000000000..6d3497f2ea
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > @@ -0,0 +1,32 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <StandaloneMm.h>
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  )
> > +{
> > +  STANDALONE_MM_FOUNDATION_ENTRY_POINT  EntryPoint;
> > +
> > +  EntryPoint =
> (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
> > +  return EntryPoint (Context1);
> > +}
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > new file mode 100644
> > index 0000000000..7f887eb77d
> > --- /dev/null
> > +++
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > @@ -0,0 +1,148 @@
> > +;------------------------------------------------------------------------------
> > +;
> > +; Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +; SPDX-License-Identifier: BSD-2-Clause-Patent
> > +;
> > +; Module Name:
> > +;
> > +;    Thunk32To64.nasm
> > +;
> > +; Abstract:
> > +;
> > +;   This is the assembly code to transition from long mode to compatibility
> > +;   mode to execute 32-bit code and then transit back to long mode.
> > +;
> > +;------------------------------------------------------------------------------
> > +
> > +    SECTION .text
> > +
> > +;------------------------------------------------------------------------------
> > +; Procedure:    AsmExecute64BitCode
> > +;
> > +; Input:        None
> > +;
> > +; Output:       None
> > +;
> > +; Prototype:    UINT32
> > +;               AsmExecute64BitCode (
> > +;                 IN UINT64           Function,
> > +;                 IN UINT64           Param1,
> > +;                 IN UINT64           Param2,
> > +;                 IN IA32_DESCRIPTOR  *InternalGdtr
> > +;                 );
> > +;
> > +;
> > +; Description:  A thunk function to execute 32-bit code in long mode.
> > +;
> > +;------------------------------------------------------------------------------
> > +global ASM_PFX(AsmExecute64BitCode)
> > +ASM_PFX(AsmExecute64BitCode):
> > +;
> > +; +---------+
> > +; | EIP(64) |
> > +; +---------+
> > +; | CS (64) |
> > +; +---------+
> > +; | EIP(32) |
> > +; +---------+
> > +; | CS (32) |<-ESP (16 bytes aligned)
> > +; +---------+
> > +; | ...     |
> > +; +---------+
> > +; | ebx     |<-EBP
> > +; +---------+
> > +; | ebp     |<-EBP + 4
> > +; +---------+
> > +; | esi     |<-EBP + 8
> > +; +---------+
> > +; | edi     |<-EBP + 12
> > +; +---------+
> > +; | RFlags  |<-EBP + 16
> > +; +---------+
> > +; | RetAddr |<-EBP (org)
> > +; +---------+
> > +; | Func    |<-EBP + 24
> > +; | Func    |
> > +; +---------+
> > +; | Param1  |<-EBP + 32
> > +; | Param1  |
> > +; +---------+
> > +; | Param2  |<-EBP + 40
> > +; | Param2  |
> > +; +---------+
> > +; | Gdtr    |
> > +; +---------+
> > +;
> > +    ;
> > +    ; Save general purpose register and RFlags register
> > +    ;
> > +    pushfd
> > +    push    edi
> > +    push    esi
> > +    push    ebp
> > +    push    ebx
> > +    mov     ebp, esp
> > +
> > +    and     esp, 0FFFFFFF0h
> > +
> > +    push    010h                        ; protected mode selector on stack
> > +    mov     eax, Compatible             ; offset for LongMode
> > +    push    eax                         ; offset on stack
> > +
> > +    push    038h                        ; long mode selector on stack
> > +    mov     eax, LongMode               ; offset for LongMode
> > +    push    eax                         ; offset on stack
> > +
> > +    mov     eax, cr4
> > +    or      al, 020h
> > +    mov     cr4, eax                    ; enable PAE
> > +    mov     ecx, 0c0000080h
> > +    rdmsr
> > +    or      ah, 1                       ; set LME
> > +    wrmsr
> > +    mov     eax, cr0
> > +    bts     eax, 31                     ; set PG
> > +    mov     cr0, eax                    ; enable paging
> > +    retf                                ; topmost 2 dwords hold the address
> > +LongMode:                               ; long mode starts here
> > +
> > +    ; Call long mode function
> > +    DB      67h, 48h                    ; 32-bit address size, 64-bit operand size
> > +    mov     eax, [ebp + 24]             ; mov rbx, [ebp + 24]
> > +    DB      67h, 48h
> > +    mov     ecx, [ebp + 24 + 8]         ; mov rcx, [ebp + 24 + 8]
> > +    DB      67h, 48h
> > +    mov     edx, [ebp + 24 + 16]        ; mov rdx, [ebp + 24 + 16]
> > +
> > +    DB      48h
> > +    add     esp, -20h                   ; add rsp, -20h
> > +    call    eax                         ; call rax
> > +    DB      48h
> > +    add     esp, 20h                    ; add rsp, 20h
> > +
> > +    ; after long mode function call
> > +    mov     ebx, eax
> > +
> > +    retf
> > +Compatible:
> > +    mov     ecx, cr0
> > +    btc     ecx, 31                     ; clear PG
> > +    mov     cr0, ecx                    ; disable paging
> > +    mov     ecx, 0C0000080h
> > +    rdmsr
> > +    btc     eax, 8                      ; clear LME
> > +    wrmsr
> > +
> > +    ;
> > +    ; Restore C register and eax hold the return status from 32-bit function.
> > +    ; Note: Do not touch rax from now which hold the return value from IA32
> > function
> > +    ;
> > +    mov     eax, ebx                    ; put return status to EAX
> > +    mov     esp, ebp                    ; restore stack pointer
> > +    pop     ebx
> > +    pop     ebp
> > +    pop     esi
> > +    pop     edi
> > +    popfd
> > +
> > +    ret
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > new file mode 100644
> > index 0000000000..be0aae70f0
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > @@ -0,0 +1,66 @@
> > +/** @file
> > +  Private header with declarations and definitions specific to the Standalone
> > +  MM IPL PEI driver
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef STANDALONE_MM_IPL_PEI_H_
> > +#define STANDALONE_MM_IPL_PEI_H_
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  );
> > +
> > +/**
> > +  Assembly function to transition from long mode to compatibility mode to
> > +  execute 32-bit code and then transit back to long mode.
> > +
> > +  @param[in] Function     The 32bit code entry to be executed.
> > +  @param[in] Param1       The first parameter to pass to 32bit code
> > +  @param[in] Param2       The second parameter to pass to 32bit code
> > +  @param[in] InternalGdtr The GDT and GDT descriptor used by this library
> > +
> > +  @retval status.
> > +**/
> > +UINT32
> > +AsmExecute64BitCode (
> > +  IN UINT64           Function,
> > +  IN UINT64           Param1,
> > +  IN UINT64           Param2,
> > +  IN IA32_DESCRIPTOR  *InternalGdtr
> > +  );
> > +
> > +/**
> > +  This is the callback function on ready to boot.
> > +
> > +  Close and lock smram ranges on ready to boot stage.
> > +
> > +  @param   PeiServices       General purpose services available to every PEIM.
> > +  @param   NotifyDescriptor  The notification structure this PEIM registered
> on
> > install.
> > +  @param   Ppi               Pointer to the PPI data associated with this function.
> > +  @retval  EFI_SUCCESS       Close and lock smram ranges successfully.
> > +  @retval  Other             Close and lock smram ranges failed.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadyToBootEvent (
> > +  IN  EFI_PEI_SERVICES           **PeiServices,
> > +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> > +  IN  VOID                       *Ppi
> > +  );
> > +
> > +#endif
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > new file mode 100644
> > index 0000000000..ff4c67a92c
> > --- /dev/null
> > +++
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > @@ -0,0 +1,75 @@
> > +## @file
> > +#  This module provide a Standalone SMM compliant implementation of SMM
> > IPL PEIM.
> > +#
> > +#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x00010005
> > +  BASE_NAME                      = StandaloneMmIplPei
> > +  FILE_GUID                      = 578A0D17-2DC0-4C7D-A121-D8D771923BB0
> > +  MODULE_TYPE                    = PEIM
> > +  VERSION_STRING                 = 1.0
> > +  PI_SPECIFICATION_VERSION       = 0x0001000A
> > +  ENTRY_POINT                    = SmmIplEntry
> > +
> > +#
> > +# The following information is for reference only and not required by the
> build
> > tools.
> > +#
> > +#  VALID_ARCHITECTURES           = IA32 X64
> > +#
> > +
> > +[Sources]
> > +  StandaloneMmIplPei.h
> > +  StandaloneMmIplPei.c
> > +
> > +[Sources.Ia32]
> > +  Ia32/LoadSmmCore.c
> > +  Ia32/Thunk32To64.nasm
> > +
> > +[Sources.X64]
> > +  X64/LoadSmmCore.c
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +  StandaloneMmPkg/StandaloneMmPkg.dec
> > +
> > +[LibraryClasses]
> > +  PeimEntryPoint
> > +  PeiServicesTablePointerLib
> > +  PeiServicesLib
> > +  BaseLib
> > +  BaseMemoryLib
> > +  PeCoffLib
> > +  CacheMaintenanceLib
> > +  MemoryAllocationLib
> > +  DebugLib
> > +  HobLib
> > +  IntrinsicLib
> > +
> > +[Guids]
> > +  gMmCoreDataHobGuid
> > +  gEfiEventReadyToBootGuid
> > +
> > +[Ppis]
> > +  gPeiSmmAccessPpiGuid                     ## CONSUMES
> > +  gPeiSmmControlPpiGuid                    ## CONSUMES
> > +
> > +[FeaturePcd.IA32]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ##
> > CONSUMES
> > +
> > +[Pcd.IA32]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ##
> > SOMETIMES_CONSUMES
> > +
> > +[Pcd]
> > +
> gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber
> > ## SOMETIMES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable
> ##
> > CONSUMES
> > +
> > +[Depex]
> > +  gPeiSmmAccessPpiGuid AND
> > +  gPeiSmmControlPpiGuid
> > +
> > diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > index 4777532a7e..872f7958be 100644
> > --- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > +++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > @@ -78,7 +78,9 @@
> >      ## options defined .pytool/Plugin/SpellCheck
> >      "SpellCheck": {
> >          "AuditOnly": False,
> > -        "IgnoreFiles": [],           # use gitignore syntax to ignore errors
> > +        "IgnoreFiles": [
> > +            "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm"
> > +        ],           # use gitignore syntax to ignore errors
> >                                       # in matching files
> >          "ExtendWords": [
> >              "Bsymbolic",
> > diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc
> > b/StandaloneMmPkg/StandaloneMmPkg.dsc
> > index 8012f93b7d..d88471fe82 100644
> > --- a/StandaloneMmPkg/StandaloneMmPkg.dsc
> > +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc
> > @@ -20,7 +20,7 @@
> >    PLATFORM_VERSION               = 1.0
> >    DSC_SPECIFICATION              = 0x00010011
> >    OUTPUT_DIRECTORY               = Build/StandaloneMm
> > -  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM
> > +  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM|IA32
> >    BUILD_TARGETS                  = DEBUG|RELEASE
> >    SKUID_IDENTIFIER               = DEFAULT
> >
> > @@ -60,6 +60,14 @@
> >
> >
> StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoin
> > t/StandaloneMmDriverEntryPoint.inf
> >
> >
> VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/V
> > ariableMmDependency.inf
> >
> > +[LibraryClasses.common.PEIM]
> > +  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> > +  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
> > +
> >
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllo
> c
> > ationLib.inf
> > +  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> > +
> >
> PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServi
> c
> > esTablePointerLib.inf
> > +  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
> > +
> >  [LibraryClasses.AARCH64, LibraryClasses.ARM]
> >    ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
> >
> >
> StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStand
> > aloneMmLib.inf
> > @@ -104,7 +112,7 @@
> >  #       generated for it, but the binary will not be put into any firmware volume.
> >  #
> >
> >
> #################################################################
> > ##################################
> > -[Components.common]
> > +[Components.AARCH64, Components.ARM, Components.X64]
> >    #
> >    # MM Core
> >    #
> > @@ -122,6 +130,9 @@
> >    StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
> >
> >
> StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMm
> > PeCoffExtraActionLib.inf
> >
> > +[Components.X64, Components.IA32]
> > +  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > +
> >
> >
> #################################################################
> > ##################################
> >  #
> >  # BuildOptions Section - Define the module specific tool chain flags that
> should
> > be used as
> > diff --git a/UefiPayloadPkg/UniversalPayloadBuild.sh
> > b/UefiPayloadPkg/UniversalPayloadBuild.sh
> > index 9a72eedd35..bacf5233a8 100644
> > --- a/UefiPayloadPkg/UniversalPayloadBuild.sh
> > +++ b/UefiPayloadPkg/UniversalPayloadBuild.sh
> > @@ -1,17 +1,17 @@
> > -#!/usr/bin/env bash
> > -#
> > -# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > -#
> > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > -#
> > -
> > -if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> > -    echo python_exe=${PYTHON_COMMAND}
> > -fi
> > -
> > -# Get file path of UniversalPayloadBuild.sh
> > -uplbld_filepath=${BASH_SOURCE:-$0}
> > -# Remove ".sh" extension
> > -uplbld_filepath_noext=${uplbld_filepath%.*}
> > -# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> > -exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> > +#!/usr/bin/env bash
> > +#
> > +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +
> > +if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> > +    echo python_exe=${PYTHON_COMMAND}
> > +fi
> > +
> > +# Get file path of UniversalPayloadBuild.sh
> > +uplbld_filepath=${BASH_SOURCE:-$0}
> > +# Remove ".sh" extension
> > +uplbld_filepath_noext=${uplbld_filepath%.*}
> > +# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> > +exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> > diff --git a/edksetup.sh b/edksetup.sh
> > index cab3a8c113..553e1676d0 100755
> > --- a/edksetup.sh
> > +++ b/edksetup.sh
> > @@ -1,147 +1,147 @@
> > -#
> > -# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> > -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > -#
> > -# In *inux environment, the build tools's source is required and need to be
> > compiled
> > -# firstly, please reference
> > https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-
> Github-
> > Quick-Start
> > -# to get how to setup build tool.
> > -#
> > -# Setup the environment for unix-like systems running a bash-like shell.
> > -# This file must be "sourced" not merely executed. For example: ".
> edksetup.sh"
> > -#
> > -# CYGWIN users: Your path and filename related environment variables
> should
> > be
> > -# set up in the unix style.  This script will make the necessary conversions to
> > -# windows style.
> > -#
> > -# Please reference edk2 user manual for more detail descriptions at
> > https://github.com/tianocore-
> > docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> > -#
> > -
> > -SCRIPTNAME="edksetup.sh"
> > -RECONFIG=FALSE
> > -
> > -HelpMsg()
> > -{
> > -  echo "Usage: $SCRIPTNAME [Options]"
> > -  echo
> > -  echo "The system environment variable, WORKSPACE, is always set to the
> > current"
> > -  echo "working directory."
> > -  echo
> > -  echo "Options: "
> > -  echo "  --help, -h, -?        Print this help screen and exit."
> > -  echo
> > -  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with
> the"
> > -  echo "                        template files from the BaseTools/Conf directory."
> > -  echo
> > -  echo Please note: This script must be \'sourced\' so the environment can be
> > changed.
> > -  echo ". $SCRIPTNAME"
> > -  echo "source $SCRIPTNAME"
> > -}
> > -
> > -SetWorkspace()
> > -{
> > -  #
> > -  # If WORKSPACE is already set, then we can return right now
> > -  #
> > -  export PYTHONHASHSEED=1
> > -  if [ -n "$WORKSPACE" ]
> > -  then
> > -    return 0
> > -  fi
> > -
> > -  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> > -  then
> > -    echo Source this script from the base of your tree.  For example:
> > -    echo "  cd /Path/To/Edk2/Clone"
> > -    echo "  . $SCRIPTNAME"
> > -    return 1
> > -  fi
> > -
> > -  #
> > -  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> > -  #
> > -  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> > -  then
> > -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > -    echo Please point EDK_TOOLS_PATH at the directory that contains
> > -    echo the EDK2 BuildEnv script.
> > -    return 1
> > -  fi
> > -
> > -  #
> > -  # Set $WORKSPACE
> > -  #
> > -  export WORKSPACE=$PWD
> > -  return 0
> > -}
> > -
> > -SetupEnv()
> > -{
> > -  if [ -n "$EDK_TOOLS_PATH" ]
> > -  then
> > -    . $EDK_TOOLS_PATH/BuildEnv
> > -  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> > -  then
> > -    . $WORKSPACE/BaseTools/BuildEnv
> > -  elif [ -n "$PACKAGES_PATH" ]
> > -  then
> > -    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> > -    do
> > -      if [ -f "$DIR/BaseTools/BuildEnv" ]
> > -      then
> > -        export EDK_TOOLS_PATH=$DIR/BaseTools
> > -        . $DIR/BaseTools/BuildEnv
> > -        break
> > -      fi
> > -    done
> > -  else
> > -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > -    echo Please check that WORKSPACE or PACKAGES_PATH is not set
> incorrectly
> > -    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> > -    echo the EDK2 BuildEnv script.
> > -    return 1
> > -  fi
> > -}
> > -
> > -SetupPython3()
> > -{
> > -  export PYTHON_COMMAND=python3
> > -}
> > -
> > -SourceEnv()
> > -{
> > -  SetupPython3
> > -  SetWorkspace
> > -  SetupEnv
> > -}
> > -
> > -I=$#
> > -while [ $I -gt 0 ]
> > -do
> > -  case "$1" in
> > -    BaseTools)
> > -      # Ignore argument for backwards compatibility
> > -      shift
> > -    ;;
> > -    --reconfig)
> > -      RECONFIG=TRUE
> > -      shift
> > -    ;;
> > -    *)
> > -      HelpMsg
> > -      break
> > -    ;;
> > -  esac
> > -  I=$((I - 1))
> > -done
> > -
> > -if [ $I -gt 0 ]
> > -then
> > -  return 1
> > -fi
> > -
> > -SourceEnv
> > -
> > -unset SCRIPTNAME RECONFIG
> > -
> > -return $?
> > +#
> > +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +# In *inux environment, the build tools's source is required and need to be
> > compiled
> > +# firstly, please reference
> > https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-
> Github-
> > Quick-Start
> > +# to get how to setup build tool.
> > +#
> > +# Setup the environment for unix-like systems running a bash-like shell.
> > +# This file must be "sourced" not merely executed. For example: ".
> edksetup.sh"
> > +#
> > +# CYGWIN users: Your path and filename related environment variables
> should
> > be
> > +# set up in the unix style.  This script will make the necessary conversions to
> > +# windows style.
> > +#
> > +# Please reference edk2 user manual for more detail descriptions at
> > https://github.com/tianocore-
> > docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> > +#
> > +
> > +SCRIPTNAME="edksetup.sh"
> > +RECONFIG=FALSE
> > +
> > +HelpMsg()
> > +{
> > +  echo "Usage: $SCRIPTNAME [Options]"
> > +  echo
> > +  echo "The system environment variable, WORKSPACE, is always set to the
> > current"
> > +  echo "working directory."
> > +  echo
> > +  echo "Options: "
> > +  echo "  --help, -h, -?        Print this help screen and exit."
> > +  echo
> > +  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with
> the"
> > +  echo "                        template files from the BaseTools/Conf directory."
> > +  echo
> > +  echo Please note: This script must be \'sourced\' so the environment can be
> > changed.
> > +  echo ". $SCRIPTNAME"
> > +  echo "source $SCRIPTNAME"
> > +}
> > +
> > +SetWorkspace()
> > +{
> > +  #
> > +  # If WORKSPACE is already set, then we can return right now
> > +  #
> > +  export PYTHONHASHSEED=1
> > +  if [ -n "$WORKSPACE" ]
> > +  then
> > +    return 0
> > +  fi
> > +
> > +  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> > +  then
> > +    echo Source this script from the base of your tree.  For example:
> > +    echo "  cd /Path/To/Edk2/Clone"
> > +    echo "  . $SCRIPTNAME"
> > +    return 1
> > +  fi
> > +
> > +  #
> > +  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> > +  #
> > +  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> > +  then
> > +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > +    echo Please point EDK_TOOLS_PATH at the directory that contains
> > +    echo the EDK2 BuildEnv script.
> > +    return 1
> > +  fi
> > +
> > +  #
> > +  # Set $WORKSPACE
> > +  #
> > +  export WORKSPACE=$PWD
> > +  return 0
> > +}
> > +
> > +SetupEnv()
> > +{
> > +  if [ -n "$EDK_TOOLS_PATH" ]
> > +  then
> > +    . $EDK_TOOLS_PATH/BuildEnv
> > +  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> > +  then
> > +    . $WORKSPACE/BaseTools/BuildEnv
> > +  elif [ -n "$PACKAGES_PATH" ]
> > +  then
> > +    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> > +    do
> > +      if [ -f "$DIR/BaseTools/BuildEnv" ]
> > +      then
> > +        export EDK_TOOLS_PATH=$DIR/BaseTools
> > +        . $DIR/BaseTools/BuildEnv
> > +        break
> > +      fi
> > +    done
> > +  else
> > +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > +    echo Please check that WORKSPACE or PACKAGES_PATH is not set
> incorrectly
> > +    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> > +    echo the EDK2 BuildEnv script.
> > +    return 1
> > +  fi
> > +}
> > +
> > +SetupPython3()
> > +{
> > +  export PYTHON_COMMAND=python3
> > +}
> > +
> > +SourceEnv()
> > +{
> > +  SetupPython3
> > +  SetWorkspace
> > +  SetupEnv
> > +}
> > +
> > +I=$#
> > +while [ $I -gt 0 ]
> > +do
> > +  case "$1" in
> > +    BaseTools)
> > +      # Ignore argument for backwards compatibility
> > +      shift
> > +    ;;
> > +    --reconfig)
> > +      RECONFIG=TRUE
> > +      shift
> > +    ;;
> > +    *)
> > +      HelpMsg
> > +      break
> > +    ;;
> > +  esac
> > +  I=$((I - 1))
> > +done
> > +
> > +if [ $I -gt 0 ]
> > +then
> > +  return 1
> > +fi
> > +
> > +SourceEnv
> > +
> > +unset SCRIPTNAME RECONFIG
> > +
> > +return $?
> > --
> > 2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105859): https://edk2.groups.io/g/devel/message/105859
Mute This Topic: https://groups.io/mt/99079640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
Posted by Zhang, Hongbin1 10 months ago
Hi Ray,
  I have split to 5 patches with 5 commits in https://github.com/tianocore/edk2/pull/4375/ according to your suggestion.
  Please help to review it again.

Thanks,
Hongbin

-----Original Message-----
From: Zhang, Hongbin1 
Sent: Wednesday, June 7, 2023 10:37 AM
To: Yao, Jiewen <jiewen.yao@intel.com>; Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io
Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Supreeth Venkatesh <supreeth.venkatesh@arm.com>; Bu, Daocheng <daocheng.bu@intel.com>; Chen, Bo <bo.chen@intel.com>
Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.

Thanks Jiewen.
I will change this.

-----Original Message-----
From: Yao, Jiewen <jiewen.yao@intel.com> 
Sent: Wednesday, June 7, 2023 10:31 AM
To: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io
Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Supreeth Venkatesh <supreeth.venkatesh@arm.com>; Bu, Daocheng <daocheng.bu@intel.com>; Chen, Bo <bo.chen@intel.com>
Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.

> 5th patch register ReadyToBoot callback. But is it too late from security perspective? Why not lock after SMM core exit? @Yao, Jiewen

Agree with Ray. ReadyToBoot is too late.



> -----Original Message-----
> From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> Sent: Wednesday, June 7, 2023 10:29 AM
> To: Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io; Yao, Jiewen
> <jiewen.yao@intel.com>
> Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami
> Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Supreeth Venkatesh
> <supreeth.venkatesh@arm.com>; Bu, Daocheng <daocheng.bu@intel.com>;
> Chen, Bo <bo.chen@intel.com>
> Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Thanks Ray.
> Replied your code comments with [Hongbin].
> And I will split to several patches, it will be better for reviewing.
> 
> -----Original Message-----
> From: Ni, Ray <ray.ni@intel.com>
> Sent: Wednesday, June 7, 2023 10:04 AM
> To: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; devel@edk2.groups.io; Yao,
> Jiewen <jiewen.yao@intel.com>
> Cc: Zeng, Star <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami
> Mujawar <sami.mujawar@arm.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Supreeth Venkatesh
> <supreeth.venkatesh@arm.com>
> Subject: RE: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> 
> Hongbin,
> The patch is so big. Can you please split the patch to small patches? For example:
> 1st patch only implements the Ipl entrypoint to find the correct SMRAM range
> and dump it
> 2nd patch loads SMM CORE without mode switch if sizeof (UINTN) matches
> SMM core module type.
> 3rd patch loads SMM CORE with mode switch if sizeof (UINTN) == 4 but SMM
> core module type is 64bit.
> 4th patch Deadloop() when sizeof (UINTN) == 8 but SMM core module type is
> 32bit.
> 5th patch register ReadyToBoot callback. But is it too late from security
> perspective? Why not lock after SMM core exit? @Yao, Jiewen
> 
> Back to the code content, 3 comments:
> 1. Have you tested the flow when LoadImageAtFixedAddress is enabled? If no, I
> prefer you do not add the logic at all in the first version. We can enable that
> later.
>      -- Yes, currently PcdLoadModuleAtFixAddressEnable was not used and
> verified, I will add later [Hongbin].
> 2. "EFIAPI" for GetSectionFromAnyFvByFileType should be removed. And the
> function prototype could be refined as below:
>     EFI_STATUS
>     LocateMmFvAndCore
>       OUT EFI_PHYSICAL_ADDRESS  *MmFvBaseAddress,
>       OUT VOID                  **MmCoreImageAddress
>     Please avoid directly modifying global variables inside this function.
>      -- Ok, will change that [Hongbin].
> 3. Can the StandaloneMmCore in open source be directly used with this IPL?
>      -- I will think about this later [Hongbin].
> 
> Thanks,
> Ray
> 
> 
> > -----Original Message-----
> > From: Zhang, Hongbin1 <hongbin1.zhang@intel.com>
> > Sent: Monday, May 22, 2023 1:21 PM
> > To: devel@edk2.groups.io
> > Cc: Zhang, Hongbin1 <hongbin1.zhang@intel.com>; Yao, Jiewen
> > <jiewen.yao@intel.com>; Ni, Ray <ray.ni@intel.com>; Zeng, Star
> > <star.zeng@intel.com>; Wu, Jiaxin <jiaxin.wu@intel.com>; Sami Mujawar
> > <sami.mujawar@arm.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
> > Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> > Subject: [PATCH v1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
> >
> > Add StandaloneMmIplPei IA32/X64 driver at PEI stage.
> > FSP will use this driver to load Standalone MM code
> > to dispatch other Standalone MM drivers.
> >
> > Signed-off-by: Hongbin1 Zhang <hongbin1.zhang@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Ray Ni <ray.ni@intel.com>
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Jiaxin Wu <jiaxin.wu@intel.com>
> > Cc: Sami Mujawar <sami.mujawar@arm.com>
> > Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> > Cc: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
> > ---
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     |
> 456
> > ++++++++++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   |
> 787
> > ++++++++++++++++++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |
> 32 +
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  |
> 148
> > ++++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  66
> > ++
> >  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |
> 75
> > ++
> >  StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
> >  StandaloneMmPkg/StandaloneMmPkg.dsc                               |  15 +-
> >  UefiPayloadPkg/UniversalPayloadBuild.sh                           |  34 +-
> >  edksetup.sh                                                       | 294 ++++----
> >  10 files changed, 1744 insertions(+), 167 deletions(-)
> >
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > new file mode 100644
> > index 0000000000..d6174d73a3
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> > @@ -0,0 +1,456 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <StandaloneMm.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <StandaloneMmIplPei.h>
> > +
> > +#pragma pack(1)
> > +
> > +//
> > +// Page-Map Level-4 Offset (PML4) and
> > +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
> > +//
> > +
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Reserved             : 1;   // Reserved
> > +    UINT64    MustBeZero           : 2;   // Must Be Zero
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    PageTableBaseAddress : 40;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // No Execute bit
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_MAP_AND_DIRECTORY_POINTER;
> > +
> > +//
> > +// Page Table Entry 2MB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> > access to page
> > +    UINT64    MustBe1              : 1;   // Must be 1
> > +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB
> not
> > cleared on CR3 write
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    Pat                  : 1;   //
> > +    UINT64    MustBeZero           : 8;   // Must be zero
> > +    UINT64    PageTableBaseAddress : 31;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_ENTRY;
> > +
> > +//
> > +// Page Table Entry 1GB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64    Present              : 1;   // 0 = Not present in memory, 1 = Present in
> > memory
> > +    UINT64    ReadWrite            : 1;   // 0 = Read-Only, 1= Read/Write
> > +    UINT64    UserSupervisor       : 1;   // 0 = Supervisor, 1=User
> > +    UINT64    WriteThrough         : 1;   // 0 = Write-Back caching, 1=Write-
> Through
> > caching
> > +    UINT64    CacheDisabled        : 1;   // 0 = Cached, 1=Non-Cached
> > +    UINT64    Accessed             : 1;   // 0 = Not accessed, 1 = Accessed (set by
> CPU)
> > +    UINT64    Dirty                : 1;   // 0 = Not Dirty, 1 = written by processor on
> > access to page
> > +    UINT64    MustBe1              : 1;   // Must be 1
> > +    UINT64    Global               : 1;   // 0 = Not global page, 1 = global page TLB
> not
> > cleared on CR3 write
> > +    UINT64    Available            : 3;   // Available for use by system software
> > +    UINT64    Pat                  : 1;   //
> > +    UINT64    MustBeZero           : 17;  // Must be zero;
> > +    UINT64    PageTableBaseAddress : 22;  // Page Table Base Address
> > +    UINT64    AvailableHigh        : 11;  // Available for use by system software
> > +    UINT64    Nx                   : 1;   // 0 = Execute Code, 1 = No Code Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_1G_ENTRY;
> > +
> > +#pragma pack()
> > +
> > +//
> > +// Global Descriptor Table (GDT)
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED IA32_SEGMENT_DESCRIPTOR
> > mGdtEntries[] = {
> > +  /* selector { Global Segment Descriptor                              } */
> > +  /* 0x00 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // null descriptor
> > +  /* 0x08 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // linear data segment descriptor
> > +  /* 0x10 */ {
> > +    { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // linear code segment descriptor
> > +  /* 0x18 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system data segment descriptor
> > +  /* 0x20 */ {
> > +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system code segment descriptor
> > +  /* 0x28 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // spare segment descriptor
> > +  /* 0x30 */ {
> > +    { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
> > +  },                                                                      // system data segment descriptor
> > +  /* 0x38 */ {
> > +    { 0xffff, 0, 0, 0xb, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
> > +  },                                                                      // system code segment descriptor
> > +  /* 0x40 */ {
> > +    { 0,      0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0, 0 }
> > +  },                                                                      // spare segment descriptor
> > +};
> > +
> > +//
> > +// IA32 Gdt register
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR  mGdt = {
> > +  sizeof (mGdtEntries) - 1,
> > +  (UINTN)mGdtEntries
> > +};
> > +
> > +/**
> > +  Calculate the total size of page table.
> > +
> > +  @return The size of page table.
> > +
> > +**/
> > +UINTN
> > +CalculatePageTableSize (
> > +  VOID
> > +  )
> > +{
> > +  UINT32   RegEax;
> > +  UINT32   RegEdx;
> > +  UINTN    TotalPagesNum;
> > +  UINT8    PhysicalAddressBits;
> > +  VOID     *Hob;
> > +  UINT32   NumberOfPml4EntriesNeeded;
> > +  UINT32   NumberOfPdpEntriesNeeded;
> > +  BOOLEAN  Page1GSupport;
> > +
> > +  Page1GSupport = FALSE;
> > +  if (PcdGetBool (PcdUse1GPageTable)) {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000001) {
> > +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> > +      if ((RegEdx & BIT26) != 0) {
> > +        Page1GSupport = TRUE;
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8)RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +
> > +  //
> > +  // Calculate the table entries needed.
> > +  //
> > +  if (PhysicalAddressBits <= 39 ) {
> > +    NumberOfPml4EntriesNeeded = 1;
> > +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 30));
> > +  } else {
> > +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 39));
> > +    NumberOfPdpEntriesNeeded  = 512;
> > +  }
> > +
> > +  if (!Page1GSupport) {
> > +    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) *
> > NumberOfPml4EntriesNeeded + 1;
> > +  } else {
> > +    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
> > +  }
> > +
> > +  return EFI_PAGES_TO_SIZE (TotalPagesNum);
> > +}
> > +
> > +/**
> > +  Allocates and fills in the Page Directory and Page Table Entries to
> > +  establish a 1:1 Virtual to Physical mapping.
> > +
> > +  @param[in]  PageTablesAddress  The base address of page table.
> > +
> > +**/
> > +VOID
> > +CreateIdentityMappingPageTables (
> > +  IN  EFI_PHYSICAL_ADDRESS  PageTablesAddress
> > +  )
> > +{
> > +  UINT32                          RegEax;
> > +  UINT32                          RegEdx;
> > +  UINT8                           PhysicalAddressBits;
> > +  EFI_PHYSICAL_ADDRESS            PageAddress;
> > +  UINTN                           IndexOfPml4Entries;
> > +  UINTN                           IndexOfPdpEntries;
> > +  UINTN                           IndexOfPageDirectoryEntries;
> > +  UINT32                          NumberOfPml4EntriesNeeded;
> > +  UINT32                          NumberOfPdpEntriesNeeded;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMap;
> > +  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
> > +  PAGE_TABLE_ENTRY                *PageDirectoryEntry;
> > +  UINTN                           BigPageAddress;
> > +  VOID                            *Hob;
> > +  BOOLEAN                         Page1GSupport;
> > +  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
> > +
> > +  Page1GSupport = FALSE;
> > +  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +  if (RegEax >= 0x80000001) {
> > +    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> > +    if ((RegEdx & BIT26) != 0) {
> > +      Page1GSupport = TRUE;
> > +    }
> > +  }
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8)RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +
> > +  //
> > +  // Calculate the table entries needed.
> > +  //
> > +  if (PhysicalAddressBits <= 39 ) {
> > +    NumberOfPml4EntriesNeeded = 1;
> > +    NumberOfPdpEntriesNeeded  = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 30));
> > +  } else {
> > +    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits
> -
> > 39));
> > +    NumberOfPdpEntriesNeeded  = 512;
> > +  }
> > +
> > +  //
> > +  // Pre-allocate big pages to avoid later allocations.
> > +  //
> > +  BigPageAddress = (UINTN)PageTablesAddress;
> > +
> > +  //
> > +  // By architecture only one PageMapLevel4 exists - so lets allocate storage
> for
> > it.
> > +  //
> > +  PageMap         = (VOID *)BigPageAddress;
> > +  BigPageAddress += SIZE_4KB;
> > +
> > +  PageMapLevel4Entry = PageMap;
> > +  PageAddress        = 0;
> > +  for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> > NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++)
> {
> > +    //
> > +    // Each PML4 entry points to a page of Page Directory Pointer entires.
> > +    // So lets allocate space for them and fill them in in the IndexOfPdpEntries
> > loop.
> > +    //
> > +    PageDirectoryPointerEntry = (VOID *)BigPageAddress;
> > +    BigPageAddress           += SIZE_4KB;
> > +
> > +    //
> > +    // Make a PML4 Entry
> > +    //
> > +    PageMapLevel4Entry->Uint64         =
> > (UINT64)(UINTN)PageDirectoryPointerEntry;
> > +    PageMapLevel4Entry->Bits.ReadWrite = 1;
> > +    PageMapLevel4Entry->Bits.Present   = 1;
> > +
> > +    if (Page1GSupport) {
> > +      PageDirectory1GEntry = (VOID *)PageDirectoryPointerEntry;
> > +
> > +      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress +=
> > SIZE_1GB) {
> > +        //
> > +        // Fill in the Page Directory entries
> > +        //
> > +        PageDirectory1GEntry->Uint64         = (UINT64)PageAddress;
> > +        PageDirectory1GEntry->Bits.ReadWrite = 1;
> > +        PageDirectory1GEntry->Bits.Present   = 1;
> > +        PageDirectory1GEntry->Bits.MustBe1   = 1;
> > +      }
> > +    } else {
> > +      for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> > NumberOfPdpEntriesNeeded; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > +        //
> > +        // Each Directory Pointer entries points to a page of Page Directory
> entires.
> > +        // So allocate space for them and fill them in in the
> > IndexOfPageDirectoryEntries loop.
> > +        //
> > +        PageDirectoryEntry = (VOID *)BigPageAddress;
> > +        BigPageAddress    += SIZE_4KB;
> > +
> > +        //
> > +        // Fill in a Page Directory Pointer Entries
> > +        //
> > +        PageDirectoryPointerEntry->Uint64         =
> > (UINT64)(UINTN)PageDirectoryEntry;
> > +        PageDirectoryPointerEntry->Bits.ReadWrite = 1;
> > +        PageDirectoryPointerEntry->Bits.Present   = 1;
> > +
> > +        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress +=
> > SIZE_2MB) {
> > +          //
> > +          // Fill in the Page Directory entries
> > +          //
> > +          PageDirectoryEntry->Uint64         = (UINT64)PageAddress;
> > +          PageDirectoryEntry->Bits.ReadWrite = 1;
> > +          PageDirectoryEntry->Bits.Present   = 1;
> > +          PageDirectoryEntry->Bits.MustBe1   = 1;
> > +        }
> > +      }
> > +
> > +      for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > +        ZeroMem (
> > +          PageDirectoryPointerEntry,
> > +          sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> > +          );
> > +      }
> > +    }
> > +  }
> > +
> > +  //
> > +  // For the PML4 entries we are not using fill in a null entry.
> > +  //
> > +  for ( ; IndexOfPml4Entries < 512; IndexOfPml4Entries++,
> > PageMapLevel4Entry++) {
> > +    ZeroMem (
> > +      PageMapLevel4Entry,
> > +      sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
> > +      );
> > +  }
> > +}
> > +
> > +/**
> > +  If in 32 bit protection mode, and coalesce image is of X64, switch to long
> mode.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @param  Context2                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully switched to long mode and
> execute
> > coalesce.
> > +  @retval Others                    Failed to execute coalesce in long mode.
> > +
> > +**/
> > +EFI_STATUS
> > +ModeSwitch (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1,
> > +  IN VOID                  *Context2
> > +  )
> > +{
> > +  UINTN            PageTableAddress;
> > +  UINTN            PageTableSize;
> > +  EFI_STATUS       Status;
> > +  IA32_DESCRIPTOR  Gdtr;
> > +
> > +  DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
> > +
> > +  //
> > +  // Save IA32 GDTR
> > +  //
> > +  AsmReadGdtr (&Gdtr);
> > +
> > +  //
> > +  // Set X64 GDTR
> > +  //
> > +  AsmWriteGdtr (&mGdt);
> > +
> > +  PageTableAddress = AsmReadCr3 () & 0xFFFFF000;
> > +
> > +  //
> > +  // If page table was created, no need to create
> > +  //
> > +  if (PageTableAddress == 0) {
> > +    PageTableSize = CalculatePageTableSize ();
> > +
> > +    PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES
> > (PageTableSize));
> > +    ASSERT (PageTableAddress != 0);
> > +
> > +    CreateIdentityMappingPageTables (PageTableAddress);
> > +
> > +    AsmWriteCr3 ((UINTN)PageTableAddress);
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n"));
> > +
> > +  Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1,
> > (UINT64)(UINTN)Context2, NULL);
> > +  if (Status != 0) {
> > +    Status = Status | MAX_BIT;
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status));
> > +
> > +  //
> > +  // Restore IA32 GDTR
> > +  //
> > +  AsmWriteGdtr (&Gdtr);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  )
> > +{
> > +  return ModeSwitch (Entry, Context1, NULL);
> > +}
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > new file mode 100644
> > index 0000000000..7fa42c32fb
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> > @@ -0,0 +1,787 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM at PEI stage
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <Ppi/SmmAccess.h>
> > +#include <Ppi/SmmControl.h>
> > +#include <Library/BaseLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/PeCoffLib.h>
> > +#include <Library/CacheMaintenanceLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/PeiServicesTablePointerLib.h>
> > +#include <Library/PeiServicesLib.h>
> > +#include <Library/HobLib.h>
> > +#include <Library/PcdLib.h>
> > +#include <Guid/SmramMemoryReserve.h>
> > +#include <Guid/MmCoreData.h>
> > +#include <StandaloneMmIplPei.h>
> > +
> > +//
> > +// MM Core Private Data structure that contains the data shared between
> > +// the SMM IPL and the Standalone MM Core.
> > +//
> > +MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
> > +  MM_CORE_PRIVATE_DATA_SIGNATURE,     // Signature
> > +  0,                                  // MmramRangeCount
> > +  0,                                  // MmramRanges
> > +  0,                                  // MmEntryPoint
> > +  FALSE,                              // MmEntryPointRegistered
> > +  FALSE,                              // InMm
> > +  0,                                  // Mmst
> > +  0,                                  // CommunicationBuffer
> > +  0,                                  // BufferSize
> > +  EFI_SUCCESS,                        // ReturnStatus
> > +  0,                                  // MmCoreImageBase
> > +  0,                                  // MmCoreImageSize
> > +  0,                                  // MmCoreEntryPoint
> > +  0,                                  // StandaloneBfvAddress
> > +};
> > +
> > +//
> > +// Global pointer used to access mMmCorePrivateData from outside and
> inside
> > SMM
> > +//
> > +MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
> > +
> > +//
> > +// SMM IPL global variables
> > +//
> > +PEI_SMM_ACCESS_PPI    *mSmmAccess;
> > +EFI_SMRAM_DESCRIPTOR  *mCurrentSmramRange;
> > +BOOLEAN               mSmmLocked = FALSE;
> > +EFI_PHYSICAL_ADDRESS  mSmramCacheBase;
> > +UINT64                mSmramCacheSize;
> > +
> > +EFI_PEI_NOTIFY_DESCRIPTOR  mReadyToBootNotifyList = {
> > +  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> > +  &gEfiEventReadyToBootGuid,
> > +  ReadyToBootEvent
> > +};
> > +
> > +/**
> > +  This is the callback function on ready to boot.
> > +
> > +  Close and Lock smram range on ready to boot stage.
> > +
> > +  @param   PeiServices          General purpose services available to every PEIM.
> > +  @param   NotifyDescriptor     The notification structure this PEIM registered
> on
> > install.
> > +  @param   Ppi                  Pointer to the PPI data associated with this function.
> > +  @retval  EFI_SUCCESS          Close and lock smram ranges successfully.
> > +  @retval  Other                Close and lock smram ranges failed.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadyToBootEvent (
> > +  IN  EFI_PEI_SERVICES           **PeiServices,
> > +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> > +  IN  VOID                       *Ppi
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +
> > +  //
> > +  // Close all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Lock all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Lock ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Find the maximum SMRAM cache range that covers the range specified by
> > SmramRange.
> > +
> > +  This function searches and joins all adjacent ranges of SmramRange into a
> > range to be cached.
> > +
> > +  @param   SmramRange       The SMRAM range to search from.
> > +  @param   SmramCacheBase   The returned cache range base.
> > +  @param   SmramCacheSize   The returned cache range size.
> > +**/
> > +VOID
> > +GetSmramCacheRange (
> > +  IN  EFI_SMRAM_DESCRIPTOR  *SmramRange,
> > +  OUT EFI_PHYSICAL_ADDRESS  *SmramCacheBase,
> > +  OUT UINT64                *SmramCacheSize
> > +  )
> > +{
> > +  UINTN                 Index;
> > +  EFI_PHYSICAL_ADDRESS  RangeCpuStart;
> > +  UINT64                RangePhysicalSize;
> > +  BOOLEAN               FoundAdjacentRange;
> > +  EFI_SMRAM_DESCRIPTOR  *SmramRanges;
> > +
> > +  *SmramCacheBase = SmramRange->CpuStart;
> > +  *SmramCacheSize = SmramRange->PhysicalSize;
> > +
> > +  SmramRanges = (EFI_SMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +  do {
> > +    FoundAdjacentRange = FALSE;
> > +    for (Index = 0; Index < gMmCorePrivate->MmramRangeCount; Index++) {
> > +      RangeCpuStart     = SmramRanges[Index].CpuStart;
> > +      RangePhysicalSize = SmramRanges[Index].PhysicalSize;
> > +      if ((RangeCpuStart < *SmramCacheBase) && (*SmramCacheBase ==
> > (RangeCpuStart + RangePhysicalSize))) {
> > +        *SmramCacheBase    = RangeCpuStart;
> > +        *SmramCacheSize   += RangePhysicalSize;
> > +        FoundAdjacentRange = TRUE;
> > +      } else if (((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart) &&
> > (RangePhysicalSize > 0)) {
> > +        *SmramCacheSize   += RangePhysicalSize;
> > +        FoundAdjacentRange = TRUE;
> > +      }
> > +    }
> > +  } while (FoundAdjacentRange);
> > +}
> > +
> > +/**
> > +  Get the fixed loading address from image header assigned by build tool. This
> > function only be called
> > +  when Loading module at Fixed address feature enabled.
> > +
> > +  @param  ImageContext              Pointer to the image context structure that
> > describes the PE/COFF
> > +                                    image that needs to be examined by this function.
> > +  @retval EFI_SUCCESS               An fixed loading address is assigned to this
> image
> > by build tools .
> > +  @retval EFI_NOT_FOUND             The image has no assigned fixed loading
> > address.
> > +**/
> > +EFI_STATUS
> > +GetPeCoffImageFixLoadingAssignedAddress (
> > +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> > +  )
> > +{
> > +  UINTN                            SectionHeaderOffset;
> > +  EFI_STATUS                       Status;
> > +  EFI_IMAGE_SECTION_HEADER         SectionHeader;
> > +  EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
> > +  EFI_PHYSICAL_ADDRESS             FixLoadingAddress;
> > +  UINT16                           Index;
> > +  UINTN                            Size;
> > +  UINT16                           NumberOfSections;
> > +  EFI_PHYSICAL_ADDRESS             SmramBase;
> > +  UINT64                           SmmCodeSize;
> > +  UINT64                           ValueInSectionHeader;
> > +
> > +  //
> > +  // Build tool will calculate the smm code size and then patch the
> > PcdLoadFixAddressSmmCodePageNumber
> > +  //
> > +  SmmCodeSize       = EFI_PAGES_TO_SIZE (PcdGet32
> > (PcdLoadFixAddressSmmCodePageNumber));
> > +  FixLoadingAddress = 0;
> > +  Status            = EFI_NOT_FOUND;
> > +  SmramBase         = mCurrentSmramRange->CpuStart;
> > +  //
> > +  // Get PeHeader pointer
> > +  //
> > +  ImgHdr              = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8
> > *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
> > +  SectionHeaderOffset = (UINTN)(
> > +                                ImageContext->PeCoffHeaderOffset +
> > +                                sizeof (UINT32) +
> > +                                sizeof (EFI_IMAGE_FILE_HEADER) +
> > +                                ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
> > +                                );
> > +  NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
> > +
> > +  //
> > +  // Get base address from the first section header that doesn't point to code
> > section.
> > +  //
> > +  for (Index = 0; Index < NumberOfSections; Index++) {
> > +    //
> > +    // Read section header from file
> > +    //
> > +    Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
> > +    Status = ImageContext->ImageRead (
> > +                             ImageContext->Handle,
> > +                             SectionHeaderOffset,
> > +                             &Size,
> > +                             &SectionHeader
> > +                             );
> > +    if (EFI_ERROR (Status)) {
> > +      return Status;
> > +    }
> > +
> > +    Status = EFI_NOT_FOUND;
> > +
> > +    if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
> > +      //
> > +      // Build tool saves the offset to SMRAM base as image base in
> > PointerToRelocations & PointerToLineNumbers fields in the
> > +      // first section header that doesn't point to code section in image header.
> > And there is an assumption that when the
> > +      // feature is enabled, if a module is assigned a loading address by tools,
> > PointerToRelocations & PointerToLineNumbers
> > +      // fields should NOT be Zero, or else, these 2 fields should be set to Zero
> > +      //
> > +      ValueInSectionHeader = ReadUnaligned64 ((UINT64
> > *)&SectionHeader.PointerToRelocations);
> > +      if (ValueInSectionHeader != 0) {
> > +        //
> > +        // Found first section header that doesn't point to code section in which
> > build tool saves the
> > +        // offset to SMRAM base as image base in PointerToRelocations &
> > PointerToLineNumbers fields
> > +        //
> > +        FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase +
> > (INT64)ValueInSectionHeader);
> > +
> > +        if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <=
> > FixLoadingAddress)) {
> > +          //
> > +          // The assigned address is valid. Return the specified loading address
> > +          //
> > +          ImageContext->ImageAddress = FixLoadingAddress;
> > +          Status                     = EFI_SUCCESS;
> > +        }
> > +      }
> > +
> > +      break;
> > +    }
> > +
> > +    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO:
> > Loading module at fixed address %x, Status = %r \n", FixLoadingAddress,
> Status));
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Searches all the available firmware volumes and returns the first matching
> FFS
> > section.
> > +
> > +  This function searches all the firmware volumes for FFS files with FV file type
> > specified by FileType
> > +  The order that the firmware volumes is searched is not deterministic. For
> each
> > available FV a search
> > +  is made for FFS file of type FileType. If the FV contains more than one FFS
> file
> > with the same FileType,
> > +  the FileInstance instance will be the matched FFS file. For each FFS file found
> a
> > search
> > +  is made for FFS sections of type SectionType. If the FFS file contains at least
> > SectionInstance instances
> > +  of the FFS section specified by SectionType, then the SectionInstance
> instance
> > is returned in Buffer.
> > +  Buffer is allocated using AllocatePool(), and the size of the allocated buffer
> is
> > returned in Size.
> > +  It is the caller's responsibility to use FreePool() to free the allocated buffer.
> > +
> > +  If Buffer is NULL, then ASSERT().
> > +  If Size is NULL, then ASSERT().
> > +
> > +  @param  FileType             Indicates the FV file type to search for within all
> > available FVs.
> > +  @param  FileInstance         Indicates which file instance within all available
> FVs
> > specified by FileType.
> > +                               FileInstance starts from zero.
> > +  @param  SectionType          Indicates the FFS section type to search for
> within
> > the FFS file
> > +                               specified by FileType with FileInstance.
> > +  @param  SectionInstance      Indicates which section instance within the FFS
> > file
> > +                               specified by FileType with FileInstance to retrieve.
> > SectionInstance starts from zero.
> > +  @param  Buffer               On output, a pointer to a callee allocated buffer
> > containing the FFS file section that was found.
> > +                               Is it the caller's responsibility to free this buffer using
> > FreePool().
> > +  @param  Size                 On output, a pointer to the size, in bytes, of Buffer.
> > +
> > +  @retval  EFI_SUCCESS          The specified FFS section was returned.
> > +  @retval  EFI_NOT_FOUND        The specified FFS section could not be found.
> > +  @retval  EFI_OUT_OF_RESOURCES There are not enough resources
> available
> > to retrieve the matching FFS section.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +GetSectionFromAnyFvByFileType  (
> > +  IN  EFI_FV_FILETYPE   FileType,
> > +  IN  UINTN             FileInstance,
> > +  IN  EFI_SECTION_TYPE  SectionType,
> > +  IN  UINTN             SectionInstance,
> > +  OUT VOID              **Buffer,
> > +  OUT UINTN             *Size
> > +  )
> > +{
> > +  EFI_STATUS           Status;
> > +  UINTN                FvIndex;
> > +  EFI_PEI_FV_HANDLE    VolumeHandle;
> > +  EFI_PEI_FILE_HANDLE  FileHandle;
> > +  EFI_PE32_SECTION     *SectionData;
> > +  UINT32               SectionSize;
> > +
> > +  //
> > +  // Search all FV
> > +  //
> > +  VolumeHandle = NULL;
> > +  for (FvIndex = 0; ; FvIndex++) {
> > +    Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
> > +    if (EFI_ERROR (Status)) {
> > +      break;
> > +    }
> > +
> > +    //
> > +    // Search PEIM FFS
> > +    //
> > +    FileHandle = NULL;
> > +    Status     = PeiServicesFfsFindNextFile (FileType, VolumeHandle,
> &FileHandle);
> > +    if (EFI_ERROR (Status)) {
> > +      continue;
> > +    }
> > +
> > +    //
> > +    // Search Section
> > +    //
> > +    SectionData = NULL;
> > +    Status      = PeiServicesFfsFindSectionData (SectionType, FileHandle, Buffer);
> > +    if (EFI_ERROR (Status)) {
> > +      continue;
> > +    }
> > +
> > +    //
> > +    // Great!
> > +    //
> > +    SectionData = (EFI_PE32_SECTION *)((UINT8 *)*Buffer - sizeof
> > (EFI_PE32_SECTION));
> > +    ASSERT (SectionData->Type == SectionType);
> > +    SectionSize  = *(UINT32 *)SectionData->Size;
> > +    SectionSize &= 0xFFFFFF;
> > +    *Size        = SectionSize - sizeof (EFI_PE32_SECTION);
> > +
> > +    if (FileType == EFI_FV_FILETYPE_MM_CORE_STANDALONE) {
> > +      EFI_FV_INFO  VolumeInfo;
> > +      //
> > +      // This is SMM BFV
> > +      //
> > +      Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
> > +      if (!EFI_ERROR (Status)) {
> > +        gMmCorePrivate->StandaloneBfvAddress =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
> > +      }
> > +    }
> > +
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > +  Load the SMM Core image into SMRAM and executes the SMM Core from
> > SMRAM.
> > +
> > +  @param[in, out] SmramRange            Descriptor for the range of SMRAM to
> > reload the
> > +                                        currently executing image, the rang of SMRAM to
> > +                                        hold SMM Core will be excluded.
> > +  @param[in, out] SmramRangeSmmCore     Descriptor for the range of
> SMRAM
> > to hold SMM Core.
> > +
> > +  @param[in]      Context               Context to pass into SMM Core
> > +
> > +  @return  EFI_STATUS
> > +
> > +**/
> > +EFI_STATUS
> > +ExecuteSmmCoreFromSmram (
> > +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRange,
> > +  IN OUT EFI_SMRAM_DESCRIPTOR  *SmramRangeSmmCore,
> > +  IN     VOID                  *Context
> > +  )
> > +{
> > +  EFI_STATUS                    Status;
> > +  VOID                          *SourceBuffer;
> > +  UINTN                         SourceSize;
> > +  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
> > +  UINTN                         PageCount;
> > +  VOID                          *HobList;
> > +
> > +  Status = PeiServicesGetHobList (&HobList);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Search all Firmware Volumes for a PE/COFF image in a file of type
> > SMM_CORE
> > +  //
> > +  Status = GetSectionFromAnyFvByFileType (
> > +             EFI_FV_FILETYPE_MM_CORE_STANDALONE,
> > +             0,
> > +             EFI_SECTION_PE32,
> > +             0,
> > +             &SourceBuffer,
> > +             &SourceSize
> > +             );
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // Initialize ImageContext
> > +  //
> > +  ImageContext.Handle    = SourceBuffer;
> > +  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
> > +
> > +  //
> > +  // Get information about the image being loaded
> > +  //
> > +  Status = PeCoffLoaderGetImageInfo (&ImageContext);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // if Loading module at Fixed Address feature is enabled, the SMM core
> driver
> > will be loaded to
> > +  // the address assigned by build tool.
> > +  //
> > +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +    //
> > +    // Get the fixed loading address assigned by Build tool
> > +    //
> > +    Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
> > +    if (!EFI_ERROR (Status)) {
> > +      //
> > +      // Since the memory range to load SMM CORE will be cut out in SMM core,
> > so no need to allocate and free this range
> > +      //
> > +      PageCount = 0;
> > +      //
> > +      // Reserved Smram Region for SmmCore is not used, and remove it from
> > SmramRangeCount.
> > +      //
> > +      gMmCorePrivate->MmramRangeCount--;
> > +    } else {
> > +      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR: Loading
> module
> > at fixed address at address failed\n"));
> > +      //
> > +      // Allocate memory for the image being loaded from the
> > EFI_SRAM_DESCRIPTOR
> > +      // specified by SmramRange
> > +      //
> > +      PageCount = (UINTN)EFI_SIZE_TO_PAGES
> ((UINTN)ImageContext.ImageSize
> > + ImageContext.SectionAlignment);
> > +
> > +      ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> > +      ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> > +
> > +      SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> > +      SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> > SmramRange->PhysicalSize;
> > +      SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> > SmramRange->PhysicalSize;
> > +      SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> > EFI_ALLOCATED;
> > +      SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> > +
> > +      //
> > +      // Align buffer on section boundary
> > +      //
> > +      ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> > +    }
> > +  } else {
> > +    //
> > +    // Allocate memory for the image being loaded from the
> > EFI_SRAM_DESCRIPTOR
> > +    // specified by SmramRange
> > +    //
> > +    PageCount = (UINTN)EFI_SIZE_TO_PAGES
> ((UINTN)ImageContext.ImageSize +
> > ImageContext.SectionAlignment);
> > +
> > +    ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
> > +    ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
> > +
> > +    SmramRange->PhysicalSize        -= EFI_PAGES_TO_SIZE (PageCount);
> > +    SmramRangeSmmCore->CpuStart      = SmramRange->CpuStart +
> > SmramRange->PhysicalSize;
> > +    SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart +
> > SmramRange->PhysicalSize;
> > +    SmramRangeSmmCore->RegionState   = SmramRange->RegionState |
> > EFI_ALLOCATED;
> > +    SmramRangeSmmCore->PhysicalSize  = EFI_PAGES_TO_SIZE (PageCount);
> > +
> > +    //
> > +    // Align buffer on section boundary
> > +    //
> > +    ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
> > +  }
> > +
> > +  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
> > +  ImageContext.ImageAddress &=
> > ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
> > +
> > +  //
> > +  // Print debug message showing SMM Core load address.
> > +  //
> > +  DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM
> > address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
> > +
> > +  //
> > +  // Load the image to our new buffer
> > +  //
> > +  Status = PeCoffLoaderLoadImage (&ImageContext);
> > +  if (!EFI_ERROR (Status)) {
> > +    //
> > +    // Relocate the image in our new buffer
> > +    //
> > +    Status = PeCoffLoaderRelocateImage (&ImageContext);
> > +    if (!EFI_ERROR (Status)) {
> > +      //
> > +      // Flush the instruction cache so the image data are written before we
> > execute it
> > +      //
> > +      InvalidateInstructionCacheRange ((VOID
> > *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
> > +
> > +      //
> > +      // Print debug message showing SMM Core entry point address.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM
> > address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
> > +
> > +      gMmCorePrivate->MmCoreImageBase = ImageContext.ImageAddress;
> > +      gMmCorePrivate->MmCoreImageSize = ImageContext.ImageSize;
> > +      DEBUG ((DEBUG_INFO, "SmmCoreImageBase - 0x%016lx\n",
> > gMmCorePrivate->MmCoreImageBase));
> > +      DEBUG ((DEBUG_INFO, "SmmCoreImageSize - 0x%016lx\n",
> > gMmCorePrivate->MmCoreImageSize));
> > +
> > +      gMmCorePrivate->MmCoreEntryPoint = ImageContext.EntryPoint;
> > +
> > +      //
> > +      // Print debug message showing Standalone MM Core entry point address.
> > +      //
> > +      DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM
> > address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
> > +
> > +      //
> > +      // Execute image
> > +      //
> > +      LoadSmmCore (ImageContext.EntryPoint, HobList);
> > +    }
> > +  }
> > +
> > +  //
> > +  // If the load operation, relocate operation, or the image execution return
> an
> > +  // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR
> > specified by
> > +  // SmramRange
> > +  //
> > +  if (EFI_ERROR (Status)) {
> > +    SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
> > +  }
> > +
> > +  //
> > +  // Always free memory allocated by GetFileBufferByFilePath ()
> > +  //
> > +  FreePool (SourceBuffer);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Get full SMRAM ranges.
> > +
> > +  It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved
> > ranges from
> > +  SmmConfiguration protocol, split the entries if there is overlap between
> them.
> > +  It will also reserve one entry for SMM core.
> > +
> > +  @param[in]  PeiServices           Describes the list of possible PEI Services.
> > +  @param[out] FullSmramRangeCount   Output pointer to full SMRAM range
> > count.
> > +
> > +  @return Pointer to full SMRAM ranges.
> > +
> > +**/
> > +EFI_SMRAM_DESCRIPTOR *
> > +GetFullSmramRanges (
> > +  IN  CONST EFI_PEI_SERVICES  **PeiServices,
> > +  OUT       UINTN             *FullSmramRangeCount
> > +  )
> > +{
> > +  EFI_STATUS            Status;
> > +  UINTN                 Size;
> > +  EFI_SMRAM_DESCRIPTOR  *FullSmramRanges;
> > +  UINTN                 AdditionSmramRangeCount;
> > +  UINTN                 SmramRangeCount;
> > +
> > +  //
> > +  // Get SMRAM information.
> > +  //
> > +  Size   = 0;
> > +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, &Size, NULL);
> > +  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
> > +
> > +  SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
> > +
> > +  //
> > +  // Reserve one entry SMM Core in the full SMRAM ranges.
> > +  //
> > +  AdditionSmramRangeCount = 1;
> > +  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +    //
> > +    // Reserve two entries for all SMM drivers & SMM Core in the full SMRAM
> > ranges.
> > +    //
> > +    AdditionSmramRangeCount = 2;
> > +  }
> > +
> > +  *FullSmramRangeCount = SmramRangeCount + AdditionSmramRangeCount;
> > +  Size                 = (*FullSmramRangeCount) * sizeof
> (EFI_SMRAM_DESCRIPTOR);
> > +  FullSmramRanges      = (EFI_SMRAM_DESCRIPTOR *)AllocateZeroPool (Size);
> > +  ASSERT (FullSmramRanges != NULL);
> > +  if (FullSmramRanges == NULL) {
> > +    return NULL;
> > +  }
> > +
> > +  Status = mSmmAccess->GetCapabilities ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, &Size, FullSmramRanges);
> > +
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return FullSmramRanges;
> > +}
> > +
> > +/**
> > +  The Entry Point for SMM IPL
> > +
> > +  Load SMM Core into SMRAM.
> > +
> > +  @param  FileHandle  Handle of the file being invoked.
> > +  @param  PeiServices Describes the list of possible PEI Services.
> > +
> > +  @retval EFI_SUCCESS    The entry point is executed successfully.
> > +  @retval Other          Some error occurred when executing this entry point.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmIplEntry (
> > +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> > +  IN CONST EFI_PEI_SERVICES     **PeiServices
> > +  )
> > +{
> > +  EFI_STATUS             Status;
> > +  UINTN                  Index;
> > +  UINT64                 MaxSize;
> > +  UINT64                 SmmCodeSize;
> > +  MM_CORE_DATA_HOB_DATA  SmmCoreDataHobData;
> > +  EFI_SMRAM_DESCRIPTOR   *MmramRanges;
> > +  EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmDriver;
> > +
> > +  //
> > +  // Build Hob for SMM and DXE phase
> > +  //
> > +  SmmCoreDataHobData.Address =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES
> > (sizeof (mMmCorePrivateData)));
> > +  ASSERT (SmmCoreDataHobData.Address != 0);
> > +  gMmCorePrivate = (VOID *)(UINTN)SmmCoreDataHobData.Address;
> > +  CopyMem ((VOID *)(UINTN)SmmCoreDataHobData.Address,
> > &mMmCorePrivateData, sizeof (mMmCorePrivateData));
> > +  DEBUG ((DEBUG_INFO, "gMmCorePrivate - 0x%x\n", gMmCorePrivate));
> > +
> > +  BuildGuidDataHob (
> > +    &gMmCoreDataHobGuid,
> > +    (VOID *)&SmmCoreDataHobData,
> > +    sizeof (SmmCoreDataHobData)
> > +    );
> > +
> > +  //
> > +  // Get SMM Access Protocol
> > +  //
> > +  Status = PeiServicesLocatePpi (&gPeiSmmAccessPpiGuid, 0, NULL, (VOID
> > **)&mSmmAccess);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Get SMRAM information
> > +  //
> > +  gMmCorePrivate->MmramRanges =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)GetFullSmramRanges (PeiServices, (UINTN
> > *)&gMmCorePrivate->MmramRangeCount);
> > +  ASSERT (gMmCorePrivate->MmramRanges != 0);
> > +  if (gMmCorePrivate->MmramRanges == 0) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  //
> > +  // Open all SMRAM ranges
> > +  //
> > +  Status = mSmmAccess->Open ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  //
> > +  // Print debug message that the SMRAM window is now open.
> > +  //
> > +  DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
> > +
> > +  //
> > +  // Find the largest SMRAM range between 1MB and 4GB that is at least
> 256KB
> > - 4K in size
> > +  //
> > +  mCurrentSmramRange = NULL;
> > +  MmramRanges        = (EFI_MMRAM_DESCRIPTOR
> *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +  if (MmramRanges == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "Fail to retrieve MmramRanges\n"));
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index <
> > gMmCorePrivate->MmramRangeCount; Index++) {
> > +    //
> > +    // Skip any SMRAM region that is already allocated, needs testing, or needs
> > ECC initialization
> > +    //
> > +    if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED |
> > EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
> > +      continue;
> > +    }
> > +
> > +    if (MmramRanges[Index].CpuStart >= BASE_1MB) {
> > +      if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize)
> <=
> > BASE_4GB) {
> > +        if (MmramRanges[Index].PhysicalSize >= MaxSize) {
> > +          MaxSize            = MmramRanges[Index].PhysicalSize;
> > +          mCurrentSmramRange = &MmramRanges[Index];
> > +        }
> > +      }
> > +    }
> > +  }
> > +
> > +  if (mCurrentSmramRange != NULL) {
> > +    //
> > +    // Print debug message showing SMRAM window that will be used by SMM
> > IPL and SMM Core
> > +    //
> > +    DEBUG ((
> > +      DEBUG_INFO,
> > +      "SMM IPL found SMRAM window %p - %p\n",
> > +      (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
> > +      (VOID *)(UINTN)(mCurrentSmramRange->CpuStart +
> > mCurrentSmramRange->PhysicalSize - 1)
> > +      ));
> > +
> > +    GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase,
> > &mSmramCacheSize);
> > +
> > +    //
> > +    // if Loading module at Fixed Address feature is enabled, save the SMRAM
> > base to Load
> > +    // Modules At Fixed Address Configuration Table.
> > +    //
> > +    if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
> > +      //
> > +      // Build tool will calculate the smm code size and then patch the
> > PcdLoadFixAddressSmmCodePageNumber
> > +      //
> > +      SmmCodeSize = LShiftU64 (PcdGet32
> > (PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
> > +      //
> > +      // The SMRAM available memory is assumed to be larger than
> SmmCodeSize
> > +      //
> > +      ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
> > +      //
> > +      // Fill the Smram range for all SMM code
> > +      //
> > +      MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges;
> > +      //
> > +      // Note: SmramRanges specific for all SMM code will put in the
> > gMmCorePrivate->MmramRangeCount - 2.
> > +      //
> > +      SmramRangeSmmDriver                = &MmramRanges[gMmCorePrivate-
> > >MmramRangeCount - 2];
> > +      SmramRangeSmmDriver->CpuStart      = mCurrentSmramRange->CpuStart;
> > +      SmramRangeSmmDriver->PhysicalStart = mCurrentSmramRange-
> > >PhysicalStart;
> > +      SmramRangeSmmDriver->RegionState   = mCurrentSmramRange-
> > >RegionState | EFI_ALLOCATED;
> > +      SmramRangeSmmDriver->PhysicalSize  = SmmCodeSize;
> > +
> > +      mCurrentSmramRange->PhysicalSize -= SmmCodeSize;
> > +      mCurrentSmramRange->CpuStart      = mCurrentSmramRange->CpuStart +
> > SmmCodeSize;
> > +      mCurrentSmramRange->PhysicalStart = mCurrentSmramRange-
> > >PhysicalStart + SmmCodeSize;
> > +    }
> > +
> > +    //
> > +    // Load SMM Core into SMRAM and execute it from SMRAM
> > +    // Note: SmramRanges specific for SMM Core will put in the
> gMmCorePrivate-
> > >MmramRangeCount - 1.
> > +    //
> > +    Status = ExecuteSmmCoreFromSmram (
> > +               mCurrentSmramRange,
> > +               &(((EFI_MMRAM_DESCRIPTOR *)(UINTN)gMmCorePrivate-
> > >MmramRanges)[gMmCorePrivate->MmramRangeCount - 1]),
> > +               gMmCorePrivate
> > +               );
> > +    if (EFI_ERROR (Status)) {
> > +      //
> > +      // Print error message that the SMM Core failed to be loaded and
> executed.
> > +      //
> > +      DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM
> Core
> > from SMRAM\n"));
> > +    }
> > +  } else {
> > +    //
> > +    // Print error message that there are not enough SMRAM resources to load
> > the SMM Core.
> > +    //
> > +    DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM
> > region to load SMM Core\n"));
> > +  }
> > +
> > +  //
> > +  // If the SMM Core could not be loaded then close SMRAM window, free
> > allocated
> > +  // resources, and return an error so SMM IPL will be unloaded.
> > +  //
> > +  if ((mCurrentSmramRange == NULL) || EFI_ERROR (Status)) {
> > +    //
> > +    // Close all SMRAM ranges
> > +    //
> > +    Status = mSmmAccess->Close ((EFI_PEI_SERVICES **)PeiServices,
> > mSmmAccess, 0);
> > +    ASSERT_EFI_ERROR (Status);
> > +
> > +    //
> > +    // Print debug message that the SMRAM window is now closed.
> > +    //
> > +    DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
> > +
> > +    //
> > +    // Free all allocated resources
> > +    //
> > +    FreePool ((VOID *)(UINTN)gMmCorePrivate->MmramRanges);
> > +
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  //
> > +  // Create ready to boot for close and lock smram ranges
> > +  //
> > +  Status = PeiServicesNotifyPpi (&mReadyToBootNotifyList);
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git
> a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > new file mode 100644
> > index 0000000000..6d3497f2ea
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
> > @@ -0,0 +1,32 @@
> > +/** @file
> > +  SMM IPL that load the SMM Core into SMRAM
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include <PiPei.h>
> > +#include <PiSmm.h>
> > +#include <StandaloneMm.h>
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  )
> > +{
> > +  STANDALONE_MM_FOUNDATION_ENTRY_POINT  EntryPoint;
> > +
> > +  EntryPoint =
> (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
> > +  return EntryPoint (Context1);
> > +}
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > new file mode 100644
> > index 0000000000..7f887eb77d
> > --- /dev/null
> > +++
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> > @@ -0,0 +1,148 @@
> > +;------------------------------------------------------------------------------
> > +;
> > +; Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +; SPDX-License-Identifier: BSD-2-Clause-Patent
> > +;
> > +; Module Name:
> > +;
> > +;    Thunk32To64.nasm
> > +;
> > +; Abstract:
> > +;
> > +;   This is the assembly code to transition from long mode to compatibility
> > +;   mode to execute 32-bit code and then transit back to long mode.
> > +;
> > +;------------------------------------------------------------------------------
> > +
> > +    SECTION .text
> > +
> > +;------------------------------------------------------------------------------
> > +; Procedure:    AsmExecute64BitCode
> > +;
> > +; Input:        None
> > +;
> > +; Output:       None
> > +;
> > +; Prototype:    UINT32
> > +;               AsmExecute64BitCode (
> > +;                 IN UINT64           Function,
> > +;                 IN UINT64           Param1,
> > +;                 IN UINT64           Param2,
> > +;                 IN IA32_DESCRIPTOR  *InternalGdtr
> > +;                 );
> > +;
> > +;
> > +; Description:  A thunk function to execute 32-bit code in long mode.
> > +;
> > +;------------------------------------------------------------------------------
> > +global ASM_PFX(AsmExecute64BitCode)
> > +ASM_PFX(AsmExecute64BitCode):
> > +;
> > +; +---------+
> > +; | EIP(64) |
> > +; +---------+
> > +; | CS (64) |
> > +; +---------+
> > +; | EIP(32) |
> > +; +---------+
> > +; | CS (32) |<-ESP (16 bytes aligned)
> > +; +---------+
> > +; | ...     |
> > +; +---------+
> > +; | ebx     |<-EBP
> > +; +---------+
> > +; | ebp     |<-EBP + 4
> > +; +---------+
> > +; | esi     |<-EBP + 8
> > +; +---------+
> > +; | edi     |<-EBP + 12
> > +; +---------+
> > +; | RFlags  |<-EBP + 16
> > +; +---------+
> > +; | RetAddr |<-EBP (org)
> > +; +---------+
> > +; | Func    |<-EBP + 24
> > +; | Func    |
> > +; +---------+
> > +; | Param1  |<-EBP + 32
> > +; | Param1  |
> > +; +---------+
> > +; | Param2  |<-EBP + 40
> > +; | Param2  |
> > +; +---------+
> > +; | Gdtr    |
> > +; +---------+
> > +;
> > +    ;
> > +    ; Save general purpose register and RFlags register
> > +    ;
> > +    pushfd
> > +    push    edi
> > +    push    esi
> > +    push    ebp
> > +    push    ebx
> > +    mov     ebp, esp
> > +
> > +    and     esp, 0FFFFFFF0h
> > +
> > +    push    010h                        ; protected mode selector on stack
> > +    mov     eax, Compatible             ; offset for LongMode
> > +    push    eax                         ; offset on stack
> > +
> > +    push    038h                        ; long mode selector on stack
> > +    mov     eax, LongMode               ; offset for LongMode
> > +    push    eax                         ; offset on stack
> > +
> > +    mov     eax, cr4
> > +    or      al, 020h
> > +    mov     cr4, eax                    ; enable PAE
> > +    mov     ecx, 0c0000080h
> > +    rdmsr
> > +    or      ah, 1                       ; set LME
> > +    wrmsr
> > +    mov     eax, cr0
> > +    bts     eax, 31                     ; set PG
> > +    mov     cr0, eax                    ; enable paging
> > +    retf                                ; topmost 2 dwords hold the address
> > +LongMode:                               ; long mode starts here
> > +
> > +    ; Call long mode function
> > +    DB      67h, 48h                    ; 32-bit address size, 64-bit operand size
> > +    mov     eax, [ebp + 24]             ; mov rbx, [ebp + 24]
> > +    DB      67h, 48h
> > +    mov     ecx, [ebp + 24 + 8]         ; mov rcx, [ebp + 24 + 8]
> > +    DB      67h, 48h
> > +    mov     edx, [ebp + 24 + 16]        ; mov rdx, [ebp + 24 + 16]
> > +
> > +    DB      48h
> > +    add     esp, -20h                   ; add rsp, -20h
> > +    call    eax                         ; call rax
> > +    DB      48h
> > +    add     esp, 20h                    ; add rsp, 20h
> > +
> > +    ; after long mode function call
> > +    mov     ebx, eax
> > +
> > +    retf
> > +Compatible:
> > +    mov     ecx, cr0
> > +    btc     ecx, 31                     ; clear PG
> > +    mov     cr0, ecx                    ; disable paging
> > +    mov     ecx, 0C0000080h
> > +    rdmsr
> > +    btc     eax, 8                      ; clear LME
> > +    wrmsr
> > +
> > +    ;
> > +    ; Restore C register and eax hold the return status from 32-bit function.
> > +    ; Note: Do not touch rax from now which hold the return value from IA32
> > function
> > +    ;
> > +    mov     eax, ebx                    ; put return status to EAX
> > +    mov     esp, ebp                    ; restore stack pointer
> > +    pop     ebx
> > +    pop     ebp
> > +    pop     esi
> > +    pop     edi
> > +    popfd
> > +
> > +    ret
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > new file mode 100644
> > index 0000000000..be0aae70f0
> > --- /dev/null
> > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
> > @@ -0,0 +1,66 @@
> > +/** @file
> > +  Private header with declarations and definitions specific to the Standalone
> > +  MM IPL PEI driver
> > +
> > +  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef STANDALONE_MM_IPL_PEI_H_
> > +#define STANDALONE_MM_IPL_PEI_H_
> > +
> > +/**
> > +  Load SMM core to dispatch other Standalone MM drivers.
> > +
> > +  @param  Entry                     Entry of Standalone MM Foundation.
> > +  @param  Context1                  A pointer to the context to pass into the
> > EntryPoint
> > +                                    function.
> > +  @retval EFI_SUCCESS               Successfully loaded SMM core.
> > +  @retval Others                    Failed to load SMM core.
> > +**/
> > +EFI_STATUS
> > +LoadSmmCore (
> > +  IN EFI_PHYSICAL_ADDRESS  Entry,
> > +  IN VOID                  *Context1
> > +  );
> > +
> > +/**
> > +  Assembly function to transition from long mode to compatibility mode to
> > +  execute 32-bit code and then transit back to long mode.
> > +
> > +  @param[in] Function     The 32bit code entry to be executed.
> > +  @param[in] Param1       The first parameter to pass to 32bit code
> > +  @param[in] Param2       The second parameter to pass to 32bit code
> > +  @param[in] InternalGdtr The GDT and GDT descriptor used by this library
> > +
> > +  @retval status.
> > +**/
> > +UINT32
> > +AsmExecute64BitCode (
> > +  IN UINT64           Function,
> > +  IN UINT64           Param1,
> > +  IN UINT64           Param2,
> > +  IN IA32_DESCRIPTOR  *InternalGdtr
> > +  );
> > +
> > +/**
> > +  This is the callback function on ready to boot.
> > +
> > +  Close and lock smram ranges on ready to boot stage.
> > +
> > +  @param   PeiServices       General purpose services available to every PEIM.
> > +  @param   NotifyDescriptor  The notification structure this PEIM registered
> on
> > install.
> > +  @param   Ppi               Pointer to the PPI data associated with this function.
> > +  @retval  EFI_SUCCESS       Close and lock smram ranges successfully.
> > +  @retval  Other             Close and lock smram ranges failed.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +ReadyToBootEvent (
> > +  IN  EFI_PEI_SERVICES           **PeiServices,
> > +  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
> > +  IN  VOID                       *Ppi
> > +  );
> > +
> > +#endif
> > diff --git
> > a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > new file mode 100644
> > index 0000000000..ff4c67a92c
> > --- /dev/null
> > +++
> b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > @@ -0,0 +1,75 @@
> > +## @file
> > +#  This module provide a Standalone SMM compliant implementation of SMM
> > IPL PEIM.
> > +#
> > +#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x00010005
> > +  BASE_NAME                      = StandaloneMmIplPei
> > +  FILE_GUID                      = 578A0D17-2DC0-4C7D-A121-D8D771923BB0
> > +  MODULE_TYPE                    = PEIM
> > +  VERSION_STRING                 = 1.0
> > +  PI_SPECIFICATION_VERSION       = 0x0001000A
> > +  ENTRY_POINT                    = SmmIplEntry
> > +
> > +#
> > +# The following information is for reference only and not required by the
> build
> > tools.
> > +#
> > +#  VALID_ARCHITECTURES           = IA32 X64
> > +#
> > +
> > +[Sources]
> > +  StandaloneMmIplPei.h
> > +  StandaloneMmIplPei.c
> > +
> > +[Sources.Ia32]
> > +  Ia32/LoadSmmCore.c
> > +  Ia32/Thunk32To64.nasm
> > +
> > +[Sources.X64]
> > +  X64/LoadSmmCore.c
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +  StandaloneMmPkg/StandaloneMmPkg.dec
> > +
> > +[LibraryClasses]
> > +  PeimEntryPoint
> > +  PeiServicesTablePointerLib
> > +  PeiServicesLib
> > +  BaseLib
> > +  BaseMemoryLib
> > +  PeCoffLib
> > +  CacheMaintenanceLib
> > +  MemoryAllocationLib
> > +  DebugLib
> > +  HobLib
> > +  IntrinsicLib
> > +
> > +[Guids]
> > +  gMmCoreDataHobGuid
> > +  gEfiEventReadyToBootGuid
> > +
> > +[Ppis]
> > +  gPeiSmmAccessPpiGuid                     ## CONSUMES
> > +  gPeiSmmControlPpiGuid                    ## CONSUMES
> > +
> > +[FeaturePcd.IA32]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ##
> > CONSUMES
> > +
> > +[Pcd.IA32]
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ##
> > SOMETIMES_CONSUMES
> > +
> > +[Pcd]
> > +
> gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber
> > ## SOMETIMES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable
> ##
> > CONSUMES
> > +
> > +[Depex]
> > +  gPeiSmmAccessPpiGuid AND
> > +  gPeiSmmControlPpiGuid
> > +
> > diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > index 4777532a7e..872f7958be 100644
> > --- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > +++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml
> > @@ -78,7 +78,9 @@
> >      ## options defined .pytool/Plugin/SpellCheck
> >      "SpellCheck": {
> >          "AuditOnly": False,
> > -        "IgnoreFiles": [],           # use gitignore syntax to ignore errors
> > +        "IgnoreFiles": [
> > +            "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm"
> > +        ],           # use gitignore syntax to ignore errors
> >                                       # in matching files
> >          "ExtendWords": [
> >              "Bsymbolic",
> > diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc
> > b/StandaloneMmPkg/StandaloneMmPkg.dsc
> > index 8012f93b7d..d88471fe82 100644
> > --- a/StandaloneMmPkg/StandaloneMmPkg.dsc
> > +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc
> > @@ -20,7 +20,7 @@
> >    PLATFORM_VERSION               = 1.0
> >    DSC_SPECIFICATION              = 0x00010011
> >    OUTPUT_DIRECTORY               = Build/StandaloneMm
> > -  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM
> > +  SUPPORTED_ARCHITECTURES        = AARCH64|X64|ARM|IA32
> >    BUILD_TARGETS                  = DEBUG|RELEASE
> >    SKUID_IDENTIFIER               = DEFAULT
> >
> > @@ -60,6 +60,14 @@
> >
> >
> StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoin
> > t/StandaloneMmDriverEntryPoint.inf
> >
> >
> VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/V
> > ariableMmDependency.inf
> >
> > +[LibraryClasses.common.PEIM]
> > +  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> > +  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
> > +
> >
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllo
> c
> > ationLib.inf
> > +  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> > +
> >
> PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServi
> c
> > esTablePointerLib.inf
> > +  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
> > +
> >  [LibraryClasses.AARCH64, LibraryClasses.ARM]
> >    ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
> >
> >
> StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStand
> > aloneMmLib.inf
> > @@ -104,7 +112,7 @@
> >  #       generated for it, but the binary will not be put into any firmware volume.
> >  #
> >
> >
> #################################################################
> > ##################################
> > -[Components.common]
> > +[Components.AARCH64, Components.ARM, Components.X64]
> >    #
> >    # MM Core
> >    #
> > @@ -122,6 +130,9 @@
> >    StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf
> >
> >
> StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMm
> > PeCoffExtraActionLib.inf
> >
> > +[Components.X64, Components.IA32]
> > +  StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
> > +
> >
> >
> #################################################################
> > ##################################
> >  #
> >  # BuildOptions Section - Define the module specific tool chain flags that
> should
> > be used as
> > diff --git a/UefiPayloadPkg/UniversalPayloadBuild.sh
> > b/UefiPayloadPkg/UniversalPayloadBuild.sh
> > index 9a72eedd35..bacf5233a8 100644
> > --- a/UefiPayloadPkg/UniversalPayloadBuild.sh
> > +++ b/UefiPayloadPkg/UniversalPayloadBuild.sh
> > @@ -1,17 +1,17 @@
> > -#!/usr/bin/env bash
> > -#
> > -# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > -#
> > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > -#
> > -
> > -if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> > -    echo python_exe=${PYTHON_COMMAND}
> > -fi
> > -
> > -# Get file path of UniversalPayloadBuild.sh
> > -uplbld_filepath=${BASH_SOURCE:-$0}
> > -# Remove ".sh" extension
> > -uplbld_filepath_noext=${uplbld_filepath%.*}
> > -# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> > -exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> > +#!/usr/bin/env bash
> > +#
> > +# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +
> > +if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
> > +    echo python_exe=${PYTHON_COMMAND}
> > +fi
> > +
> > +# Get file path of UniversalPayloadBuild.sh
> > +uplbld_filepath=${BASH_SOURCE:-$0}
> > +# Remove ".sh" extension
> > +uplbld_filepath_noext=${uplbld_filepath%.*}
> > +# execute UniversalPayloadBuild.py to build UefiPayloadPkg
> > +exec "${python_exe:-python}" "$uplbld_filepath_noext.py" "$@"
> > diff --git a/edksetup.sh b/edksetup.sh
> > index cab3a8c113..553e1676d0 100755
> > --- a/edksetup.sh
> > +++ b/edksetup.sh
> > @@ -1,147 +1,147 @@
> > -#
> > -# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> > -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > -#
> > -# In *inux environment, the build tools's source is required and need to be
> > compiled
> > -# firstly, please reference
> > https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-
> Github-
> > Quick-Start
> > -# to get how to setup build tool.
> > -#
> > -# Setup the environment for unix-like systems running a bash-like shell.
> > -# This file must be "sourced" not merely executed. For example: ".
> edksetup.sh"
> > -#
> > -# CYGWIN users: Your path and filename related environment variables
> should
> > be
> > -# set up in the unix style.  This script will make the necessary conversions to
> > -# windows style.
> > -#
> > -# Please reference edk2 user manual for more detail descriptions at
> > https://github.com/tianocore-
> > docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> > -#
> > -
> > -SCRIPTNAME="edksetup.sh"
> > -RECONFIG=FALSE
> > -
> > -HelpMsg()
> > -{
> > -  echo "Usage: $SCRIPTNAME [Options]"
> > -  echo
> > -  echo "The system environment variable, WORKSPACE, is always set to the
> > current"
> > -  echo "working directory."
> > -  echo
> > -  echo "Options: "
> > -  echo "  --help, -h, -?        Print this help screen and exit."
> > -  echo
> > -  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with
> the"
> > -  echo "                        template files from the BaseTools/Conf directory."
> > -  echo
> > -  echo Please note: This script must be \'sourced\' so the environment can be
> > changed.
> > -  echo ". $SCRIPTNAME"
> > -  echo "source $SCRIPTNAME"
> > -}
> > -
> > -SetWorkspace()
> > -{
> > -  #
> > -  # If WORKSPACE is already set, then we can return right now
> > -  #
> > -  export PYTHONHASHSEED=1
> > -  if [ -n "$WORKSPACE" ]
> > -  then
> > -    return 0
> > -  fi
> > -
> > -  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> > -  then
> > -    echo Source this script from the base of your tree.  For example:
> > -    echo "  cd /Path/To/Edk2/Clone"
> > -    echo "  . $SCRIPTNAME"
> > -    return 1
> > -  fi
> > -
> > -  #
> > -  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> > -  #
> > -  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> > -  then
> > -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > -    echo Please point EDK_TOOLS_PATH at the directory that contains
> > -    echo the EDK2 BuildEnv script.
> > -    return 1
> > -  fi
> > -
> > -  #
> > -  # Set $WORKSPACE
> > -  #
> > -  export WORKSPACE=$PWD
> > -  return 0
> > -}
> > -
> > -SetupEnv()
> > -{
> > -  if [ -n "$EDK_TOOLS_PATH" ]
> > -  then
> > -    . $EDK_TOOLS_PATH/BuildEnv
> > -  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> > -  then
> > -    . $WORKSPACE/BaseTools/BuildEnv
> > -  elif [ -n "$PACKAGES_PATH" ]
> > -  then
> > -    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> > -    do
> > -      if [ -f "$DIR/BaseTools/BuildEnv" ]
> > -      then
> > -        export EDK_TOOLS_PATH=$DIR/BaseTools
> > -        . $DIR/BaseTools/BuildEnv
> > -        break
> > -      fi
> > -    done
> > -  else
> > -    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > -    echo Please check that WORKSPACE or PACKAGES_PATH is not set
> incorrectly
> > -    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> > -    echo the EDK2 BuildEnv script.
> > -    return 1
> > -  fi
> > -}
> > -
> > -SetupPython3()
> > -{
> > -  export PYTHON_COMMAND=python3
> > -}
> > -
> > -SourceEnv()
> > -{
> > -  SetupPython3
> > -  SetWorkspace
> > -  SetupEnv
> > -}
> > -
> > -I=$#
> > -while [ $I -gt 0 ]
> > -do
> > -  case "$1" in
> > -    BaseTools)
> > -      # Ignore argument for backwards compatibility
> > -      shift
> > -    ;;
> > -    --reconfig)
> > -      RECONFIG=TRUE
> > -      shift
> > -    ;;
> > -    *)
> > -      HelpMsg
> > -      break
> > -    ;;
> > -  esac
> > -  I=$((I - 1))
> > -done
> > -
> > -if [ $I -gt 0 ]
> > -then
> > -  return 1
> > -fi
> > -
> > -SourceEnv
> > -
> > -unset SCRIPTNAME RECONFIG
> > -
> > -return $?
> > +#
> > +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +# In *inux environment, the build tools's source is required and need to be
> > compiled
> > +# firstly, please reference
> > https://github.com/tianocore/tianocore.github.io/wiki/SourceForge-to-
> Github-
> > Quick-Start
> > +# to get how to setup build tool.
> > +#
> > +# Setup the environment for unix-like systems running a bash-like shell.
> > +# This file must be "sourced" not merely executed. For example: ".
> edksetup.sh"
> > +#
> > +# CYGWIN users: Your path and filename related environment variables
> should
> > be
> > +# set up in the unix style.  This script will make the necessary conversions to
> > +# windows style.
> > +#
> > +# Please reference edk2 user manual for more detail descriptions at
> > https://github.com/tianocore-
> > docs/Docs/raw/master/User_Docs/EDK_II_UserManual_0_7.pdf
> > +#
> > +
> > +SCRIPTNAME="edksetup.sh"
> > +RECONFIG=FALSE
> > +
> > +HelpMsg()
> > +{
> > +  echo "Usage: $SCRIPTNAME [Options]"
> > +  echo
> > +  echo "The system environment variable, WORKSPACE, is always set to the
> > current"
> > +  echo "working directory."
> > +  echo
> > +  echo "Options: "
> > +  echo "  --help, -h, -?        Print this help screen and exit."
> > +  echo
> > +  echo "  --reconfig            Overwrite the WORKSPACE/Conf/*.txt files with
> the"
> > +  echo "                        template files from the BaseTools/Conf directory."
> > +  echo
> > +  echo Please note: This script must be \'sourced\' so the environment can be
> > changed.
> > +  echo ". $SCRIPTNAME"
> > +  echo "source $SCRIPTNAME"
> > +}
> > +
> > +SetWorkspace()
> > +{
> > +  #
> > +  # If WORKSPACE is already set, then we can return right now
> > +  #
> > +  export PYTHONHASHSEED=1
> > +  if [ -n "$WORKSPACE" ]
> > +  then
> > +    return 0
> > +  fi
> > +
> > +  if [ ! -f ${SCRIPTNAME} ] && [ -z "$PACKAGES_PATH" ]
> > +  then
> > +    echo Source this script from the base of your tree.  For example:
> > +    echo "  cd /Path/To/Edk2/Clone"
> > +    echo "  . $SCRIPTNAME"
> > +    return 1
> > +  fi
> > +
> > +  #
> > +  # Check for BaseTools/BuildEnv before dirtying the user's environment.
> > +  #
> > +  if [ ! -f BaseTools/BuildEnv ] && [ -z "$EDK_TOOLS_PATH" ]
> > +  then
> > +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > +    echo Please point EDK_TOOLS_PATH at the directory that contains
> > +    echo the EDK2 BuildEnv script.
> > +    return 1
> > +  fi
> > +
> > +  #
> > +  # Set $WORKSPACE
> > +  #
> > +  export WORKSPACE=$PWD
> > +  return 0
> > +}
> > +
> > +SetupEnv()
> > +{
> > +  if [ -n "$EDK_TOOLS_PATH" ]
> > +  then
> > +    . $EDK_TOOLS_PATH/BuildEnv
> > +  elif [ -f "$WORKSPACE/BaseTools/BuildEnv" ]
> > +  then
> > +    . $WORKSPACE/BaseTools/BuildEnv
> > +  elif [ -n "$PACKAGES_PATH" ]
> > +  then
> > +    for DIR in $(echo $PACKAGES_PATH | tr ':' ' ')
> > +    do
> > +      if [ -f "$DIR/BaseTools/BuildEnv" ]
> > +      then
> > +        export EDK_TOOLS_PATH=$DIR/BaseTools
> > +        . $DIR/BaseTools/BuildEnv
> > +        break
> > +      fi
> > +    done
> > +  else
> > +    echo BaseTools not found in your tree, and EDK_TOOLS_PATH is not set.
> > +    echo Please check that WORKSPACE or PACKAGES_PATH is not set
> incorrectly
> > +    echo in your shell, or point EDK_TOOLS_PATH at the directory that contains
> > +    echo the EDK2 BuildEnv script.
> > +    return 1
> > +  fi
> > +}
> > +
> > +SetupPython3()
> > +{
> > +  export PYTHON_COMMAND=python3
> > +}
> > +
> > +SourceEnv()
> > +{
> > +  SetupPython3
> > +  SetWorkspace
> > +  SetupEnv
> > +}
> > +
> > +I=$#
> > +while [ $I -gt 0 ]
> > +do
> > +  case "$1" in
> > +    BaseTools)
> > +      # Ignore argument for backwards compatibility
> > +      shift
> > +    ;;
> > +    --reconfig)
> > +      RECONFIG=TRUE
> > +      shift
> > +    ;;
> > +    *)
> > +      HelpMsg
> > +      break
> > +    ;;
> > +  esac
> > +  I=$((I - 1))
> > +done
> > +
> > +if [ $I -gt 0 ]
> > +then
> > +  return 1
> > +fi
> > +
> > +SourceEnv
> > +
> > +unset SCRIPTNAME RECONFIG
> > +
> > +return $?
> > --
> > 2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#106364): https://edk2.groups.io/g/devel/message/106364
Mute This Topic: https://groups.io/mt/99079640/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-