ChainloadApp hands the payload over on AArch64 with the MMU and caches
enabled, on translation tables it owns. ArmMmuLib allocates every level
of that hierarchy through MemoryAllocationLib::AllocatePages(), which
the stock UefiMemoryAllocationLib backs with EfiBootServicesData, and
the payload's memory-map HOB reports EfiBootServicesData as free RAM,
so DXE could allocate straight over the live hierarchy. The handover
itself arrives with a later change; its allocator is added first so
that it is reviewable on its own.

Add ReservedUefiMemoryAllocationLib, a per-module MemoryAllocationLib
override for ChainloadApp that redirects AllocatePages() to
EfiReservedMemoryType. Every page it hands out then sits in an
isolated Reserved descriptor in the outer
memory-map snapshot, never coalesces with adjacent conventional
memory, and the payload's HOB-memory search cannot select it. Pool
allocations stay EfiBootServicesData: they back short-lived buffers
(Print(), the memory-map snapshot) that are freed before the branch.
The library implements only the MemoryAllocationLib functions this
module links against; the runtime, aligned, copy and reallocate
variants are omitted.

The library also records the base and page count of every Reserved
page allocation it returns, in a 64-entry table; on overflow it warns
with DEBUG_WARN and the page stays Reserved. A later change publishes
those ranges to the payload as an explicit boot-time reservation list,
so the OS reclaims the pages instead of losing them to a Reserved
descriptor for the rest of the boot. We use Reserved for placement,
not lifetime: in a normal ArmMmuLib-based boot the table pages are
ordinary EfiBootServicesData and need not survive ExitBootServices().

Cc: Benjamin Doron <[email protected]>
Cc: Gua Guo <[email protected]>
Cc: Guo Dong <[email protected]>
Cc: James Lu <[email protected]>
Cc: Sean Rhodes <[email protected]>
Cc: Shuo Liu <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Sami Mujawar <[email protected]>
Cc: Vishal Oliyil Kunnnil <[email protected]>
Assisted-by: claude-opus-5
Signed-off-by: Alexander Graf <[email protected]>
---
 .../ReservedUefiMemoryAllocationLib.c         | 191 ++++++++++++++++++
 .../ReservedUefiMemoryAllocationLib.inf       |  32 +++
 UefiPayloadPkg/UefiPayloadPkg.dsc             |   7 +
 3 files changed, 230 insertions(+)
 create mode 100644 
UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.c
 create mode 100644 
UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.inf

diff --git a/UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.c 
b/UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.c
new file mode 100644
index 0000000000..0fc67aa14d
--- /dev/null
+++ b/UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.c
@@ -0,0 +1,191 @@
+/** @file

+  MemoryAllocationLib instance that keeps ArmMmuLib's translation-table

+  pages as EfiReservedMemoryType.

+

+  ChainloadApp installs its own translation tables via

+  ArmConfigureMmu() while the outer firmware is still running, so

+  that the payload can be entered with the MMU and caches enabled.

+  ArmMmuLib allocates every level of that hierarchy through

+  MemoryAllocationLib::AllocatePages(), which the stock

+  UefiMemoryAllocationLib backs with EfiBootServicesData.  After

+  ExitBootServices() the payload's memory-map HOB reports

+  EfiBootServicesData as free RAM, so DXE could allocate over the

+  live tables.  Overriding AllocatePages() to EfiReservedMemoryType

+  keeps every table page in an isolated Reserved descriptor in the

+  outer memory-map snapshot, so it never coalesces with adjacent

+  conventional memory and the payload's HOB-memory search cannot

+  select it.  Every Reserved page allocation is also recorded so

+  ChainloadApp can hand the payload an explicit list of boot-time

+  reservations for it to publish as SYSTEM_MEMORY pinned by an

+  EfiBootServicesData allocation HOB, letting the OS reclaim the

+  table pages after it has installed its own translation.

+

+  Only AllocatePages() is redirected.  Pool allocations remain

+  EfiBootServicesData: they back short-lived buffers (Print(), the

+  memory-map snapshot) that are freed before the branch and never

+  carried across the handoff.  The library implements only the

+  MemoryAllocationLib functions this module links against; the

+  runtime, aligned, copy and reallocate variants are omitted.

+

+  Copyright (c) 2026, Amazon.com, Inc. or its affiliates. All Rights 
Reserved.<BR>

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+**/

+

+#include <Uefi.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+

+//

+// Every Reserved page allocation this library returns is recorded so

+// that ChainloadApp can hand the payload an explicit list of the

+// launcher's own boot-time-only reservations (the translation-table

+// pages ArmMmuLib allocates through here, in addition to the FV, HOB

+// list and stack ChainloadApp allocates itself).  The library is a

+// per-module override for ChainloadApp only, so exporting these as

+// plain globals is sufficient; there is no MemoryAllocationLib

+// interface for it.

+//

+#define RESERVED_PAGE_ALLOC_MAX  64

+

+EFI_PHYSICAL_ADDRESS  gReservedPageAllocBase[RESERVED_PAGE_ALLOC_MAX];

+UINTN                 gReservedPageAllocPages[RESERVED_PAGE_ALLOC_MAX];

+UINTN                 gReservedPageAllocCount;

+

+STATIC

+VOID

+RecordReservedPageAlloc (

+  IN EFI_PHYSICAL_ADDRESS  Base,

+  IN UINTN                 Pages

+  )

+{

+  if (gReservedPageAllocCount < RESERVED_PAGE_ALLOC_MAX) {

+    gReservedPageAllocBase[gReservedPageAllocCount]  = Base;

+    gReservedPageAllocPages[gReservedPageAllocCount] = Pages;

+    gReservedPageAllocCount++;

+  } else {

+    DEBUG ((

+      DEBUG_WARN,

+      "%a: table full at 0x%Lx (%u pages); page stays Reserved and is "

+      "not reclaimed to the OS\n",

+      __func__,

+      (UINT64)Base,

+      (UINT32)Pages

+      ));

+  }

+}

+

+STATIC

+VOID *

+InternalAllocatePages (

+  IN EFI_MEMORY_TYPE  MemoryType,

+  IN UINTN            Pages

+  )

+{

+  EFI_STATUS            Status;

+  EFI_PHYSICAL_ADDRESS  Memory;

+

+  if (Pages == 0) {

+    return NULL;

+  }

+

+  Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);

+  if (EFI_ERROR (Status)) {

+    return NULL;

+  }

+

+  if (MemoryType == EfiReservedMemoryType) {

+    RecordReservedPageAlloc (Memory, Pages);

+  }

+

+  return (VOID *)(UINTN)Memory;

+}

+

+VOID *

+EFIAPI

+AllocatePages (

+  IN UINTN  Pages

+  )

+{

+  return InternalAllocatePages (EfiReservedMemoryType, Pages);

+}

+

+VOID

+EFIAPI

+FreePages (

+  IN VOID   *Buffer,

+  IN UINTN  Pages

+  )

+{

+  EFI_STATUS  Status;

+

+  ASSERT (Pages != 0);

+  Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Pages);

+  ASSERT_EFI_ERROR (Status);

+}

+

+STATIC

+VOID *

+InternalAllocatePool (

+  IN EFI_MEMORY_TYPE  MemoryType,

+  IN UINTN            AllocationSize

+  )

+{

+  EFI_STATUS  Status;

+  VOID        *Memory;

+

+  Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);

+  if (EFI_ERROR (Status)) {

+    Memory = NULL;

+  }

+

+  return Memory;

+}

+

+VOID *

+EFIAPI

+AllocatePool (

+  IN UINTN  AllocationSize

+  )

+{

+  return InternalAllocatePool (EfiBootServicesData, AllocationSize);

+}

+

+STATIC

+VOID *

+InternalAllocateZeroPool (

+  IN EFI_MEMORY_TYPE  PoolType,

+  IN UINTN            AllocationSize

+  )

+{

+  VOID  *Memory;

+

+  Memory = InternalAllocatePool (PoolType, AllocationSize);

+  if (Memory != NULL) {

+    ZeroMem (Memory, AllocationSize);

+  }

+

+  return Memory;

+}

+

+VOID *

+EFIAPI

+AllocateZeroPool (

+  IN UINTN  AllocationSize

+  )

+{

+  return InternalAllocateZeroPool (EfiBootServicesData, AllocationSize);

+}

+

+VOID

+EFIAPI

+FreePool (

+  IN VOID  *Buffer

+  )

+{

+  EFI_STATUS  Status;

+

+  Status = gBS->FreePool (Buffer);

+  ASSERT_EFI_ERROR (Status);

+}

diff --git a/UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.inf 
b/UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.inf
new file mode 100644
index 0000000000..4cba2796aa
--- /dev/null
+++ b/UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.inf
@@ -0,0 +1,32 @@
+## @file

+#  MemoryAllocationLib whose page allocations are EfiReservedMemoryType.

+#

+#  Overrides UefiMemoryAllocationLib for ChainloadApp so that the

+#  translation-table pages ArmMmuLib allocates through AllocatePages()

+#  are Reserved and each allocation is recorded for ChainloadApp to

+#  publish as a boot-time reservation.  Pool allocations remain

+#  EfiBootServicesData.

+#

+#  Copyright (c) 2026, Amazon.com, Inc. or its affiliates. All Rights 
Reserved.<BR>

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = ReservedUefiMemoryAllocationLib

+  FILE_GUID                      = 4e4b7c1d-6a34-4a02-9c8e-9c9e9d0e0aa1

+  MODULE_TYPE                    = UEFI_APPLICATION

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = MemoryAllocationLib|UEFI_APPLICATION

+

+[Sources]

+  ReservedUefiMemoryAllocationLib.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  UefiBootServicesTableLib

diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc 
b/UefiPayloadPkg/UefiPayloadPkg.dsc
index 3f5e2661a4..b6306ac7c3 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -1403,4 +1403,11 @@
       # Route DEBUG() through the outer firmware's ConOut instead.

       #

       DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

+      #

+      # ArmMmuLib allocates translation-table pages via

+      # MemoryAllocationLib::AllocatePages().  Redirect those to

+      # EfiReservedMemoryType so the payload's memory-map HOB reports

+      # them as Reserved and DXE cannot allocate over the live tables.

+      #

+      
MemoryAllocationLib|UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.inf

   }

-- 
2.47.3



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#122100): https://edk2.groups.io/g/devel/message/122100
Mute This Topic: https://groups.io/mt/120797293/21656
Group Owner: [email protected]
Unsubscribe: https://edk2.groups.io/g/devel/unsub [[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to