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.zh...@intel.com>
Cc: Jiewen Yao <jiewen....@intel.com>
Cc: Ray Ni <ray...@intel.com>
Cc: Star Zeng <star.z...@intel.com>
Cc: Jiaxin Wu <jiaxin...@intel.com>
Cc: Sami Mujawar <sami.muja...@arm.com>
Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org>
Cc: Supreeth Venkatesh <supreeth.venkat...@arm.com>
---
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c     | 456 
++++++++++++++++++++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c   |  18 +-
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c      |  29 ++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm  | 148 +++++++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h   |  47 ++
 StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf |  11 +
 StandaloneMmPkg/StandaloneMmPkg.ci.yaml                           |   4 +-
 7 files changed, 709 insertions(+), 4 deletions(-)

diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c 
b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
new file mode 100644
index 0000000000..2d43807a88
--- /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 after IA32 mode to X64 
mode.
+
+  @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
+LoadSmmCoreIA32ToX64 (
+  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
index e043fcdb65..47cc18ecbd 100644
--- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
@@ -20,6 +20,7 @@
 #include <Library/PeiServicesLib.h>
 #include <Library/HobLib.h>
 #include <Guid/MmCoreData.h>
+#include <StandaloneMmIplPei.h>
 
 //
 // MM Core Private Data structure that contains the data shared between
@@ -43,7 +44,7 @@ MM_CORE_PRIVATE_DATA  mMmCorePrivateData = {
 };
 
 //
-// Global pointer used to access mMmCorePrivateData from outside and inside SMM
+// Global pointer used to access mMmCorePrivateData from outside and inside 
SMM.
 //
 MM_CORE_PRIVATE_DATA  *gMmCorePrivate;
 
@@ -399,9 +400,20 @@ ExecuteSmmCoreFromSmram (
       DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM address 
- 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint));
 
       //
-      // Execute image
+      // If StandaloneMmIpl driver is IA32 image, but Standalone MM core is 
X64 image
+      // Switch 32 bit protect mode to X64 mode and load SMM core
       //
-      LoadSmmCore (ImageContext.EntryPoint, HobList);
+      if ((sizeof (UINTN) == sizeof (UINT32)) && (ImageContext.Machine == 
EFI_IMAGE_MACHINE_X64)) {
+        //
+        // Switch to X64 mode and load SMM core
+        //
+        LoadSmmCoreIA32ToX64 (ImageContext.EntryPoint, HobList);
+      } else {
+        //
+        // Execute image
+        //
+        LoadSmmCore (ImageContext.EntryPoint, HobList);
+      }
     }
   }
 
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c 
b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
new file mode 100644
index 0000000000..9cd0636c4b
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c
@@ -0,0 +1,29 @@
+/** @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 after IA32 mode to X64 
mode.
+
+  @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
+LoadSmmCoreIA32ToX64 (
+  IN EFI_PHYSICAL_ADDRESS  Entry,
+  IN VOID                  *Context1
+  )
+{
+  return EFI_SUCCESS;
+}
\ No newline at end of file
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..170a6c9e40
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h
@@ -0,0 +1,47 @@
+/** @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_
+
+/**
+  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
+  );
+
+/**
+  Load SMM core to dispatch other Standalone MM drivers after IA32 mode to X64 
mode.
+
+  @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
+LoadSmmCoreIA32ToX64 (
+  IN EFI_PHYSICAL_ADDRESS  Entry,
+  IN VOID                  *Context1
+  );
+
+#endif
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf 
b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
index 668d3afbf4..b9851c072f 100644
--- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf
@@ -23,8 +23,16 @@
 #
 
 [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
@@ -49,6 +57,9 @@
 [Ppis]
   gPeiSmmAccessPpiGuid                     ## CONSUMES
 
+[Pcd.IA32]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable              ## 
SOMETIMES_CONSUMES
+
 [Pcd]
 
 [Depex]
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",
-- 
2.37.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#106192): https://edk2.groups.io/g/devel/message/106192
Mute This Topic: https://groups.io/mt/99640660/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to