UEFI Memory Map Descriptors for Operating Systems
This article provides a technical overview of how the Unified
Extensible Firmware Interface (UEFI) defines and conveys physical memory
layouts to an operating system. It examines the
EFI_MEMORY_DESCRIPTOR structure, breaks down each of its
essential fields, explains how the operating system retrieves this map
using boot services, and describes how the kernel interprets different
memory types to safely manage system resources and reclaim firmware
memory.
The
EFI_MEMORY_DESCRIPTOR Structure
In the UEFI specification, the physical memory layout of the platform
is represented as an array of descriptor structures. When an operating
system bootloader queries the firmware for the system memory layout, it
receives an array of EFI_MEMORY_DESCRIPTOR entries.
In C-style syntax, the structure is defined as follows:
typedef struct {
UINT32 Type;
EFI_PHYSICAL_ADDRESS PhysicalStart;
EFI_VIRTUAL_ADDRESS VirtualStart;
UINT64 NumberOfPages;
UINT64 Attribute;
} EFI_MEMORY_DESCRIPTOR;Each field inside this structure serves a specific role:
Type(UINT32): Specifies the classification and intended usage of the memory region.PhysicalStart(EFI_PHYSICAL_ADDRESS / UINT64): The starting physical address of the memory region. It is always aligned to a 4 KiB boundary.VirtualStart(EFI_VIRTUAL_ADDRESS / UINT64): The starting virtual address of the memory region. During boot services, this is typically unassigned or identical toPhysicalStart. It is populated if the operating system configures virtual addresses and invokes theSetVirtualAddressMap()runtime service.NumberOfPages(UINT64): The size of the memory region expressed in the number of contiguous 4 KiB pages. The total byte size of the region is calculated asNumberOfPages * 4096.Attribute(UINT64): A bitmask defining the architectural capabilities, caching modes (such as UC, WC, WT, WB), and protection levels (such as WP, RP, XP) of the region, as well as whether the region needs to be preserved for runtime firmware calls (EFI_MEMORY_RUNTIME).
Key UEFI Memory Types
The Type field dictates whether the operating system can
immediately take control of the region, must preserve it, or can reclaim
it later. The standard types defined by the specification include:
EfiConventionalMemory: Free, unallocated RAM. The operating system can immediately use this memory for its own allocators and page tables.EfiLoaderCodeandEfiLoaderData: Memory allocated by the UEFI OS loader. The operating system may reclaim this space once the bootloader has finished execution.EfiBootServicesCodeandEfiBootServicesData: Memory holding UEFI boot services code and data. The operating system can safely reclaim these regions after successfully callingExitBootServices().EfiRuntimeServicesCodeandEfiRuntimeServicesData: Memory holding UEFI runtime services code and operational data. The OS must reserve these ranges across reboots and map them to allow the kernel to execute runtime services (such as updating NVRAM variables or setting the RTC).EfiACPIReclaimMemory: Contains ACPI tables. The OS can reclaim this memory only after it has fully read and parsed the ACPI tables into its own structures.EfiACPIMemoryNVS: Non-Volatile Sleep memory used by firmware ACPI code. The operating system must never overwrite this memory.EfiMemoryMappedIOandEfiMemoryMappedIOPortSpace: Physical address ranges designated for memory-mapped hardware registers.EfiReservedMemoryTypeandEfiUnusableMemory: Memory regions that are firmware-reserved or have sustained hardware errors; the OS must not use them.
Retrieving the
Memory Map via GetMemoryMap()
The operating system bootloader retrieves the memory map array by
calling the UEFI Boot Service function GetMemoryMap():
EFI_STATUS GetMemoryMap (
IN OUT UINTN *MemoryMapSize,
OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
OUT UINTN *MapKey,
OUT UINTN *DescriptorSize,
OUT UINT32 *DescriptorVersion
);Iterating the Array Correctly
Compilers and firmware implementations may extend the descriptor or
add padding. Therefore, operating systems must not iterate through the
returned buffer using sizeof(EFI_MEMORY_DESCRIPTOR).
Instead, the OS must advance to the next entry by adding the returned
DescriptorSize parameter in bytes:
\[\text{Next Descriptor} = (\text{EFI\_MEMORY\_DESCRIPTOR}*) ((\text{UINT8}*)\text{CurrentDescriptor} + \text{DescriptorSize})\]
The Role of MapKey
The MapKey parameter acts as an integrity token. When
the operating system is ready to assume full hardware control, it calls
ExitBootServices(ImageHandle, MapKey). If memory
allocations changed between the last call to GetMemoryMap()
and ExitBootServices(), the MapKey becomes
invalid, the exit call fails, and the OS must fetch the memory map again
before retrying.
Operating System Handoff
Once ExitBootServices() succeeds:
- The OS kernel marks all
EfiConventionalMemory,EfiBootServicesCode, andEfiBootServicesDataregions as usable system RAM. - The OS maps regions flagged with the
EFI_MEMORY_RUNTIMEattribute into its own address space if it intends to utilize UEFI runtime services. - Hardware registers identified by
EfiMemoryMappedIOare tracked to prevent overlapping physical memory allocations.