From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mx.groups.io with SMTP id smtpd.web11.2875.1687160811414090506 for ; Mon, 19 Jun 2023 00:47:00 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=U1aoEF3N; spf=pass (domain: intel.com, ip: 192.55.52.151, mailfrom: hongbin1.zhang@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1687160820; x=1718696820; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QQgWMhojlcSzmITnmbW8YTFcci6f6s4ggZn8BIacRno=; b=U1aoEF3NwKDLfota7fqEN9zHqO0qib09I490p7OUpoPWy5C9c3iItBfy mBcMnmfs8FDA79cXJJ8QfTLunFEuy7ZPMjtegX1LDTtiEV4qmPkRxA8JF DqDJAEBZVrqfKS7KMiAjZUWosAs7wCAlu8wFkk3L7GL2YRqVGqMHNxslU CswDkhgsIu979tVh9S8AnEI2VpH9yHH2tTrosIc8nFGpMyUfUVOwiWqAf QosdKq9tZxlQNvllJScO/aDAHD2eGDFG+0DPL7fImoM+gTXtamSI20eLE TgX06nmICeK3V0nrGhQ6z5zAmrntyoA0Trd6Pk6wvaCpihWpD7rexgHkm Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10745"; a="339904862" X-IronPort-AV: E=Sophos;i="6.00,254,1681196400"; d="scan'208";a="339904862" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Jun 2023 00:47:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10745"; a="960346453" X-IronPort-AV: E=Sophos;i="6.00,254,1681196400"; d="scan'208";a="960346453" Received: from hongbin1-mobl1.ccr.corp.intel.com ([10.238.0.232]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Jun 2023 00:46:57 -0700 From: "Zhang, Hongbin1" To: devel@edk2.groups.io Cc: "Zhang, Hongbin1" , Jiewen Yao , Ray Ni , Star Zeng , Jiaxin Wu , Sami Mujawar , Ard Biesheuvel , Supreeth Venkatesh Subject: [PATCH v4 3/5] StandaloneMmPkg: Add StandaloneMmIplPei driver. Date: Mon, 19 Jun 2023 15:46:37 +0800 Message-Id: <20230619074639.1569-3-hongbin1.zhang@intel.com> X-Mailer: git-send-email 2.37.0.windows.1 In-Reply-To: <20230619074639.1569-1-hongbin1.zhang@intel.com> References: <20230619074639.1569-1-hongbin1.zhang@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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: Jiaxin Wu Cc: Sami Mujawar Cc: Ard Biesheuvel Cc: Supreeth Venkatesh --- StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c | 456 ++++++++++++++++++++ StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c | 18 +- StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c | 29 ++ StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm | 148 +++++++ StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h | 47 ++ StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf | 11 + StandaloneMmPkg/StandaloneMmPkg.ci.yaml | 4 +- 7 files changed, 709 insertions(+), 4 deletions(-) diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c new file mode 100644 index 0000000000..2d43807a88 --- /dev/null +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/LoadSmmCore.c @@ -0,0 +1,456 @@ +/** @file + SMM IPL that load the SMM Core into SMRAM + + Copyright (c) 2023, Intel Corporation. All rights reserved.
+ 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; + IA32_DESCRIPTOR Gdtr; + + DEBUG ((DEBUG_INFO, "ModeSwitch\n")); + + // + // Save IA32 GDTR + // + AsmReadGdtr (&Gdtr); + + // + // Set X64 GDTR + // + AsmWriteGdtr (&mGdt); + + PageTableAddress = AsmReadCr3 () & 0xFFFFF000; + + // + // If page table was created, no need to create + // + if (PageTableAddress == 0) { + PageTableSize = CalculatePageTableSize (); + + PageTableAddress = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PageTableSize)); + ASSERT (PageTableAddress != 0); + + CreateIdentityMappingPageTables (PageTableAddress); + + AsmWriteCr3 ((UINTN)PageTableAddress); + } + + DEBUG ((DEBUG_INFO, "AsmExecute64BitCode ...\n")); + + Status = AsmExecute64BitCode (Entry, (UINT64)(UINTN)Context1, (UINT64)(UINTN)Context2, NULL); + if (Status != 0) { + Status = Status | MAX_BIT; + } + + DEBUG ((DEBUG_INFO, "AsmExecute64BitCode - %r\n", Status)); + + // + // Restore IA32 GDTR + // + AsmWriteGdtr (&Gdtr); + + return Status; +} + +/** + Load SMM core to dispatch other Standalone MM drivers after IA32 mode to X64 mode. + + @param Entry Entry of Standalone MM Foundation. + @param Context1 A pointer to the context to pass into the EntryPoint + function. + @retval EFI_SUCCESS Successfully loaded SMM core. + @retval Others Failed to load SMM core. +**/ +EFI_STATUS +LoadSmmCoreIA32ToX64 ( + IN EFI_PHYSICAL_ADDRESS Entry, + IN VOID *Context1 + ) +{ + return ModeSwitch (Entry, Context1, NULL); +} diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c index e043fcdb65..47cc18ecbd 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c @@ -20,6 +20,7 @@ #include #include #include +#include // // MM Core Private Data structure that contains the data shared between @@ -43,7 +44,7 @@ MM_CORE_PRIVATE_DATA mMmCorePrivateData = { }; // -// Global pointer used to access mMmCorePrivateData from outside and inside SMM +// Global pointer used to access mMmCorePrivateData from outside and inside SMM. // MM_CORE_PRIVATE_DATA *gMmCorePrivate; @@ -399,9 +400,20 @@ ExecuteSmmCoreFromSmram ( DEBUG ((DEBUG_INFO, "SMM IPL calling Standalone MM Core at SMRAM address - 0x%016lx\n", gMmCorePrivate->MmCoreEntryPoint)); // - // Execute image + // If StandaloneMmIpl driver is IA32 image, but Standalone MM core is X64 image + // Switch 32 bit protect mode to X64 mode and load SMM core // - LoadSmmCore (ImageContext.EntryPoint, HobList); + if ((sizeof (UINTN) == sizeof (UINT32)) && (ImageContext.Machine == EFI_IMAGE_MACHINE_X64)) { + // + // Switch to X64 mode and load SMM core + // + LoadSmmCoreIA32ToX64 (ImageContext.EntryPoint, HobList); + } else { + // + // Execute image + // + LoadSmmCore (ImageContext.EntryPoint, HobList); + } } } diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c new file mode 100644 index 0000000000..9cd0636c4b --- /dev/null +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/X64/LoadSmmCore.c @@ -0,0 +1,29 @@ +/** @file + SMM IPL that load the SMM Core into SMRAM + + Copyright (c) 2023, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +/** + Load SMM core to dispatch other Standalone MM drivers after IA32 mode to X64 mode. + + @param Entry Entry of Standalone MM Foundation. + @param Context1 A pointer to the context to pass into the EntryPoint + function. + @retval EFI_SUCCESS Successfully loaded SMM core. + @retval Others Failed to load SMM core. +**/ +EFI_STATUS +LoadSmmCoreIA32ToX64 ( + IN EFI_PHYSICAL_ADDRESS Entry, + IN VOID *Context1 + ) +{ + return EFI_SUCCESS; +} \ No newline at end of file diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm new file mode 100644 index 0000000000..7f887eb77d --- /dev/null +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm @@ -0,0 +1,148 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2023, Intel Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; Thunk32To64.nasm +; +; Abstract: +; +; This is the assembly code to transition from long mode to compatibility +; mode to execute 32-bit code and then transit back to long mode. +; +;------------------------------------------------------------------------------ + + SECTION .text + +;------------------------------------------------------------------------------ +; Procedure: AsmExecute64BitCode +; +; Input: None +; +; Output: None +; +; Prototype: UINT32 +; AsmExecute64BitCode ( +; IN UINT64 Function, +; IN UINT64 Param1, +; IN UINT64 Param2, +; IN IA32_DESCRIPTOR *InternalGdtr +; ); +; +; +; Description: A thunk function to execute 32-bit code in long mode. +; +;------------------------------------------------------------------------------ +global ASM_PFX(AsmExecute64BitCode) +ASM_PFX(AsmExecute64BitCode): +; +; +---------+ +; | EIP(64) | +; +---------+ +; | CS (64) | +; +---------+ +; | EIP(32) | +; +---------+ +; | CS (32) |<-ESP (16 bytes aligned) +; +---------+ +; | ... | +; +---------+ +; | ebx |<-EBP +; +---------+ +; | ebp |<-EBP + 4 +; +---------+ +; | esi |<-EBP + 8 +; +---------+ +; | edi |<-EBP + 12 +; +---------+ +; | RFlags |<-EBP + 16 +; +---------+ +; | RetAddr |<-EBP (org) +; +---------+ +; | Func |<-EBP + 24 +; | Func | +; +---------+ +; | Param1 |<-EBP + 32 +; | Param1 | +; +---------+ +; | Param2 |<-EBP + 40 +; | Param2 | +; +---------+ +; | Gdtr | +; +---------+ +; + ; + ; Save general purpose register and RFlags register + ; + pushfd + push edi + push esi + push ebp + push ebx + mov ebp, esp + + and esp, 0FFFFFFF0h + + push 010h ; protected mode selector on stack + mov eax, Compatible ; offset for LongMode + push eax ; offset on stack + + push 038h ; long mode selector on stack + mov eax, LongMode ; offset for LongMode + push eax ; offset on stack + + mov eax, cr4 + or al, 020h + mov cr4, eax ; enable PAE + mov ecx, 0c0000080h + rdmsr + or ah, 1 ; set LME + wrmsr + mov eax, cr0 + bts eax, 31 ; set PG + mov cr0, eax ; enable paging + retf ; topmost 2 dwords hold the address +LongMode: ; long mode starts here + + ; Call long mode function + DB 67h, 48h ; 32-bit address size, 64-bit operand size + mov eax, [ebp + 24] ; mov rbx, [ebp + 24] + DB 67h, 48h + mov ecx, [ebp + 24 + 8] ; mov rcx, [ebp + 24 + 8] + DB 67h, 48h + mov edx, [ebp + 24 + 16] ; mov rdx, [ebp + 24 + 16] + + DB 48h + add esp, -20h ; add rsp, -20h + call eax ; call rax + DB 48h + add esp, 20h ; add rsp, 20h + + ; after long mode function call + mov ebx, eax + + retf +Compatible: + mov ecx, cr0 + btc ecx, 31 ; clear PG + mov cr0, ecx ; disable paging + mov ecx, 0C0000080h + rdmsr + btc eax, 8 ; clear LME + wrmsr + + ; + ; Restore C register and eax hold the return status from 32-bit function. + ; Note: Do not touch rax from now which hold the return value from IA32 function + ; + mov eax, ebx ; put return status to EAX + mov esp, ebp ; restore stack pointer + pop ebx + pop ebp + pop esi + pop edi + popfd + + ret diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h new file mode 100644 index 0000000000..170a6c9e40 --- /dev/null +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.h @@ -0,0 +1,47 @@ +/** @file + Private header with declarations and definitions specific to the Standalone + MM IPL PEI driver + + Copyright (c) 2023, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef STANDALONE_MM_IPL_PEI_H_ +#define STANDALONE_MM_IPL_PEI_H_ + +/** + Assembly function to transition from long mode to compatibility mode to + execute 32-bit code and then transit back to long mode. + + @param[in] Function The 32bit code entry to be executed. + @param[in] Param1 The first parameter to pass to 32bit code + @param[in] Param2 The second parameter to pass to 32bit code + @param[in] InternalGdtr The GDT and GDT descriptor used by this library + + @retval status. +**/ +UINT32 +AsmExecute64BitCode ( + IN UINT64 Function, + IN UINT64 Param1, + IN UINT64 Param2, + IN IA32_DESCRIPTOR *InternalGdtr + ); + +/** + Load SMM core to dispatch other Standalone MM drivers after IA32 mode to X64 mode. + + @param Entry Entry of Standalone MM Foundation. + @param Context1 A pointer to the context to pass into the EntryPoint + function. + @retval EFI_SUCCESS Successfully loaded SMM core. + @retval Others Failed to load SMM core. +**/ +EFI_STATUS +LoadSmmCoreIA32ToX64 ( + IN EFI_PHYSICAL_ADDRESS Entry, + IN VOID *Context1 + ); + +#endif diff --git a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf index 668d3afbf4..b9851c072f 100644 --- a/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf +++ b/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.inf @@ -23,8 +23,16 @@ # [Sources] + StandaloneMmIplPei.h StandaloneMmIplPei.c +[Sources.Ia32] + Ia32/LoadSmmCore.c + Ia32/Thunk32To64.nasm + +[Sources.X64] + X64/LoadSmmCore.c + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec @@ -49,6 +57,9 @@ [Ppis] gPeiSmmAccessPpiGuid ## CONSUMES +[Pcd.IA32] + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES + [Pcd] [Depex] diff --git a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml index 4777532a7e..872f7958be 100644 --- a/StandaloneMmPkg/StandaloneMmPkg.ci.yaml +++ b/StandaloneMmPkg/StandaloneMmPkg.ci.yaml @@ -78,7 +78,9 @@ ## options defined .pytool/Plugin/SpellCheck "SpellCheck": { "AuditOnly": False, - "IgnoreFiles": [], # use gitignore syntax to ignore errors + "IgnoreFiles": [ + "Drivers/StandaloneMmIplPei/Ia32/Thunk32To64.nasm" + ], # use gitignore syntax to ignore errors # in matching files "ExtendWords": [ "Bsymbolic", -- 2.37.0.windows.1