When a UEFI payload is chainloaded from an outer UEFI firmware, the
memory the OS sees as available after ExitBootServices() should be
essentially the same as when the OS boots directly on the outer
firmware. Today it is not: on AArch64, -m 2G, the same memory-map probe
under the payload sees 9,528 KiB less usable memory than a direct boot,
and that whole difference is one EfiReservedMemoryType descriptor
covering the launcher's own payload FV, HOB list, initial stack and
translation-table pages.

None of those need to survive past the OS's ExitBootServices():
DxeCore loads every driver out of the FV into its own pages, the
launcher's HOB list is dead once UefiPayloadEntry has rebuilt the HOB
list, the launcher's stack is dead once HandOffToDxeCore() has switched
to its own, and firmware translation tables are the same
EfiBootServicesData in a normal ArmMmuLib-based boot. They are Reserved
only so that they stay isolated in the outer memory-map snapshot and
are never selected as free RAM by the payload's HOB-memory search.

Introduce a gLoaderBootTimeReservationGuid HOB carrying every such
range. ChainloadApp records the FV, HOB list and stack directly, and
the translation-table pages via ReservedUefiMemoryAllocationLib, which
backs every ArmMmuLib page allocation and records each Reserved page it
hands out. Any Reserved outer-map descriptor whose whole span is
covered by recorded reservations is emitted as SBL type 1 (RAM) so the
payload publishes it as EFI_RESOURCE_SYSTEM_MEMORY, and the GUID HOB is
emitted alongside.

The reservation list is a separate GUID HOB and not a bit in the
existing MEMORY_MAP_ENTRY.Flag byte because the pinned ranges do not,
in general, coincide with memory-map descriptor boundaries: a
reservation can be a page-sized allocation inside a much larger
descriptor of a different type, and a Flag bit on that descriptor
cannot express "pin these two pages of this range". A per-range list is
required; the consumer rejects any Revision it does not understand.

UefiPayloadEntry consumes the HOB before choosing HobMemBase and
excludes any candidate that overlaps a listed range; after the HOB list
is rebuilt, BuildGenericHob() pins every listed range with an
EfiBootServicesData memory-allocation HOB.
CoreInitializeMemoryServices()' FindLargestFreeRegion() and
CoreInitializeGcdServices()' memory-allocation-HOB walk both honour
those pins, so DXE never allocates over the launcher's live FV, stack
or page tables and the OS reclaims them after ExitBootServices(). A
launcher that emits no such HOB (Slim Bootloader, coreboot) sees no
change: the count is 0 and the existing paths run as before.

Measured on the AArch64 -m 2G reference platform, with the
translation-table handover in place:

  Reserved     50,680 -> 41,152 KiB    (-9,528 KiB)
  Usable-to-OS 2,068,068 -> 2,077,596 KiB (+9,528 KiB)

The IsReservedInMemoryMap() assertion is unchanged: the allocations are
still EfiReservedMemoryType in the outer memory map, and that is what
keeps them from coalescing with adjacent conventional memory into a
range large enough to be selected as HOB memory before any allocation
HOB is honoured.

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]>
Assisted-by: claude-opus-5
Signed-off-by: Alexander Graf <[email protected]>
---
 UefiPayloadPkg/ChainloadApp/ChainloadApp.c    | 204 ++++++++++++++++--
 UefiPayloadPkg/ChainloadApp/ChainloadApp.inf  |   1 +
 .../Include/Guid/BootTimeReservationGuid.h    |  53 +++++
 .../UefiPayloadEntry/UefiPayloadEntry.c       | 151 +++++++++++++
 .../UefiPayloadEntry/UefiPayloadEntry.inf     |   1 +
 UefiPayloadPkg/UefiPayloadPkg.dec             |   1 +
 UefiPayloadPkg/UefiPayloadPkg.dsc             |   7 +-
 7 files changed, 399 insertions(+), 19 deletions(-)
 create mode 100644 UefiPayloadPkg/Include/Guid/BootTimeReservationGuid.h

diff --git a/UefiPayloadPkg/ChainloadApp/ChainloadApp.c 
b/UefiPayloadPkg/ChainloadApp/ChainloadApp.c
index 77c19d12e2..029d56e4aa 100644
--- a/UefiPayloadPkg/ChainloadApp/ChainloadApp.c
+++ b/UefiPayloadPkg/ChainloadApp/ChainloadApp.c
@@ -40,6 +40,7 @@
 #include <UniversalPayload/ExtraData.h>

 #include <UniversalPayload/SmbiosTable.h>

 #include <UniversalPayload/AcpiTable.h>

+#include <Guid/BootTimeReservationGuid.h>

 

 //

 // PciBarFixup.c: program endpoint BARs the outer firmware left at

@@ -82,6 +83,26 @@ FixupUnassignedBars (
 #define PAYLOAD_STACK_PAGES  4

 #define PAYLOAD_STACK_SIZE   (EFI_PAGES_TO_SIZE (PAYLOAD_STACK_PAGES))

 

+//

+// Boot-time-only reservations: the FV copy, the HOB list buffer, the

+// payload's initial stack and, on AArch64, every translation-table

+// page.  All are allocated as EfiReservedMemoryType so they appear as

+// isolated Reserved records in the outer memory-map snapshot and are

+// therefore never selected as free RAM by the payload's HOB-memory

+// search; but none of them needs to survive past the OS's

+// ExitBootServices(), so they are handed to the payload in a

+// gLoaderBootTimeReservationGuid HOB and the payload publishes each as

+// SYSTEM_MEMORY pinned by an EfiBootServicesData memory-allocation

+// HOB.  The bound comfortably covers the FV/HOB/stack plus every

+// translation-table page ArmMmuLib may allocate for the outer GCD

+// map; on X64 no page tables are recorded and only three entries are

+// used.

+//

+#define MAX_BOOT_TIME_RESERVATIONS  128

+

+STATIC LOADER_BOOT_TIME_RESERVATION_ENTRY  
mBootTimeReservation[MAX_BOOT_TIME_RESERVATIONS];

+STATIC UINTN                               mBootTimeReservationCount;

+

 //

 // A single HOB's length is UINT16 and must be 8-byte aligned (PI 5.2).

 // The largest data payload a GUID HOB can therefore carry:

@@ -232,6 +253,91 @@ EmitGuidHob (
   return GuidHob + 1;

 }

 

+/**

+  Record one boot-time-only reservation for the

+  gLoaderBootTimeReservationGuid HOB.

+

+  @param[in] Base  Physical base of the allocation.

+  @param[in] Size  Size in bytes (page-aligned).

+**/

+STATIC

+VOID

+RecordBootTimeReservation (

+  IN EFI_PHYSICAL_ADDRESS  Base,

+  IN UINT64                Size

+  )

+{

+  if (mBootTimeReservationCount >= MAX_BOOT_TIME_RESERVATIONS) {

+    //

+    // Overflow means some reservations stay Reserved forever.  That

+    // is only a memory-parity loss, not a correctness problem, so a

+    // diagnostic is enough.

+    //

+    Print (

+      L"ChainloadApp: boot-time reservation table full at 0x%lx\n",

+      Base

+      );

+    return;

+  }

+

+  mBootTimeReservation[mBootTimeReservationCount].Base = Base;

+  mBootTimeReservation[mBootTimeReservationCount].Size = Size;

+  mBootTimeReservationCount++;

+}

+

+/**

+  Return whether a Reserved outer memory-map descriptor is entirely

+  covered by the recorded boot-time reservations.

+

+  The four allocations are made back to back with AllocateMaxAddress

+  and, on AArch64, AllocateAnyPages, so the outer memory map typically

+  reports one coalesced EfiReservedMemoryType descriptor covering all

+  of them; but no assumption is made about that: any Reserved

+  descriptor whose whole span lies inside recorded reservations is

+  reclassified.  A partial overlap is left as Reserved.

+

+  @param[in] Base  Descriptor start.

+  @param[in] End   Descriptor end (exclusive).

+

+  @retval TRUE   Every page in [Base,End) is a recorded reservation.

+  @retval FALSE  At least one page is not.

+**/

+STATIC

+BOOLEAN

+IsBootTimeReservation (

+  IN EFI_PHYSICAL_ADDRESS  Base,

+  IN EFI_PHYSICAL_ADDRESS  End

+  )

+{

+  EFI_PHYSICAL_ADDRESS  Cursor;

+  UINTN                 Index;

+  BOOLEAN               Advanced;

+

+  if (mBootTimeReservationCount == 0) {

+    return FALSE;

+  }

+

+  Cursor = Base;

+  while (Cursor < End) {

+    Advanced = FALSE;

+    for (Index = 0; Index < mBootTimeReservationCount; Index++) {

+      if ((Cursor >= mBootTimeReservation[Index].Base) &&

+          (Cursor < (mBootTimeReservation[Index].Base + 
mBootTimeReservation[Index].Size)))

+      {

+        Cursor   = mBootTimeReservation[Index].Base + 
mBootTimeReservation[Index].Size;

+        Advanced = TRUE;

+        break;

+      }

+    }

+

+    if (!Advanced) {

+      return FALSE;

+    }

+  }

+

+  return TRUE;

+}

+

 /**

   Translate an EFI_MEMORY_TYPE from the outer firmware's memory map into

   the SBL memory-map HOB Type and Flag fields.

@@ -593,11 +699,13 @@ IsReservedInMemoryMap (
   The FV image, HOB list buffer, payload stack and (on AArch64) the

   translation-table pages are allocated as EfiReservedMemoryType

   before the caller takes its memory-map snapshot, so the snapshot

-  already describes all of them and EfiTypeToSblEntry()

-  maps them to SBL type 2 (Reserved); the payload's free-memory search

-  therefore cannot select them.  No separate records are injected for

-  them, and this function asserts that the snapshot really does report

-  them as Reserved.

+  already describes all of them.  This function asserts that the

+  snapshot really does report them as Reserved, then reclassifies

+  those Reserved records to SBL type 1 (RAM) and emits a

+  gLoaderBootTimeReservationGuid HOB naming them, so the payload

+  publishes them as EFI_RESOURCE_SYSTEM_MEMORY pinned by an

+  EfiBootServicesData allocation HOB and the OS reclaims them after

+  ExitBootServices().

 

   @param[in] HobList         Pre-allocated HOB list buffer (Reserved memory).

   @param[in] HobBufSize      Size of HobList in bytes.

@@ -642,6 +750,7 @@ BuildPayloadHobList (
   UNIVERSAL_PAYLOAD_EXTRA_DATA        *ExtraData;

   UNIVERSAL_PAYLOAD_SMBIOS_TABLE      *SmbiosHob;

   UNIVERSAL_PAYLOAD_ACPI_TABLE        *AcpiHob;

+  LOADER_BOOT_TIME_RESERVATION        *BootTimeRes;

   SERIAL_PORT_INFO                    *SblSerial;

   UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO  *UplSerial;

   UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO  Serial;

@@ -743,15 +852,18 @@ BuildPayloadHobList (
   // SBL memory-map GUID HOB.  The FV image, HOB list buffer, payload

   // stack and (on AArch64) the translation-table pages were allocated

   // as EfiReservedMemoryType before the caller took its snapshot, so

-  // the snapshot already reports all of them and

-  // EfiTypeToSblEntry() maps them to SBL type 2 (Reserved).  Emitting

-  // separate records for them would produce exact duplicates:

-  // MemInfoCallbackMmio() in the payload calls

-  // BuildResourceDescriptorHob() once per record with no dedup and no

-  // overlap check, so on X64 the second copy is silently rejected by

-  // CoreInternalAddMemorySpace() and on AArch64 ConfigureMmuFromHobs()

-  // builds overlapping region descriptors from it.  Assert the

-  // expectation rather than adding a second copy.

+  // the snapshot reports them as one or more Reserved descriptors.

+  // Allocating them Reserved keeps them from coalescing with adjacent

+  // conventional memory in the outer memory map, so each Reserved

+  // descriptor covering only launcher allocations stays smaller than

+  // PcdSystemMemoryUefiRegionSize and FindFreeMemForHobCallback()

+  // never selects it; the payload additionally excludes ranges the

+  // gLoaderBootTimeReservationGuid HOB names.  Below, any Reserved

+  // descriptor entirely covered by recorded boot-time reservations is

+  // reclassified to SBL type 1 (RAM), so the payload publishes it as

+  // EFI_RESOURCE_SYSTEM_MEMORY, pins it with an EfiBootServicesData

+  // memory-allocation HOB, and the OS reclaims it after

+  // ExitBootServices().

   //

   // The GCD MMIO regions are recorded as MMIO, including the ECAM

   // window: the payload maps the resulting MEMORY_RESERVED resource as

@@ -847,6 +959,24 @@ BuildPayloadHobList (
       &MemMapInfo->Entry[EntryIndex].Type,

       &MemMapInfo->Entry[EntryIndex].Flag

       );

+

+    //

+    // A Reserved descriptor entirely covered by our own boot-time

+    // reservations is DRAM the OS may reclaim after ExitBootServices():

+    // report it as SBL type 1 so the payload publishes it as

+    // SYSTEM_MEMORY.  The gLoaderBootTimeReservationGuid HOB below

+    // tells the payload to keep it out of its HOB-memory search and to

+    // pin it with an EfiBootServicesData memory-allocation HOB.

+    //

+    if ((Entry->Type == EfiReservedMemoryType) &&

+        IsBootTimeReservation (

+          Entry->PhysicalStart,

+          Entry->PhysicalStart + EFI_PAGES_TO_SIZE (Entry->NumberOfPages)

+          ))

+    {

+      MemMapInfo->Entry[EntryIndex].Type = 1;

+    }

+

     EntryIndex++;

   }

 

@@ -880,6 +1010,36 @@ BuildPayloadHobList (
 

   MemMapInfo->Count = (UINT32)EntryIndex;

 

+  //

+  // Boot-time reservation GUID HOB: the payload excludes each range

+  // from FindFreeMemForHobCallback() and pins each with an

+  // EfiBootServicesData memory-allocation HOB.  A payload that does

+  // not know the GUID sees the ranges as ordinary SBL type 1 RAM

+  // records, each far smaller than PcdSystemMemoryUefiRegionSize and

+  // therefore already unpickable by the HOB-memory search.

+  //

+  if (mBootTimeReservationCount > 0) {

+    BootTimeRes = EmitGuidHob (

+                    HobList,

+                    &HobOffset,

+                    HobLimit,

+                    &gLoaderBootTimeReservationGuid,

+                    sizeof (LOADER_BOOT_TIME_RESERVATION) +

+                    mBootTimeReservationCount * sizeof 
(LOADER_BOOT_TIME_RESERVATION_ENTRY)

+                    );

+    if (BootTimeRes == NULL) {

+      return EFI_BUFFER_TOO_SMALL;

+    }

+

+    BootTimeRes->Revision = 1;

+    BootTimeRes->Count    = (UINT32)mBootTimeReservationCount;

+    CopyMem (

+      BootTimeRes->Entry,

+      mBootTimeReservation,

+      mBootTimeReservationCount * sizeof (LOADER_BOOT_TIME_RESERVATION_ENTRY)

+      );

+  }

+

   if (Serial.RegisterBase != 0) {

     //

     // SERIAL_PORT_INFO.BaseAddr is UINT32, but SPCR can legally place an

@@ -1242,8 +1402,8 @@ ChainloadEntry (
   // used.  The ExtraData HOB records the actual FV base, so nothing

   // downstream still assumes the PCD value.  The HOB list and payload

   // stack are also placed below 4 GiB.  All three are typed as

-  // EfiReservedMemoryType so that they survive as SBL type 2 (Reserved)

-  // in the memory-map HOB.

+  // EfiReservedMemoryType; IsBootTimeReservation() later reports them

+  // as SBL type 1 (RAM) with a matching allocation HOB to pin them.

   //

   FvAddress = PcdGet32 (PcdPayloadFdMemBase);

   Status    = gBS->AllocatePages (AllocateAddress, EfiReservedMemoryType, 
FvPages, &FvAddress);

@@ -1266,6 +1426,7 @@ ChainloadEntry (
 

   CopyMem ((VOID *)(UINTN)FvAddress, EmbeddedFv, FvSize);

   Print (L"ChainloadApp: FV 0x%lx bytes copied to 0x%lx\n", (UINT64)FvSize, 
FvAddress);

+  RecordBootTimeReservation (FvAddress, EFI_PAGES_TO_SIZE (FvPages));

 

   HobAddress = MAX_UINT32;

   Status     = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, 
HOB_LIST_PAGES, &HobAddress);

@@ -1277,6 +1438,7 @@ ChainloadEntry (
 

   HobList = (VOID *)(UINTN)HobAddress;

   ZeroMem (HobList, HOB_LIST_SIZE);

+  RecordBootTimeReservation (HobAddress, HOB_LIST_SIZE);

 

   StackAddress = MAX_UINT32;

   Status       = gBS->AllocatePages (AllocateMaxAddress, 
EfiReservedMemoryType, PAYLOAD_STACK_PAGES, &StackAddress);

@@ -1286,6 +1448,8 @@ ChainloadEntry (
     goto FreeReserved;

   }

 

+  RecordBootTimeReservation (StackAddress, PAYLOAD_STACK_SIZE);

+

   //

   // Fetch the GCD memory space map.  On AArch64 it drives the

   // ARM_MEMORY_REGION_DESCRIPTOR list handed to ArmConfigureMmu(); on

@@ -1359,7 +1523,13 @@ ChainloadEntry (
     goto FreeReserved;

   }

 

-  Print (L"ChainloadApp: HOB list at 0x%lx, stack at 0x%lx\n", HobAddress, 
StackAddress);

+  Print (

+    L"ChainloadApp: HOB list at 0x%lx, stack at 0x%lx, %lu boot-time 
reservation%s\n",

+    HobAddress,

+    StackAddress,

+    (UINT64)mBootTimeReservationCount,

+    (mBootTimeReservationCount == 1) ? L"" : L"s"

+    );

 

   //

   // Locate the SEC-core PE/COFF image inside the copied FV, then use

diff --git a/UefiPayloadPkg/ChainloadApp/ChainloadApp.inf 
b/UefiPayloadPkg/ChainloadApp/ChainloadApp.inf
index 1d75b7cbda..7eb5f31a06 100644
--- a/UefiPayloadPkg/ChainloadApp/ChainloadApp.inf
+++ b/UefiPayloadPkg/ChainloadApp/ChainloadApp.inf
@@ -63,6 +63,7 @@
   gEfiSmbios3TableGuid

   gUniversalPayloadExtraDataGuid

   gLoaderMemoryMapInfoGuid

+  gLoaderBootTimeReservationGuid

   gUefiSerialPortInfoGuid

   gUniversalPayloadSerialPortInfoGuid

   gUniversalPayloadSmbiosTableGuid

diff --git a/UefiPayloadPkg/Include/Guid/BootTimeReservationGuid.h 
b/UefiPayloadPkg/Include/Guid/BootTimeReservationGuid.h
new file mode 100644
index 0000000000..d20e177b04
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/BootTimeReservationGuid.h
@@ -0,0 +1,53 @@
+/** @file

+  Boot-time reservation GUID HOB.

+

+  A UEFI-hosted launcher (ChainloadApp) allocates the payload FV, its

+  own HOB list, the payload's initial stack and, on AArch64, a full

+  translation-table hierarchy from the outer firmware as

+  EfiReservedMemoryType so that they appear as isolated Reserved

+  descriptors in the memory-map snapshot and cannot be selected as

+  free RAM by the payload's HOB-memory search.  None of them, however,

+  needs to survive past the OS's ExitBootServices() call: DxeCore

+  loads every driver out of the FV into its own pages, the launcher's

+  HOB list is dead once UefiPayloadEntry has rebuilt the HOB list, the

+  launcher's stack is dead once HandOffToDxeCore() has switched to its

+  own, and firmware translation tables are the same EfiBootServicesData

+  in a normal ArmMmuLib-based boot.

+

+  This HOB tells the payload which of the Reserved records in the SBL

+  memory-map HOB are the launcher's own boot-time-only allocations.

+  UefiPayloadEntry excludes them from FindFreeMemForHobCallback(),

+  publishes each as EFI_RESOURCE_SYSTEM_MEMORY, and pins each with an

+  EfiBootServicesData memory-allocation HOB so that the payload's DXE

+  never allocates over them and the OS reclaims them after

+  ExitBootServices().

+

+  A launcher that does not emit this HOB (Slim Bootloader, coreboot)

+  gets the pre-existing behaviour unchanged: the payload publishes the

+  Reserved records as EFI_RESOURCE_MEMORY_RESERVED and the OS never

+  touches them.

+

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

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

+**/

+

+#ifndef LOADER_BOOT_TIME_RESERVATION_GUID_H_

+#define LOADER_BOOT_TIME_RESERVATION_GUID_H_

+

+extern EFI_GUID  gLoaderBootTimeReservationGuid;

+

+#pragma pack(1)

+typedef struct {

+  EFI_PHYSICAL_ADDRESS    Base;

+  UINT64                  Size;

+} LOADER_BOOT_TIME_RESERVATION_ENTRY;

+

+typedef struct {

+  UINT8                                 Revision;

+  UINT8                                 Reserved0[3];

+  UINT32                                Count;

+  LOADER_BOOT_TIME_RESERVATION_ENTRY    Entry[0];

+} LOADER_BOOT_TIME_RESERVATION;

+#pragma pack()

+

+#endif

diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c 
b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
index 00b016003b..fe66243280 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
@@ -8,12 +8,24 @@
 **/

 

 #include <Guid/MemoryTypeInformation.h>

+#include <Guid/BootTimeReservationGuid.h>

 #include <Library/BaseArchLibSupport.h>

 #include "UefiPayloadEntry.h"

 

 STATIC UINT32   mTopOfLowerUsableDram = 0;

 STATIC BOOLEAN  mMcfgResourceHobBuilt = FALSE;

 

+//

+// Boot-time reservations from the launcher's

+// gLoaderBootTimeReservationGuid HOB, if it emitted one.

+// FindFreeMemForHobCallback() excludes ranges overlapping any of

+// these; BuildGenericHob() pins each with an EfiBootServicesData

+// memory-allocation HOB.  A launcher that does not emit the HOB

+// (Slim Bootloader, coreboot) leaves both NULL/0.

+//

+STATIC LOADER_BOOT_TIME_RESERVATION_ENTRY  *mBootTimeReservation;

+STATIC UINTN                               mBootTimeReservationCount;

+

 EFI_MEMORY_TYPE_INFORMATION  mDefaultMemoryTypeInformation[] = {

   { EfiACPIReclaimMemory,   FixedPcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory)  
 },

   { EfiACPIMemoryNVS,       FixedPcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS)      
 },

@@ -221,6 +233,36 @@ FindToludCallback (
   return EFI_SUCCESS;

 }

 

+/**

+   Return whether a range overlaps any of the launcher's boot-time

+   reservations.

+

+   @param[in] Base  Range start.

+   @param[in] End   Range end (exclusive).

+

+   @retval TRUE   The range overlaps a boot-time reservation.

+   @retval FALSE  It does not, or no launcher published any.

+**/

+STATIC

+BOOLEAN

+OverlapsBootTimeReservation (

+  IN UINT64  Base,

+  IN UINT64  End

+  )

+{

+  UINTN  Index;

+

+  for (Index = 0; Index < mBootTimeReservationCount; Index++) {

+    if ((Base < (mBootTimeReservation[Index].Base + 
mBootTimeReservation[Index].Size)) &&

+        (End > mBootTimeReservation[Index].Base))

+    {

+      return TRUE;

+    }

+  }

+

+  return FALSE;

+}

+

 /**

    Callback function to find free and usable DRAM for HOB

    The memory region returned will have at least PcdSystemMemoryUefiRegionSize 
bytes

@@ -300,6 +342,24 @@ FindFreeMemForHobCallback (
     return EFI_SUCCESS;

   }

 

+  //

+  // A ChainloadApp launcher reports its own FV/HOB/stack/page-table

+  // allocations as SBL type 1 records so they become SYSTEM_MEMORY

+  // rather than MEMORY_RESERVED.  They are still live: HOB memory

+  // must not land on any of them.  What actually protects them is

+  // the BuildMemoryAllocationHob() pin in BuildGenericHob() below;

+  // this check is belt-and-braces so an SBL type-1 entry that

+  // overlapped one is skipped outright rather than split.  The

+  // launcher emits one SBL entry per outer memory-map descriptor

+  // and never merges Reserved with Conventional, so on today's

+  // launcher this check does not fire.  A launcher that emits no

+  // gLoaderBootTimeReservationGuid HOB (Slim Bootloader, coreboot)

+  // never enters this branch.

+  //

+  if (OverlapsBootTimeReservation (Entry.Base, Entry.Base + Entry.Size)) {

+    return EFI_SUCCESS;

+  }

+

   //

   // Overlaps UefiPayload, split into smaller chunks

   //

@@ -633,6 +693,59 @@ FindBootloaderExtraDataHob (
   return ExtraData;

 }

 

+/**

+  Locate the launcher's boot-time reservation HOB, if it published one.

+

+  @param[in]  BootloaderParameter  Bootloader-provided argument.

+  @param[out] Count                Entry count, clamped to what the

+                                   HOB's own data size can hold.

+

+  @return  First reservation entry, or NULL if the launcher did not

+           hand over a PEI HOB list carrying the GUID HOB.

+**/

+STATIC

+LOADER_BOOT_TIME_RESERVATION_ENTRY *

+FindBootloaderBootTimeReservationHob (

+  IN  UINTN  BootloaderParameter,

+  OUT UINTN  *Count

+  )

+{

+  EFI_PEI_HOB_POINTERS          BlHob;

+  LOADER_BOOT_TIME_RESERVATION  *BootTimeRes;

+  UINTN                         DataSize;

+

+  *Count = 0;

+

+  BlHob.Raw = (UINT8 *)BootloaderParameter;

+  if ((BlHob.Raw == NULL) ||

+      (BlHob.Header->HobType != EFI_HOB_TYPE_HANDOFF) ||

+      (BlHob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)))

+  {

+    return NULL;

+  }

+

+  BlHob.Raw = GetNextGuidHob (&gLoaderBootTimeReservationGuid, BlHob.Raw);

+  if (BlHob.Raw == NULL) {

+    return NULL;

+  }

+

+  BootTimeRes = (LOADER_BOOT_TIME_RESERVATION *)GET_GUID_HOB_DATA (BlHob.Raw);

+  DataSize    = GET_GUID_HOB_DATA_SIZE (BlHob.Raw);

+  if ((DataSize < sizeof (LOADER_BOOT_TIME_RESERVATION)) ||

+      (BootTimeRes->Revision != 1))

+  {

+    return NULL;

+  }

+

+  *Count = MIN (

+             (UINTN)BootTimeRes->Count,

+             (DataSize - sizeof (LOADER_BOOT_TIME_RESERVATION)) /

+             sizeof (LOADER_BOOT_TIME_RESERVATION_ENTRY)

+             );

+

+  return BootTimeRes->Entry;

+}

+

 /**

   Locate the payload FV base and size from the bootloader's ExtraData

   HOB, if it published one.

@@ -699,11 +812,38 @@ BuildGenericHob (
   )

 {

   UINT8                        PhysicalAddressBits;

+  UINTN                        Index;

   EFI_RESOURCE_ATTRIBUTE_TYPE  ResourceAttribute;

 

   // The UEFI payload FV

   BuildMemoryAllocationHob (PayloadFvBase, PayloadFvSize, EfiBootServicesData);

 

+  //

+  // Pin every launcher boot-time reservation with an

+  // EfiBootServicesData memory-allocation HOB so that DXE never

+  // allocates over the launcher's HOB list, initial stack or (on

+  // AArch64) live translation tables.  The FV was pinned just above,

+  // so the entry naming it is skipped.  A launcher that emitted no

+  // gLoaderBootTimeReservationGuid HOB leaves the count at 0.

+  //

+  for (Index = 0; Index < mBootTimeReservationCount; Index++) {

+    if (mBootTimeReservation[Index].Base == PayloadFvBase) {

+      continue;

+    }

+

+    BuildMemoryAllocationHob (

+      mBootTimeReservation[Index].Base,

+      mBootTimeReservation[Index].Size,

+      EfiBootServicesData

+      );

+    DEBUG ((

+      DEBUG_INFO,

+      "boot-time reservation: base = 0x%lx, size = 0x%lx\n",

+      mBootTimeReservation[Index].Base,

+      mBootTimeReservation[Index].Size

+      ));

+  }

+

   PhysicalAddressBits = ArchGetPhysicalAddressBits ();

   BuildCpuHob (PhysicalAddressBits, 16);

 

@@ -765,6 +905,17 @@ _ModuleEntryPoint (
     PayloadFvSize = PcdGet32 (PcdPayloadFdMemSize);

   }

 

+  //

+  // If the launcher published boot-time reservations, cache them so

+  // FindFreeMemForHobCallback() below excludes those ranges from the

+  // HOB-memory search.  A launcher that did not (Slim Bootloader,

+  // coreboot) leaves the count at 0 and nothing changes.

+  //

+  mBootTimeReservation = FindBootloaderBootTimeReservationHob (

+                           BootloaderParameter,

+                           &mBootTimeReservationCount

+                           );

+

   // HOB region is used for HOB and memory allocation for this module

   MemBase    = PayloadFvBase;

   HobMemBase = 0;

diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf 
b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
index 91aa8e3f5d..7e345a9349 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
@@ -72,6 +72,7 @@
   gUniversalPayloadAcpiTableGuid

   gUniversalPayloadSerialPortInfoGuid

   gUniversalPayloadExtraDataGuid

+  gLoaderBootTimeReservationGuid

   gEfiFirmwareInfoHobGuid

   gEfiSmmStoreInfoHobGuid

 

diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec 
b/UefiPayloadPkg/UefiPayloadPkg.dec
index 3c6352e0c6..3a445b0f87 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -40,6 +40,7 @@
   gUefiAcpiBoardInfoGuid   = {0xad3d31b, 0xb3d8, 0x4506, {0xae, 0x71, 0x2e, 
0xf1, 0x10, 0x6, 0xd9, 0xf}}

   gUefiSerialPortInfoGuid  = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 
0x8d, 0x62, 0xde, 0x87, 0xf1 } }

   gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 
0xf3, 0x57, 0xd1, 0x28, 0x32 } }

+  gLoaderBootTimeReservationGuid = { 0x058e371c, 0x3486, 0x46b1, { 0xac, 0xf6, 
0x2a, 0x3f, 0x26, 0x9c, 0xe2, 0x69 } }

   gEdkiiPayloadCommandLineGuid = {0xb5aeb34f, 0x3047, 0x4955, {0xb8, 0x80, 
0xad, 0xd3, 0x6d, 0x86, 0xdc, 0x0f}}

 

   # SMM variable support

diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc 
b/UefiPayloadPkg/UefiPayloadPkg.dsc
index b6306ac7c3..ec1bee7ad2 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -1406,8 +1406,11 @@
       #

       # 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.

+      # EfiReservedMemoryType so they stay isolated in the outer

+      # memory-map snapshot and cannot be selected as HOB memory,

+      # and record each one so ChainloadApp can hand the payload an

+      # explicit boot-time reservation list to publish as

+      # EfiBootServicesData.

       #

       
MemoryAllocationLib|UefiPayloadPkg/ChainloadApp/ReservedUefiMemoryAllocationLib.inf

   }

-- 
2.47.3



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


Reply via email to