public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Min Xu" <min.m.xu@intel.com>
To: devel@edk2.groups.io
Cc: Jiaqi Gao <jiaqi.gao@intel.com>,
	Jian J Wang <jian.j.wang@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Dandan Bi <dandan.bi@intel.com>,
	Erdem Aktas <erdemaktas@google.com>,
	James Bottomley <jejb@linux.ibm.com>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	Gerd Hoffmann <kraxel@redhat.com>, Min Xu <min.m.xu@intel.com>
Subject: [PATCH V2 14/14] MdeModulePkg: Pool and page functions accept memory when OOM occurs
Date: Sat, 27 Aug 2022 14:21:21 +0800	[thread overview]
Message-ID: <a9f9178ddc8704e66b205cc759da41f52cd868e7.1661579220.git.min.m.xu@intel.com> (raw)
In-Reply-To: <cover.1661579220.git.min.m.xu@intel.com>

From: Jiaqi Gao <jiaqi.gao@intel.com>

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3937

When CoreAllocatePages() / CoreAllocatePool() meets error of
EFI_OUT_OF_RESOURCES, locate the EdkiiMemoryAcceptProtocol and accept extra
memory dynamically.

Firstly, find the unaccpeted memory region with enough size in GCD
entries. Then locate the EdkiiMemoryAcceptProtocol and accept the memory.
Finally, update the GCD memory and gMemoryMap entries.

After updating the memory infomation, CoreInternalAllocatePages() /
CoreInternalAllocatePool() will be recalled to allocate pages / pool.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Jiaqi Gao <jiaqi.gao@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/Core/Dxe/DxeMain.inf |   1 +
 MdeModulePkg/Core/Dxe/Mem/Imem.h  |  16 +++
 MdeModulePkg/Core/Dxe/Mem/Page.c  | 190 ++++++++++++++++++++++++++++++
 MdeModulePkg/Core/Dxe/Mem/Pool.c  |  14 +++
 4 files changed, 221 insertions(+)

diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index e4bca895773d..371ba45357be 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -169,6 +169,7 @@
   gEfiVariableArchProtocolGuid                  ## CONSUMES
   gEfiCapsuleArchProtocolGuid                   ## CONSUMES
   gEfiWatchdogTimerArchProtocolGuid             ## CONSUMES
+  gEdkiiMemoryAcceptProtocolGuid                ## CONSUMES
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber    ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Core/Dxe/Mem/Imem.h b/MdeModulePkg/Core/Dxe/Mem/Imem.h
index 2f0bf2bf631f..22e0d0e44030 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Imem.h
+++ b/MdeModulePkg/Core/Dxe/Mem/Imem.h
@@ -47,6 +47,22 @@ typedef struct {
 // Internal prototypes
 //
 
+/**
+  Internal function.  Used by the pool and page functions to accept memory
+  when OOM occurs.
+
+  @param  Type                   The type of allocation to perform.
+  @param  AcceptSize             Size of memory to be accepted.
+  @param  Memory                 Accept memory address
+
+**/
+EFI_STATUS
+AcceptMemoryResource (
+  IN EFI_ALLOCATE_TYPE         Type,
+  IN UINTN                     AcceptSize,
+  IN OUT EFI_PHYSICAL_ADDRESS  *Memory
+  );
+
 /**
   Internal function.  Used by the pool functions to allocate pages
   to back pool allocation requests.
diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c
index 160289c1f9ec..513792a7fe04 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Page.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Page.c
@@ -10,6 +10,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include "Imem.h"
 #include "HeapGuard.h"
 #include <Pi/PrePiDxeCis.h>
+#include <Protocol/MemoryAccept.h>
 
 //
 // Entry for tracking the memory regions for each memory type to coalesce similar memory types
@@ -379,6 +380,176 @@ CoreFreeMemoryMapStack (
   mFreeMapStack -= 1;
 }
 
+/**
+  Used to accept memory when OOM occurs.
+
+  @param  Type                   The type of allocation to perform.
+  @param  AcceptSize             Size of memory to be accepted.
+  @param  Memory                 Accept memory address
+
+**/
+EFI_STATUS
+AcceptMemoryResource (
+  IN EFI_ALLOCATE_TYPE         Type,
+  IN UINTN                     AcceptSize,
+  IN OUT EFI_PHYSICAL_ADDRESS  *Memory
+  )
+{
+ #ifdef MDE_CPU_X64
+
+  LIST_ENTRY                    *Link;
+  EFI_GCD_MAP_ENTRY             *GcdEntry;
+  EFI_GCD_MAP_ENTRY             UnacceptedEntry;
+  EDKII_MEMORY_ACCEPT_PROTOCOL  *MemoryAcceptProtocol;
+  UINTN                         Start;
+  UINTN                         End;
+  EFI_STATUS                    Status;
+
+  //
+  // We accept n*32MB at one time to improve the efficiency.
+  //
+  AcceptSize = (AcceptSize + SIZE_32MB - 1) & ~(SIZE_32MB - 1);
+
+  if (AcceptSize == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = gBS->LocateProtocol (&gEdkiiMemoryAcceptProtocolGuid, NULL, (VOID **)&MemoryAcceptProtocol);
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (Type == AllocateAddress) {
+    Start = *Memory;
+    End   = *Memory + AcceptSize;
+  }
+
+  if (Type == AllocateMaxAddress) {
+    if (*Memory < EFI_PAGE_MASK) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if ((*Memory & EFI_PAGE_MASK) != EFI_PAGE_MASK) {
+      //
+      // Change MaxAddress to be 1 page lower
+      //
+      *Memory -= EFI_PAGE_SIZE;
+
+      //
+      // Set MaxAddress to a page boundary
+      //
+      *Memory &= ~(UINT64)EFI_PAGE_MASK;
+
+      //
+      // Set MaxAddress to end of the page
+      //
+      *Memory |= EFI_PAGE_MASK;
+    }
+  }
+
+  //
+  // Traverse the mGcdMemorySpaceMap to find out the unaccepted
+  // memory entry with big enough size.
+  //
+  Link = mGcdMemorySpaceMap.ForwardLink;
+  while (Link != &mGcdMemorySpaceMap) {
+    GcdEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
+    if (GcdEntry->GcdMemoryType == EFI_GCD_MEMORY_TYPE_UNACCEPTED) {
+      if (Type == AllocateMaxAddress) {
+        if (GcdEntry->BaseAddress + AcceptSize - 1 > *Memory) {
+          Link = Link->ForwardLink;
+          continue;
+        }
+      } else if (Type == AllocateAddress) {
+        if ((GcdEntry->BaseAddress > *Memory) || (GcdEntry->EndAddress < *Memory + AcceptSize - 1)) {
+          Link = Link->ForwardLink;
+          continue;
+        }
+      }
+
+      //
+      // Is the entry big enough?
+      //
+      if (AcceptSize <= GcdEntry->EndAddress - GcdEntry->BaseAddress + 1) {
+        UnacceptedEntry = *GcdEntry;
+        if (Type != AllocateAddress) {
+          Start = UnacceptedEntry.BaseAddress;
+          End   = UnacceptedEntry.BaseAddress + AcceptSize - 1;
+        }
+
+        break;
+      }
+    }
+
+    Link = Link->ForwardLink;
+  }
+
+  if (Link == &mGcdMemorySpaceMap) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Accept memory using the interface provide by the protocol.
+  //
+  Status = MemoryAcceptProtocol->AcceptMemory (MemoryAcceptProtocol, Start, AcceptSize);
+  if (EFI_ERROR (Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // If memory is accepted successfully, remove the target memory space from GCD.
+  //
+  CoreRemoveMemorySpace (UnacceptedEntry.BaseAddress, UnacceptedEntry.EndAddress - UnacceptedEntry.BaseAddress + 1);
+
+  //
+  // Add the remain lower part of unaccepted memory to the
+  // Gcd memory space and memory map.
+  //
+  if (Start > UnacceptedEntry.BaseAddress) {
+    CoreAddMemorySpace (
+      EFI_GCD_MEMORY_TYPE_UNACCEPTED,
+      UnacceptedEntry.BaseAddress,
+      Start - UnacceptedEntry.BaseAddress,
+      UnacceptedEntry.Capabilities
+      );
+  }
+
+  //
+  // Update accepted part of the memory entry to type of EfiGcdMemoryTypeSystemMemory
+  // and add the range to the memory map.
+  //
+  CoreAddMemorySpace (
+    EfiGcdMemoryTypeSystemMemory,
+    Start,
+    AcceptSize,
+    //
+    // Hardcode memory space attributes.
+    //
+    EFI_MEMORY_CPU_CRYPTO | EFI_MEMORY_XP | EFI_MEMORY_RO | EFI_MEMORY_RP
+    );
+
+  //
+  // Add the remain higher part of unaccepted memory to the
+  // Gcd memory space and memory map.
+  //
+  if (UnacceptedEntry.EndAddress > End) {
+    CoreAddMemorySpace (
+      EFI_GCD_MEMORY_TYPE_UNACCEPTED,
+      End + 1,
+      UnacceptedEntry.EndAddress - End,
+      UnacceptedEntry.Capabilities
+      );
+  }
+
+  return EFI_SUCCESS;
+
+ #else
+
+  return EFI_UNSUPPORTED;
+
+ #endif
+}
+
 /**
   Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.
 
@@ -1486,6 +1657,25 @@ CoreAllocatePages (
                 Memory,
                 NeedGuard
                 );
+ #ifdef MDE_CPU_X64
+
+  if (Status == EFI_OUT_OF_RESOURCES) {
+    Status = AcceptMemoryResource (Type, NumberOfPages << EFI_PAGE_SHIFT, Memory);
+    if (!EFI_ERROR (Status)) {
+      Status = CoreInternalAllocatePages (
+                 Type,
+                 MemoryType,
+                 NumberOfPages,
+                 Memory,
+                 NeedGuard
+                 );
+    } else {
+      Status = EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+ #endif
+
   if (!EFI_ERROR (Status)) {
     CoreUpdateProfile (
       (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
diff --git a/MdeModulePkg/Core/Dxe/Mem/Pool.c b/MdeModulePkg/Core/Dxe/Mem/Pool.c
index 7aaf501600cf..9e8c8611c1ef 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Pool.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Pool.c
@@ -273,6 +273,20 @@ CoreAllocatePool (
   EFI_STATUS  Status;
 
   Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
+
+ #ifdef MDE_CPU_X64
+
+  if (Status == EFI_OUT_OF_RESOURCES) {
+    Status = AcceptMemoryResource (AllocateAnyPages, Size, NULL);
+    if (!EFI_ERROR (Status)) {
+      Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
+    } else {
+      Status = EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+ #endif
+
   if (!EFI_ERROR (Status)) {
     CoreUpdateProfile (
       (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
-- 
2.29.2.windows.2


  parent reply	other threads:[~2022-08-27  6:22 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-27  6:21 [PATCH V2 00/14] Introduce Lazy-accept for Tdx guest Min Xu
2022-08-27  6:21 ` [PATCH V2 01/14] MdeModulePkg: Add PrePiHob.h Min Xu
2022-09-01 15:47   ` Gerd Hoffmann
2022-09-01 23:34     ` Min Xu
2022-09-04 11:34     ` Min Xu
2022-09-07  5:30       ` Gerd Hoffmann
2022-09-07 23:56         ` [edk2-devel] " Min Xu
2022-08-27  6:21 ` [PATCH V2 02/14] MdePkg: Increase EFI_RESOURCE_MAX_MEMORY_TYPE Min Xu
2022-08-27  6:21 ` [PATCH V2 03/14] OvmfPkg: Use EFI_RESOURCE_MEMORY_UNACCEPTED which defined in MdeModulePkg Min Xu
2022-08-27  6:21 ` [PATCH V2 04/14] MdePkg: Add UEFI Unaccepted memory definition Min Xu
2022-08-27  6:21 ` [PATCH V2 05/14] MdeModulePkg: Update Dxe to handle unaccepted memory type Min Xu
2022-08-27  6:21 ` [PATCH V2 06/14] ShellPkg: Update shell command memmap to show unaccepted memory Min Xu
2022-09-01 15:50   ` Gerd Hoffmann
2022-08-27  6:21 ` [PATCH V2 07/14] OvmfPkg: Add PCD and DEFINEs for Lazy Accept page Min Xu
2022-09-01 15:56   ` Gerd Hoffmann
2022-09-01 23:33     ` [edk2-devel] " Min Xu
2022-09-02  5:30       ` Gerd Hoffmann
2022-08-27  6:21 ` [PATCH V2 08/14] OvmfPkg: Add MaxAcceptedMemoryAddress in TDX work area Min Xu
2022-08-27  6:21 ` [PATCH V2 09/14] OvmfPkg: Introduce lazy accept in PlatformInitLib and PlatformPei Min Xu
2022-08-27  6:21 ` [PATCH V2 10/14] OvmfPkg: Update ConstructFwHobList for lazy accept Min Xu
2022-08-27  6:21 ` [PATCH V2 11/14] MdePkg: The prototype definition of EdkiiMemoryAcceptProtocol Min Xu
2022-09-01 15:57   ` Gerd Hoffmann
2022-08-27  6:21 ` [PATCH V2 12/14] OvmfPkg: Realize EdkiiMemoryAcceptProtocol in TdxDxe Min Xu
2022-09-01 15:58   ` Gerd Hoffmann
2022-08-27  6:21 ` [PATCH V2 13/14] OvmfPkg: Call gEdkiiMemoryAcceptProtocolGuid to accept pages Min Xu
2022-09-01 15:59   ` Gerd Hoffmann
2022-08-27  6:21 ` Min Xu [this message]
2022-08-29 20:47   ` [PATCH V2 14/14] MdeModulePkg: Pool and page functions accept memory when OOM occurs Lendacky, Thomas
2022-08-30  0:29     ` [edk2-devel] " Ni, Ray
2022-08-30  6:00       ` Min Xu
2022-08-30  6:14         ` Ni, Ray
2022-08-30  6:35           ` Min Xu
2022-08-30  7:12             ` Ni, Ray
2022-08-30  7:30               ` Min Xu
2022-08-30  7:43                 ` Ni, Ray
2022-08-30  8:08                   ` Min Xu
2022-08-30  9:28                     ` Ni, Ray
     [not found]                 ` <17100F9FBCB0C570.28430@groups.io>
2022-08-30  7:47                   ` Ni, Ray
2022-08-30  3:20     ` Min Xu
2022-08-30 14:24       ` Lendacky, Thomas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a9f9178ddc8704e66b205cc759da41f52cd868e7.1661579220.git.min.m.xu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox