UefiPayloadPkg/UefiPayloadEntry: Don't mutate the bootloader memory map

FindFreeMemForHobCallback() aligns the base of a candidate RAM region
up to 1 MiB and, on 32-bit builds, clips its size at 4 GiB. It makes
both adjustments through the incoming MemoryMapEntry pointer, and for
Slim Bootloader that pointer refers directly into the
gLoaderMemoryMapInfoGuid HOB the bootloader handed over, so we rewrite
the bootloader's map in place.

MemInfoCallback() walks the same array afterwards to publish the system
memory resource HOBs. On any platform whose RAM base is not already
1 MiB aligned we therefore drop the leading fragment silently: it is
published neither as system memory nor as anything else, and ends up
NonExistent in the GCD map with no way for the OS to reclaim it. On
32-bit builds we lose RAM above 4 GiB the same way.

Copy the entry to a local before adjusting it, mirroring the
MemoryMapEntrySplit idiom the function already uses when it recurses
around the payload FV. The selected HobMemBase is unchanged; only the
caller's array stops being corrupted.

CbParseLib is unaffected: its ParseMemoryInfo() already passes a
stack-local MEMORY_MAP_ENTRY to the callback and refills it on every
iteration.

Cc: Benjamin Doron <benjamin.doron@9elements.com>
Cc: Gua Guo <gua.guo@intel.com>
Cc: Guo Dong <guo.dong@intel.com>
Cc: James Lu <james.lu@intel.com>
Cc: Sean Rhodes <sean@starlabs.systems>
Cc: Shuo Liu <shuo.liu@intel.com>
Assisted-by: claude-opus-5
Signed-off-by: Alexander Graf <graf@amazon.com>
This commit is contained in:
Alexander Graf 2026-08-02 05:29:35 +00:00
parent 339e8221af
commit ed3e2c6143

View file

@ -190,6 +190,7 @@ FindFreeMemForHobCallback (
)
{
EFI_STATUS Status;
MEMORY_MAP_ENTRY Entry;
MEMORY_MAP_ENTRY MemoryMapEntrySplit;
UINTN *HobMemBase = (UINTN *)Params;
@ -207,56 +208,63 @@ FindFreeMemForHobCallback (
return EFI_SUCCESS;
}
//
// Operate on a copy so the caller's memory map is not modified.
// SblParseLib passes pointers into the bootloader's HOB and the same
// array is walked again later to publish system memory resource HOBs.
//
Entry = *MemoryMapEntry;
//
// Align on 1 MiB
//
if (ALIGN_VALUE (MemoryMapEntry->Base, SIZE_1MB) > MemoryMapEntry->Base) {
if (ALIGN_VALUE (Entry.Base, SIZE_1MB) > Entry.Base) {
//
// Skip too small
//
if (ALIGN_VALUE (MemoryMapEntry->Base, SIZE_1MB) >= (MemoryMapEntry->Base + MemoryMapEntry->Size)) {
if (ALIGN_VALUE (Entry.Base, SIZE_1MB) >= (Entry.Base + Entry.Size)) {
return EFI_SUCCESS;
}
MemoryMapEntry->Size -= ALIGN_VALUE (MemoryMapEntry->Base, SIZE_1MB) - MemoryMapEntry->Base;
MemoryMapEntry->Base = ALIGN_VALUE (MemoryMapEntry->Base, SIZE_1MB);
Entry.Size -= ALIGN_VALUE (Entry.Base, SIZE_1MB) - Entry.Base;
Entry.Base = ALIGN_VALUE (Entry.Base, SIZE_1MB);
}
//
// Skip resources above 4GiB on x86_32
//
if ((sizeof (UINTN) == 4) && (MemoryMapEntry->Base >= 0x100000000ULL)) {
if ((sizeof (UINTN) == 4) && (Entry.Base >= 0x100000000ULL)) {
return EFI_SUCCESS;
}
if ((sizeof (UINTN) == 4) && ((MemoryMapEntry->Base + MemoryMapEntry->Size) > 0x100000000ULL)) {
MemoryMapEntry->Size = 0x100000000ULL - MemoryMapEntry->Base;
if ((sizeof (UINTN) == 4) && ((Entry.Base + Entry.Size) > 0x100000000ULL)) {
Entry.Size = 0x100000000ULL - Entry.Base;
}
//
// Skip too small
//
if (MemoryMapEntry->Size < FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)) {
if (Entry.Size < FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)) {
return EFI_SUCCESS;
}
//
// Overlaps UefiPayload, split into smaller chunks
//
if ((MemoryMapEntry->Base <= PcdGet32 (PcdPayloadFdMemBase)) &&
((MemoryMapEntry->Base + MemoryMapEntry->Size) >= PcdGet32 (PcdPayloadFdMemBase)))
if ((Entry.Base <= PcdGet32 (PcdPayloadFdMemBase)) &&
((Entry.Base + Entry.Size) >= PcdGet32 (PcdPayloadFdMemBase)))
{
MemoryMapEntrySplit.Type = E820_RAM;
MemoryMapEntrySplit.Base = MemoryMapEntry->Base;
MemoryMapEntrySplit.Base = Entry.Base;
MemoryMapEntrySplit.Size = PcdGet32 (PcdPayloadFdMemBase) - MemoryMapEntrySplit.Base;
Status = FindFreeMemForHobCallback (&MemoryMapEntrySplit, Params);
if (EFI_ERROR (Status)) {
return Status;
}
if ((MemoryMapEntry->Base + MemoryMapEntry->Size) > (PcdGet32 (PcdPayloadFdMemBase) + PcdGet32 (PcdPayloadFdMemSize))) {
if ((Entry.Base + Entry.Size) > (PcdGet32 (PcdPayloadFdMemBase) + PcdGet32 (PcdPayloadFdMemSize))) {
MemoryMapEntrySplit.Base = PcdGet32 (PcdPayloadFdMemBase) + PcdGet32 (PcdPayloadFdMemSize);
MemoryMapEntrySplit.Size = (MemoryMapEntry->Base + MemoryMapEntry->Size) - MemoryMapEntrySplit.Base;
MemoryMapEntrySplit.Size = (Entry.Base + Entry.Size) - MemoryMapEntrySplit.Base;
Status = FindFreeMemForHobCallback (&MemoryMapEntrySplit, Params);
if (EFI_ERROR (Status)) {
return Status;
@ -266,7 +274,7 @@ FindFreeMemForHobCallback (
return EFI_SUCCESS;
}
*HobMemBase = MemoryMapEntry->Base;
*HobMemBase = Entry.Base;
return EFI_ALREADY_STARTED;
}