UEFI Memory Map

Overview

The UEFI memory map describes how physical memory is currently used by the firmware before an operating system takes control.

It is one of the most important data structures in the UEFI boot process because a boot loader must obtain the final memory map immediately before calling ExitBootServices().


Why It Exists

During firmware execution, memory is used for many different purposes:

  • UEFI code
  • Boot Services data
  • Runtime Services data
  • ACPI tables
  • Device memory mappings
  • Conventional RAM available to the operating system

The memory map allows a boot loader to distinguish between memory that is free and memory that must be preserved.


EFI_MEMORY_DESCRIPTOR

Each entry in the memory map is an EFI_MEMORY_DESCRIPTOR.

A descriptor contains information such as:

  • Memory type
  • Physical start address
  • Number of pages
  • Attributes

A simplified view:

EFI_MEMORY_DESCRIPTOR
├── Type
├── PhysicalStart
├── VirtualStart
├── NumberOfPages
└── Attribute

Retrieving the Memory Map

UEFI requires a two-step GetMemoryMap() workflow.

The application cannot know the required buffer size in advance.

The typical sequence is:

GetMemoryMap(NULL buffer)
        |
        v
EFI_BUFFER_TOO_SMALL
        |
        v
AllocatePool(required size)
        |
        v
GetMemoryMap(real buffer)
        |
        v
Process descriptors

Why Two Calls Are Necessary

The first call returns:

  • Required buffer size
  • Descriptor size
  • Descriptor version

After allocating the buffer, the application calls GetMemoryMap() again to retrieve the actual descriptors.

This pattern appears frequently in UEFI APIs.


Important: Allocation Changes the Memory Map

A subtle but critical detail is that AllocatePool() itself modifies the memory map.

For this reason, applications usually reserve additional space before allocation.

Example:

MemoryMapSize += 2 * DescriptorSize;

Without the extra space, the second GetMemoryMap() call may fail because the map changed during allocation.


Iterating Descriptors

Descriptors are not guaranteed to be tightly packed.

The firmware provides the correct descriptor size.

Incorrect:

Descriptor++;

Correct:

Descriptor =
    (EFI_MEMORY_DESCRIPTOR*)
    (
        (UINT8*)Descriptor + DescriptorSize
    );

This works across different firmware implementations.


Common Memory Types

Frequently encountered memory types include:

Memory Type Purpose
EfiLoaderCode Boot loader executable code
EfiLoaderData Boot loader data
EfiBootServicesCode Firmware Boot Services code
EfiBootServicesData Firmware Boot Services data
EfiRuntimeServicesCode Runtime Services code
EfiRuntimeServicesData Runtime Services data
EfiConventionalMemory Free RAM available to the OS
EfiACPIReclaimMemory ACPI tables reclaimable by the OS
EfiACPIMemoryNVS ACPI NVS memory that must be preserved
EfiMemoryMappedIO Device memory mappings

For operating system development, EfiConventionalMemory is usually the most important category because it represents usable physical RAM.


Page Count and Size

UEFI reports memory in 4 KiB pages.

The size of a region is calculated as:

SizeInBytes = NumberOfPages * 4096;

Example:

Pages Size
1 4 KiB
256 1 MiB
512 2 MiB
32768 128 MiB

The MapKey

GetMemoryMap() also returns a MapKey.

The MapKey identifies the exact version of the memory map.

When calling ExitBootServices(), the boot loader must provide the same MapKey that was returned by the final successful GetMemoryMap() call.

If the memory map changes between these calls, ExitBootServices() fails.

This is one of the most common pitfalls in UEFI boot loader development.


Example Output

The Memory Map Viewer application displays descriptors in a human-readable format:

Memory Map Viewer

The output includes:

  • Memory type
  • Physical start address
  • Page count
  • Calculated size

Contiguous regions of the same type are grouped together to improve readability.




Why This Matters for the Boot Loader

The future Linux loader in this project will rely on the memory map to:

  • Identify usable RAM
  • Avoid firmware-reserved regions
  • Retrieve the final MapKey
  • Successfully call ExitBootServices()
  • Transfer control to the kernel

Understanding the memory map is therefore a prerequisite for implementing a correct firmware-to-kernel handoff.


This site uses Just the Docs, a documentation theme for Jekyll.