Why does UEFI GetMemoryMap return EFI_BUFFER_TOO_SMALL after allocating a buffer of the reported size?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
OrdChaosXQ
Posts: 2
Joined: Sat Oct 01, 2022 9:42 pm
Libera.chat IRC: OrdChaosXQ

Why does UEFI GetMemoryMap return EFI_BUFFER_TOO_SMALL after allocating a buffer of the reported size?

Post by OrdChaosXQ »

I've asked this question on stackoverflow.

url: https://stackoverflow.com/questions/796 ... g-a-buffer

I'm writing a UEFI application in Zig.

I'm calling GetMemoryMap() twice: once to get the required buffer size, then again after allocating the buffer using AllocatePool().

Here's my code:

Code: Select all

fn getMemoryMap() uefi.Status {
    const log = std.log.scoped(.memory_map);
    const system_table = uefi.system_table;
    const boot_services = system_table.boot_services.?;
    var status: uefi.Status = undefined;

    var mmap_size: usize = 0;
    var mmap: ?[*]uefi.tables.MemoryDescriptor = null;
    var map_key: usize = undefined;
    var descriptor_size: usize = undefined;
    var descriptor_version: u32 = undefined;

    status = boot_services.getMemoryMap(&mmap_size, mmap, &map_key, &descriptor_size, &descriptor_version);
    switch (status) {
        .buffer_too_small => log.debug("Buffer too small, need {d} bytes for buffer", .{mmap_size}),
        else => {
            log.err("Excepted buffer_too_small but got {s} instead", .{@tagName(status)});
            return status;
        },
    }
    //mmap_size += descriptor_size * 2;

    status = boot_services.allocatePool(.loader_data, mmap_size, @ptrCast(&mmap));
    switch (status) {
        .success => log.debug("Allocated {d} bytes for memory map at {*}", .{ mmap_size, mmap }),
        else => {
            log.err("Excepted success but got {s} instead", .{@tagName(status)});
            return status;
        },
    }

    status = boot_services.getMemoryMap(&mmap_size, mmap, &map_key, &descriptor_size, &descriptor_version);
    switch (status) {
        .success => log.debug("Got memory map", .{}),
        else => {
            log.err("Excepted success but got {s} instead", .{@tagName(status)});
            return status;
        },
    }

    return uefi.Status.success;
}
The problem:
The second call to getMemoryMap() fails with EFI_BUFFER_TOO_SMALL, even though I allocated the exact size reported in the first call.
log:

Code: Select all

[debug(memory_map)]Buffer too small, need 5856 bytes for buffer
[debug(memory_map)]Allocated 5856 bytes for memory map at [*]os.uefi.tables.MemoryDescriptor@2808018
[error(memory_map)]Excepted success but got buffer_too_small instead
And if I add mmap_size += descriptor_size * 2; before the 2nd call, it can run.

Is this normal? I can't find any examples of this, sorry.
User avatar
iansjack
Member
Member
Posts: 4908
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Why does UEFI GetMemoryMap return EFI_BUFFER_TOO_SMALL after allocating a buffer of the reported size?

Post by iansjack »

If you read the documentation for the function it says that the buffer allocated should be larger than the required size indicated by the first call. This is because the memory allocation will have altered the map.
OrdChaosXQ
Posts: 2
Joined: Sat Oct 01, 2022 9:42 pm
Libera.chat IRC: OrdChaosXQ

Re: Why does UEFI GetMemoryMap return EFI_BUFFER_TOO_SMALL after allocating a buffer of the reported size?

Post by OrdChaosXQ »

iansjack wrote: Sat Jul 12, 2025 3:47 pm If you read the documentation for the function it says that the buffer allocated should be larger than the required size indicated by the first call. This is because the memory allocation will have altered the map.
OH WELL, THANKS.

I found that in the doc.

I had questioned about that because I can't find some examples which really request for more memory.
Post Reply