summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiaxin Wu <jiaxin.wu@intel.com>2024-06-24 20:24:30 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-08-28 15:25:27 +0000
commit8ccf7f65e5e3276e2bad06419134759c02107e75 (patch)
tree490193498ee6b0d9b6cc88d0839c1932defd68b2
parentcc5df45eb6bb1b514df6abd002c3663388efb814 (diff)
downloadedk2-8ccf7f65e5e3276e2bad06419134759c02107e75.tar.gz
UefiCpuPkg/PiSmmCpuDxeSmm: Centralize Non-Mmram Mem Management Code
Centralize the SMM Non-Mmram Memory Management related code into the NonMmramMapDxeSmm.c. The file SmmCpuMemoryManagement.c will be target to use for both SMM and MM in subsequent patches. No function impact. Signed-off-by: Jiaxin Wu <jiaxin.wu@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Dun Tan <dun.tan@intel.com> Cc: Hongbin1 Zhang <hongbin1.zhang@intel.com> Cc: Wei6 Xu <wei6.xu@intel.com> Cc: Yuanhao Xie <yuanhao.xie@intel.com>
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c488
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf1
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c477
3 files changed, 489 insertions, 477 deletions
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c
new file mode 100644
index 0000000000..d188b11a96
--- /dev/null
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c
@@ -0,0 +1,488 @@
+/** @file
+
+Copyright (c) 2016 - 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCpuCommon.h"
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+//
+// attributes for reserved memory before it is promoted to system memory
+//
+#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
+#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
+#define EFI_MEMORY_TESTED 0x0400000000000000ULL
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap;
+UINTN mUefiMemoryMapSize;
+UINTN mUefiDescriptorSize;
+
+EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace = NULL;
+UINTN mGcdMemNumberOfDesc = 0;
+
+EFI_MEMORY_ATTRIBUTES_TABLE *mUefiMemoryAttributesTable = NULL;
+
+/**
+ Sort memory map entries based upon PhysicalStart, from low to high.
+
+ @param MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+}
+
+/**
+ Return if a UEFI memory page should be marked as not present in SMM page table.
+ If the memory map entries type is
+ EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
+ EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
+ Or return FALSE.
+
+ @param[in] MemoryMap A pointer to the memory descriptor.
+
+ @return TRUE The memory described will be marked as not present in SMM page table.
+ @return FALSE The memory described will not be marked as not present in SMM page table.
+**/
+BOOLEAN
+IsUefiPageNotPresent (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMap
+ )
+{
+ switch (MemoryMap->Type) {
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ case EfiUnusableMemory:
+ case EfiACPIReclaimMemory:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ Merge continuous memory map entries whose type is
+ EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
+ EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
+ these entries will be set as NOT present in SMM page table.
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
+ MemoryMap buffer. On input, this is the size of
+ the current memory map. On output,
+ it is the size of new memory map after merge.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+MergeMemoryMapForNotPresentEntry (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN OUT UINTN *MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINT64 MemoryBlockLength;
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+
+ MemoryMapEntry = MemoryMap;
+ NewMemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+
+ do {
+ MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages));
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
+ IsUefiPageNotPresent (MemoryMapEntry) && IsUefiPageNotPresent (NextMemoryMapEntry) &&
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
+ {
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ if (NewMemoryMapEntry != MemoryMapEntry) {
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ continue;
+ } else {
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ break;
+ }
+ } while (TRUE);
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
+ }
+
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
+
+ return;
+}
+
+/**
+ This function caches the GCD memory map information.
+**/
+VOID
+GetGcdMemoryMap (
+ VOID
+ )
+{
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ mGcdMemNumberOfDesc = 0;
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&
+ ((MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))
+ )
+ {
+ mGcdMemNumberOfDesc++;
+ }
+ }
+
+ mGcdMemSpace = AllocateZeroPool (mGcdMemNumberOfDesc * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
+ ASSERT (mGcdMemSpace != NULL);
+ if (mGcdMemSpace == NULL) {
+ mGcdMemNumberOfDesc = 0;
+ gBS->FreePool (MemSpaceMap);
+ return;
+ }
+
+ mGcdMemNumberOfDesc = 0;
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&
+ ((MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
+ (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))
+ )
+ {
+ CopyMem (
+ &mGcdMemSpace[mGcdMemNumberOfDesc],
+ &MemSpaceMap[Index],
+ sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)
+ );
+ mGcdMemNumberOfDesc++;
+ }
+ }
+
+ gBS->FreePool (MemSpaceMap);
+}
+
+/**
+ Get UEFI MemoryAttributesTable.
+**/
+VOID
+GetUefiMemoryAttributesTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
+ UINTN MemoryAttributesTableSize;
+
+ Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
+ if (!EFI_ERROR (Status) && (MemoryAttributesTable != NULL)) {
+ MemoryAttributesTableSize = sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;
+ mUefiMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);
+ ASSERT (mUefiMemoryAttributesTable != NULL);
+ }
+}
+
+/**
+ This function caches the UEFI memory map information.
+**/
+VOID
+GetUefiMemoryMap (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN MapKey;
+ UINT32 DescriptorVersion;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN UefiMemoryMapSize;
+
+ DEBUG ((DEBUG_INFO, "GetUefiMemoryMap\n"));
+
+ UefiMemoryMapSize = 0;
+ MemoryMap = NULL;
+ Status = gBS->GetMemoryMap (
+ &UefiMemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &mUefiDescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ Status = gBS->AllocatePool (EfiBootServicesData, UefiMemoryMapSize, (VOID **)&MemoryMap);
+ ASSERT (MemoryMap != NULL);
+ if (MemoryMap == NULL) {
+ return;
+ }
+
+ Status = gBS->GetMemoryMap (
+ &UefiMemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &mUefiDescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (MemoryMap);
+ MemoryMap = NULL;
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ if (MemoryMap == NULL) {
+ return;
+ }
+
+ SortMemoryMap (MemoryMap, UefiMemoryMapSize, mUefiDescriptorSize);
+ MergeMemoryMapForNotPresentEntry (MemoryMap, &UefiMemoryMapSize, mUefiDescriptorSize);
+
+ mUefiMemoryMapSize = UefiMemoryMapSize;
+ mUefiMemoryMap = AllocateCopyPool (UefiMemoryMapSize, MemoryMap);
+ ASSERT (mUefiMemoryMap != NULL);
+
+ gBS->FreePool (MemoryMap);
+
+ //
+ // Get additional information from GCD memory map.
+ //
+ GetGcdMemoryMap ();
+
+ //
+ // Get UEFI memory attributes table.
+ //
+ GetUefiMemoryAttributesTable ();
+}
+
+/**
+ This function sets UEFI memory attribute according to UEFI memory map.
+
+ The normal memory region is marked as not present, such as
+ EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
+ EfiUnusableMemory, EfiACPIReclaimMemory.
+**/
+VOID
+SetUefiMemMapAttributes (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN MemoryMapEntryCount;
+ UINTN Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ BOOLEAN WriteProtect;
+ BOOLEAN CetEnabled;
+
+ PERF_FUNCTION_BEGIN ();
+
+ DEBUG ((DEBUG_INFO, "SetUefiMemMapAttributes\n"));
+
+ WRITE_UNPROTECT_RO_PAGES (WriteProtect, CetEnabled);
+
+ if (mUefiMemoryMap != NULL) {
+ MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
+ MemoryMap = mUefiMemoryMap;
+ for (Index = 0; Index < MemoryMapEntryCount; Index++) {
+ if (IsUefiPageNotPresent (MemoryMap)) {
+ Status = SmmSetMemoryAttributes (
+ MemoryMap->PhysicalStart,
+ EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
+ EFI_MEMORY_RP
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ "UefiMemory protection: 0x%lx - 0x%lx %r\n",
+ MemoryMap->PhysicalStart,
+ MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
+ Status
+ ));
+ }
+
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mUefiDescriptorSize);
+ }
+ }
+
+ //
+ // Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
+ //
+
+ //
+ // Set untested memory as not present.
+ //
+ if (mGcdMemSpace != NULL) {
+ for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {
+ Status = SmmSetMemoryAttributes (
+ mGcdMemSpace[Index].BaseAddress,
+ mGcdMemSpace[Index].Length,
+ EFI_MEMORY_RP
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ "GcdMemory protection: 0x%lx - 0x%lx %r\n",
+ mGcdMemSpace[Index].BaseAddress,
+ mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length,
+ Status
+ ));
+ }
+ }
+
+ //
+ // Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
+ //
+
+ //
+ // Set UEFI runtime memory with EFI_MEMORY_RO as not present.
+ //
+ if (mUefiMemoryAttributesTable != NULL) {
+ Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);
+ for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {
+ if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {
+ if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
+ Status = SmmSetMemoryAttributes (
+ Entry->PhysicalStart,
+ EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
+ EFI_MEMORY_RP
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ "UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
+ Entry->PhysicalStart,
+ Entry->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
+ Status
+ ));
+ }
+ }
+
+ Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);
+ }
+ }
+
+ WRITE_PROTECT_RO_PAGES (WriteProtect, CetEnabled);
+
+ //
+ // Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
+ //
+
+ PERF_FUNCTION_END ();
+}
+
+/**
+ Return if the Address is forbidden as SMM communication buffer.
+
+ @param[in] Address the address to be checked
+
+ @return TRUE The address is forbidden as SMM communication buffer.
+ @return FALSE The address is allowed as SMM communication buffer.
+**/
+BOOLEAN
+IsSmmCommBufferForbiddenAddress (
+ IN UINT64 Address
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN MemoryMapEntryCount;
+ UINTN Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+
+ if (mUefiMemoryMap != NULL) {
+ MemoryMap = mUefiMemoryMap;
+ MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
+ for (Index = 0; Index < MemoryMapEntryCount; Index++) {
+ if (IsUefiPageNotPresent (MemoryMap)) {
+ if ((Address >= MemoryMap->PhysicalStart) &&
+ (Address < MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages)))
+ {
+ return TRUE;
+ }
+ }
+
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mUefiDescriptorSize);
+ }
+ }
+
+ if (mGcdMemSpace != NULL) {
+ for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {
+ if ((Address >= mGcdMemSpace[Index].BaseAddress) &&
+ (Address < mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length))
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ if (mUefiMemoryAttributesTable != NULL) {
+ Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);
+ for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {
+ if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {
+ if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
+ if ((Address >= Entry->PhysicalStart) &&
+ (Address < Entry->PhysicalStart + LShiftU64 (Entry->NumberOfPages, EFI_PAGE_SHIFT)))
+ {
+ return TRUE;
+ }
+
+ Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
index 56349a771e..d18e9e85f8 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
@@ -46,6 +46,7 @@
SmmMp.c
SmmMpPerf.h
SmmMpPerf.c
+ NonMmramMapDxeSmm.c
[Sources.Ia32]
Ia32/PageTbl.c
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
index 4a1bab68dd..76eaaec981 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
@@ -7,25 +7,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "PiSmmCpuCommon.h"
-//
-// attributes for reserved memory before it is promoted to system memory
-//
-#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
-#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
-#define EFI_MEMORY_TESTED 0x0400000000000000ULL
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap;
-UINTN mUefiMemoryMapSize;
-UINTN mUefiDescriptorSize;
-
-EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace = NULL;
-UINTN mGcdMemNumberOfDesc = 0;
-
-EFI_MEMORY_ATTRIBUTES_TABLE *mUefiMemoryAttributesTable = NULL;
-
BOOLEAN mIsShadowStack = FALSE;
BOOLEAN m5LevelPagingNeeded = FALSE;
PAGING_MODE mPagingMode = PagingModeMax;
@@ -1119,464 +1100,6 @@ SetMemMapAttributes (
}
/**
- Sort memory map entries based upon PhysicalStart, from low to high.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-SortMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- EFI_MEMORY_DESCRIPTOR TempMemoryMap;
-
- MemoryMapEntry = MemoryMap;
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while (MemoryMapEntry < MemoryMapEnd) {
- while (NextMemoryMapEntry < MemoryMapEnd) {
- if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
- CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-}
-
-/**
- Return if a UEFI memory page should be marked as not present in SMM page table.
- If the memory map entries type is
- EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
- EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
- Or return FALSE.
-
- @param[in] MemoryMap A pointer to the memory descriptor.
-
- @return TRUE The memory described will be marked as not present in SMM page table.
- @return FALSE The memory described will not be marked as not present in SMM page table.
-**/
-BOOLEAN
-IsUefiPageNotPresent (
- IN EFI_MEMORY_DESCRIPTOR *MemoryMap
- )
-{
- switch (MemoryMap->Type) {
- case EfiLoaderCode:
- case EfiLoaderData:
- case EfiBootServicesCode:
- case EfiBootServicesData:
- case EfiConventionalMemory:
- case EfiUnusableMemory:
- case EfiACPIReclaimMemory:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-/**
- Merge continuous memory map entries whose type is
- EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
- EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
- these entries will be set as NOT present in SMM page table.
-
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-MergeMemoryMapForNotPresentEntry (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- UINT64 MemoryBlockLength;
- EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
-
- MemoryMapEntry = MemoryMap;
- NewMemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
-
- do {
- MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages));
- if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
- IsUefiPageNotPresent (MemoryMapEntry) && IsUefiPageNotPresent (NextMemoryMapEntry) &&
- ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
- {
- MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- if (NewMemoryMapEntry != MemoryMapEntry) {
- NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- continue;
- } else {
- MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- break;
- }
- } while (TRUE);
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
- }
-
- *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
-
- return;
-}
-
-/**
- This function caches the GCD memory map information.
-**/
-VOID
-GetGcdMemoryMap (
- VOID
- )
-{
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;
- EFI_STATUS Status;
- UINTN Index;
-
- Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
- if (EFI_ERROR (Status)) {
- return;
- }
-
- mGcdMemNumberOfDesc = 0;
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if ((MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&
- ((MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
- (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))
- )
- {
- mGcdMemNumberOfDesc++;
- }
- }
-
- mGcdMemSpace = AllocateZeroPool (mGcdMemNumberOfDesc * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
- ASSERT (mGcdMemSpace != NULL);
- if (mGcdMemSpace == NULL) {
- mGcdMemNumberOfDesc = 0;
- gBS->FreePool (MemSpaceMap);
- return;
- }
-
- mGcdMemNumberOfDesc = 0;
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if ((MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&
- ((MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
- (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))
- )
- {
- CopyMem (
- &mGcdMemSpace[mGcdMemNumberOfDesc],
- &MemSpaceMap[Index],
- sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)
- );
- mGcdMemNumberOfDesc++;
- }
- }
-
- gBS->FreePool (MemSpaceMap);
-}
-
-/**
- Get UEFI MemoryAttributesTable.
-**/
-VOID
-GetUefiMemoryAttributesTable (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
- UINTN MemoryAttributesTableSize;
-
- Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
- if (!EFI_ERROR (Status) && (MemoryAttributesTable != NULL)) {
- MemoryAttributesTableSize = sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;
- mUefiMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);
- ASSERT (mUefiMemoryAttributesTable != NULL);
- }
-}
-
-/**
- This function caches the UEFI memory map information.
-**/
-VOID
-GetUefiMemoryMap (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN MapKey;
- UINT32 DescriptorVersion;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- UINTN UefiMemoryMapSize;
-
- DEBUG ((DEBUG_INFO, "GetUefiMemoryMap\n"));
-
- UefiMemoryMapSize = 0;
- MemoryMap = NULL;
- Status = gBS->GetMemoryMap (
- &UefiMemoryMapSize,
- MemoryMap,
- &MapKey,
- &mUefiDescriptorSize,
- &DescriptorVersion
- );
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
-
- do {
- Status = gBS->AllocatePool (EfiBootServicesData, UefiMemoryMapSize, (VOID **)&MemoryMap);
- ASSERT (MemoryMap != NULL);
- if (MemoryMap == NULL) {
- return;
- }
-
- Status = gBS->GetMemoryMap (
- &UefiMemoryMapSize,
- MemoryMap,
- &MapKey,
- &mUefiDescriptorSize,
- &DescriptorVersion
- );
- if (EFI_ERROR (Status)) {
- gBS->FreePool (MemoryMap);
- MemoryMap = NULL;
- }
- } while (Status == EFI_BUFFER_TOO_SMALL);
-
- if (MemoryMap == NULL) {
- return;
- }
-
- SortMemoryMap (MemoryMap, UefiMemoryMapSize, mUefiDescriptorSize);
- MergeMemoryMapForNotPresentEntry (MemoryMap, &UefiMemoryMapSize, mUefiDescriptorSize);
-
- mUefiMemoryMapSize = UefiMemoryMapSize;
- mUefiMemoryMap = AllocateCopyPool (UefiMemoryMapSize, MemoryMap);
- ASSERT (mUefiMemoryMap != NULL);
-
- gBS->FreePool (MemoryMap);
-
- //
- // Get additional information from GCD memory map.
- //
- GetGcdMemoryMap ();
-
- //
- // Get UEFI memory attributes table.
- //
- GetUefiMemoryAttributesTable ();
-}
-
-/**
- This function sets UEFI memory attribute according to UEFI memory map.
-
- The normal memory region is marked as not present, such as
- EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
- EfiUnusableMemory, EfiACPIReclaimMemory.
-**/
-VOID
-SetUefiMemMapAttributes (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- UINTN MemoryMapEntryCount;
- UINTN Index;
- EFI_MEMORY_DESCRIPTOR *Entry;
- BOOLEAN WriteProtect;
- BOOLEAN CetEnabled;
-
- PERF_FUNCTION_BEGIN ();
-
- DEBUG ((DEBUG_INFO, "SetUefiMemMapAttributes\n"));
-
- WRITE_UNPROTECT_RO_PAGES (WriteProtect, CetEnabled);
-
- if (mUefiMemoryMap != NULL) {
- MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
- MemoryMap = mUefiMemoryMap;
- for (Index = 0; Index < MemoryMapEntryCount; Index++) {
- if (IsUefiPageNotPresent (MemoryMap)) {
- Status = SmmSetMemoryAttributes (
- MemoryMap->PhysicalStart,
- EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
- EFI_MEMORY_RP
- );
- DEBUG ((
- DEBUG_INFO,
- "UefiMemory protection: 0x%lx - 0x%lx %r\n",
- MemoryMap->PhysicalStart,
- MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
- Status
- ));
- }
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mUefiDescriptorSize);
- }
- }
-
- //
- // Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
- //
-
- //
- // Set untested memory as not present.
- //
- if (mGcdMemSpace != NULL) {
- for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {
- Status = SmmSetMemoryAttributes (
- mGcdMemSpace[Index].BaseAddress,
- mGcdMemSpace[Index].Length,
- EFI_MEMORY_RP
- );
- DEBUG ((
- DEBUG_INFO,
- "GcdMemory protection: 0x%lx - 0x%lx %r\n",
- mGcdMemSpace[Index].BaseAddress,
- mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length,
- Status
- ));
- }
- }
-
- //
- // Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
- //
-
- //
- // Set UEFI runtime memory with EFI_MEMORY_RO as not present.
- //
- if (mUefiMemoryAttributesTable != NULL) {
- Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);
- for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {
- if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {
- if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
- Status = SmmSetMemoryAttributes (
- Entry->PhysicalStart,
- EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
- EFI_MEMORY_RP
- );
- DEBUG ((
- DEBUG_INFO,
- "UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
- Entry->PhysicalStart,
- Entry->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
- Status
- ));
- }
- }
-
- Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);
- }
- }
-
- WRITE_PROTECT_RO_PAGES (WriteProtect, CetEnabled);
-
- //
- // Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
- //
-
- PERF_FUNCTION_END ();
-}
-
-/**
- Return if the Address is forbidden as SMM communication buffer.
-
- @param[in] Address the address to be checked
-
- @return TRUE The address is forbidden as SMM communication buffer.
- @return FALSE The address is allowed as SMM communication buffer.
-**/
-BOOLEAN
-IsSmmCommBufferForbiddenAddress (
- IN UINT64 Address
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- UINTN MemoryMapEntryCount;
- UINTN Index;
- EFI_MEMORY_DESCRIPTOR *Entry;
-
- if (mUefiMemoryMap != NULL) {
- MemoryMap = mUefiMemoryMap;
- MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
- for (Index = 0; Index < MemoryMapEntryCount; Index++) {
- if (IsUefiPageNotPresent (MemoryMap)) {
- if ((Address >= MemoryMap->PhysicalStart) &&
- (Address < MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages)))
- {
- return TRUE;
- }
- }
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mUefiDescriptorSize);
- }
- }
-
- if (mGcdMemSpace != NULL) {
- for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {
- if ((Address >= mGcdMemSpace[Index].BaseAddress) &&
- (Address < mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length))
- {
- return TRUE;
- }
- }
- }
-
- if (mUefiMemoryAttributesTable != NULL) {
- Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);
- for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {
- if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {
- if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
- if ((Address >= Entry->PhysicalStart) &&
- (Address < Entry->PhysicalStart + LShiftU64 (Entry->NumberOfPages, EFI_PAGE_SHIFT)))
- {
- return TRUE;
- }
-
- Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);
- }
- }
- }
- }
-
- return FALSE;
-}
-
-/**
This function set given attributes of the memory region specified by
BaseAddress and Length.