* [PATCH v2 1/1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
@ 2022-11-21 1:08 Hongbin1 Zhang
2022-11-21 7:55 ` Ard Biesheuvel
0 siblings, 1 reply; 2+ messages in thread
From: Hongbin1 Zhang @ 2022-11-21 1:08 UTC (permalink / raw)
To: devel
Cc: Hongbin1 Zhang, Jiewen Yao, Ray Ni, Star Zeng, Jiaxin Wu,
Sami Mujawar, Ard Biesheuvel, Supreeth Venkatesh
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 | 442 +++++++++++
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 +-
8 files changed, 1566 insertions(+), 3 deletions(-)
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
new file mode 100644
index 000000000000..0dfb574bd228
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
@@ -0,0 +1,442 @@
+/** @file
+ SMM IPL that load the SMM Core into SMRAM
+
+ Copyright (c) 2022, 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;
+
+ DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
+
+ PageTableSize = CalculatePageTableSize ();
+
+ PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PageTableSize));
+ ASSERT (PageTableAddress != 0);
+
+ CreateIdentityMappingPageTables (PageTableAddress);
+
+ AsmWriteGdtr (&mGdt);
+
+ 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));
+
+ 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
+ )
+{
+ STANDALONE_MM_FOUNDATION_ENTRY_POINT EntryPoint;
+
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return ModeSwitch (Entry, Context1, NULL);
+ }
+
+ EntryPoint = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
+ return EntryPoint (Context1);
+}
diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
new file mode 100644
index 000000000000..9b3e611f2d17
--- /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) 2022, 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 000000000000..5cabf310e33c
--- /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) 2022, 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 000000000000..2332d32e5885
--- /dev/null
+++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
@@ -0,0 +1,148 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2022, 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 000000000000..5eca763f842a
--- /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) 2022, 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 000000000000..4e74a0b3eec0
--- /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) 2022, 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 4777532a7ede..872f7958be84 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 8012f93b7dcc..d88471fe82be 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
--
2.26.2.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v2 1/1] StandaloneMmPkg: Add StandaloneMmIplPei driver.
2022-11-21 1:08 [PATCH v2 1/1] StandaloneMmPkg: Add StandaloneMmIplPei driver Hongbin1 Zhang
@ 2022-11-21 7:55 ` Ard Biesheuvel
0 siblings, 0 replies; 2+ messages in thread
From: Ard Biesheuvel @ 2022-11-21 7:55 UTC (permalink / raw)
To: Hongbin1 Zhang
Cc: devel, Jiewen Yao, Ray Ni, Star Zeng, Jiaxin Wu, Sami Mujawar
How is this v2 different from v1 ?
On Mon, 21 Nov 2022 at 02:09, Hongbin1 Zhang <hongbin1.zhang@intel.com> wrote:
>
> 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 | 442 +++++++++++
> 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 +-
> 8 files changed, 1566 insertions(+), 3 deletions(-)
>
> diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> new file mode 100644
> index 000000000000..0dfb574bd228
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c
> @@ -0,0 +1,442 @@
> +/** @file
> + SMM IPL that load the SMM Core into SMRAM
> +
> + Copyright (c) 2022, 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;
> +
> + DEBUG ((DEBUG_INFO, "ModeSwitch\n"));
> +
> + PageTableSize = CalculatePageTableSize ();
> +
> + PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PageTableSize));
> + ASSERT (PageTableAddress != 0);
> +
> + CreateIdentityMappingPageTables (PageTableAddress);
> +
> + AsmWriteGdtr (&mGdt);
> +
> + 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));
> +
> + 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
> + )
> +{
> + STANDALONE_MM_FOUNDATION_ENTRY_POINT EntryPoint;
> +
> + if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
> + return ModeSwitch (Entry, Context1, NULL);
> + }
> +
> + EntryPoint = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)Entry;
> + return EntryPoint (Context1);
> +}
> diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c
> new file mode 100644
> index 000000000000..9b3e611f2d17
> --- /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) 2022, 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 000000000000..5cabf310e33c
> --- /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) 2022, 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 000000000000..2332d32e5885
> --- /dev/null
> +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm
> @@ -0,0 +1,148 @@
> +;------------------------------------------------------------------------------
> +;
> +; Copyright (c) 2022, 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 000000000000..5eca763f842a
> --- /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) 2022, 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 000000000000..4e74a0b3eec0
> --- /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) 2022, 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 4777532a7ede..872f7958be84 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 8012f93b7dcc..d88471fe82be 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
> --
> 2.26.2.windows.1
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2022-11-21 7:56 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-21 1:08 [PATCH v2 1/1] StandaloneMmPkg: Add StandaloneMmIplPei driver Hongbin1 Zhang
2022-11-21 7:55 ` Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox