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:
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 withEFI_BUFFER_TOO_SMALL, even though I allocated the exact size reported in the first call.
Log:
[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.