You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何按UEFI GetMemoryMap返回大小分配缓冲区后仍报EFI_BUFFER_TOO_SMALL?

UEFI GetMemoryMap() 分配精确大小仍返回BUFFER_TOO_SMALL是否正常?

问题场景

我用Zig编写UEFI应用时,调用两次GetMemoryMap():第一次获取所需缓冲区大小,随后用AllocatePool()分配对应大小的缓冲区,但第二次调用仍返回EFI_BUFFER_TOO_SMALL。添加mmap_size += descriptor_size * 2;后程序正常运行。

代码实现

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;
}

运行日志

[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

回答

这种情况是完全正常的,属于UEFI规范定义的预期行为,核心原因如下:

1. 内存映射会在两次调用间动态变化

第一次调用GetMemoryMap()返回的mmap_size,仅代表调用瞬间系统内存映射所需的缓冲区大小。但在你调用AllocatePool()分配内存的过程中,系统内存映射已经发生了改变——AllocatePool()本身会向内存映射中添加一个新的MemoryDescriptor条目,用来描述刚分配的内存区域,这直接导致第二次调用GetMemoryMap()时,需要的缓冲区空间比第一次返回的数值更大。

2. UEFI规范的明确要求

UEFI规范中明确指出:调用者不能仅依赖第一次返回的精确大小分配缓冲区,必须预留额外的冗余空间(至少1~2个MemoryDescriptor的大小),以应对两次调用之间内存映射的动态变更。你添加的mmap_size += descriptor_size * 2正是为缓冲区预留了足够的冗余空间,因此第二次调用能够成功。

可行的处理方案

  • 预分配冗余空间:在第一次获取的mmap_size基础上,额外加上1~2倍的descriptor_size,这是最常用且高效的做法,能覆盖绝大多数场景下的内存映射变化。
  • 循环重试机制:如果第二次调用仍返回BUFFER_TOO_SMALL,则释放当前缓冲区,根据新返回的mmap_size重新分配更大的空间,再次调用GetMemoryMap(),直到调用成功。

内容的提问来源于stack exchange,提问作者OrderChaos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:45:57