From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by mx.groups.io with SMTP id smtpd.web09.1683.1667989202781363624 for ; Wed, 09 Nov 2022 02:20:03 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=t5NfFZG2; spf=pass (domain: kernel.org, ip: 145.40.68.75, mailfrom: ardb@kernel.org) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 4C0DAB81D7E for ; Wed, 9 Nov 2022 10:20:00 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A49B2C433D6 for ; Wed, 9 Nov 2022 10:19:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1667989199; bh=j2EKnkc0RlZoVFyIH4lG6daCMpTeUtjrZMKjU3Why7w=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=t5NfFZG2/2rkIQ7ye42uIcUXiT9KrOwYkj4rTo6XLiDryVRx6zPVZC//nPH6KroF4 Ok6gXYocw1UC11/jhjitYk/BTMyIOat+I6sb0SuhzBqLOlv9gpe4sv/NSf6dH+VXEo /NpuqlChAh9Ru8qjbZzEIVxKnG9qX+rpbNrdpq/XvKkANJ+VlwYgOfIxd+R1MpvyJe EpF0mEexzHNxj+WlQS15ZVZ80Qiqp0RHi8WHgnf5dKKHzD4KOlMIMA79hqbd/RG2/h hBDSEM3iOzwuy+pOnmFDZ2lReBc9bny8tnjdl58chwzxnducEEso600wtCr8bQxE8b 8SiE1f1FCPXAA== Received: by mail-lj1-f175.google.com with SMTP id a15so25018691ljb.7 for ; Wed, 09 Nov 2022 02:19:58 -0800 (PST) X-Gm-Message-State: ACrzQf0od8oZ4mfn6cixIKNXyWn9lB0vi+NMjU84rZPoLpYNCOFpL/mE IQM2isX5VEv8BKIqDTP47tUi1P6Nq3NaEJsZI7I= X-Google-Smtp-Source: AMsMyM7DkorGMe/zXyqAN8qpapkpT0GQcXiEsdbk46DodPk0+G9rwIp/hY+a28EET1yl2a0r4Osjt/JfjMRcap9u7TQ= X-Received: by 2002:a2e:9a81:0:b0:26c:5b63:7a83 with SMTP id p1-20020a2e9a81000000b0026c5b637a83mr21863352lji.291.1667989196467; Wed, 09 Nov 2022 02:19:56 -0800 (PST) MIME-Version: 1.0 References: <20221109061636.578-1-hongbin1.zhang@intel.com> In-Reply-To: <20221109061636.578-1-hongbin1.zhang@intel.com> From: "Ard Biesheuvel" Date: Wed, 9 Nov 2022 11:19:45 +0100 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [PATCH v1 1/1] StandaloneMmPkg: Add StandaloneMmIplPei driver. To: Hongbin1 Zhang Cc: devel@edk2.groups.io, Jiewen Yao , Ray Ni , Star Zeng , Sami Mujawar Content-Type: text/plain; charset="UTF-8" On Wed, 9 Nov 2022 at 07:17, Hongbin1 Zhang 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 > Cc: Jiewen Yao > Cc: Ray Ni > Cc: Star Zeng > Cc: Sami Mujawar > Cc: Ard Biesheuvel I cannot review this but I'm happy for it to go in. Acked-by: Ard Biesheuvel > --- > StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c | 442 ++++++++++++ > StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c | 726 ++++++++++++++++++++ > StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c | 32 + > StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm | 148 ++++ > StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h | 47 ++ > StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf | 74 ++ > StandaloneMmPkg/StandaloneMmPkg.ci.yaml | 4 +- > StandaloneMmPkg/StandaloneMmPkg.dsc | 15 +- > 8 files changed, 1485 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.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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..e1ac6a2b3119 > --- /dev/null > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c > @@ -0,0 +1,726 @@ > +/** @file > + SMM IPL that load the SMM Core into SMRAM at PEI stage > + > + Copyright (c) 2022, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +// > +// 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; > + > +/** > + 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 three entries for all SMM drivers & SMM Core in the full SMRAM ranges. > + // > + AdditionSmramRangeCount = 2; > + } > + > + // > + // No reserved SMRAM entry from SMM Configuration Protocol. > + // > + *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; > + > + // > + // 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); > + } > + > + // > + // 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; > + } > + > + 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.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > + > +/** > + 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.
> +; 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..5e27dfe1454c > --- /dev/null > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h > @@ -0,0 +1,47 @@ > +/** @file > + Private header with declarations and definitions specific to the Standalone > + MM IPL PEI driver > + > + Copyright (c) 2022, Intel Corporation. All rights reserved.
> + 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 > + > + @return status. > +**/ > +UINT32 > +AsmExecute64BitCode ( > + IN UINT64 Function, > + IN UINT64 Param1, > + IN UINT64 Param2, > + IN IA32_DESCRIPTOR *InternalGdtr > + ); > + > +#endif > diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf > new file mode 100644 > index 000000000000..e531280abdfe > --- /dev/null > +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf > @@ -0,0 +1,74 @@ > +## @file > +# This module provide a Standalone SMM compliant implementation of SMM IPL PEIM. > +# > +# Copyright (c) 2022, Intel Corporation. All rights reserved.
> +# > +# 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 > + > +[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 >