I’ve been looking into getting GitHub - nrdmn/uefi-examples: UEFI examples in Zig to compile on 0.13. Looks fairly straightforward, but memory map failed because of unknown enum and the memory map printout looks like complete garbage. So I looked into it some more and turns out zig standard library misinterprets UEFI memory map table.
The standard library defines:
pub const MemoryDescriptor = extern struct {
type: MemoryType, //enum(u32)
physical_start: u64,
virtual_start: u64,
number_of_pages: u64,
attribute: MemoryDescriptorAttribute, //packed struct(u64)
};
//...
getMemoryMap: *const fn (mmap_size: *usize, mmap: ?[*]MemoryDescriptor, mapKey: *usize, descriptor_size: *usize, descriptor_version: *u32) callconv(cc) Status
But as UEFI specs goes, mmap isn’t really [*]MemoryDescriptor, because new UEFI versions may (and do) introduce extra fields. That’s why there is an extra output argument, descriptor_size, that would contain actual stride of mmap.
zig std.os.uefi implicitly assumes
descriptor_size==@sizeOf(MemoryDescriptor)==40
which doesn’t hold on QEMU OVMF (descriptor_size==48
) and probably not on real hardware either.
My question is, how do I express this idiomatically with zig? On C I would just use something like
(MemoryDescriptor*)(((uint8_t*)mmap)+i*descriptor_size)
But zig complains about possible misalignment (maybe rightfully so). So I’m forced to write:
@memcpy( @as(*[@sizeOf(std.os.uefi.tables.MemoryDescriptor)]u8, @ptrCast(&d)),
@as(*[@sizeOf(std.os.uefi.tables.MemoryDescriptor)]u8,
@ptrFromInt(@intFromPtr(memory_map)+i*descriptor_size)));
Which is honestly not very fun.