Search code examples
coperating-systembootloaderosdevuefi

Can't get the right memory map using uefi's GetMemoryMap function


I'm writing a little boot loader in UEFI environment for my custom os using POSIX-UEFI.

When trying to get the memory map using GetMemoryMap boot service to calculate the amount of memory, it returns not only a different number of memory descriptors each time the program is executed, but the descriptor table itself seems to be corrupted or something...

Here's the code to get the memory map:

efi_memory_descriptor_t *map = NULL;
uintn_t mapsize, mapkey, descriptorsize;
uint32_t descriptorversion;
uint64_t memory_size = 0;

ST->BootServices->GetMemoryMap(&mapsize, map, &mapkey, &descriptorsize, &descriptorversion);
ST->BootServices->AllocatePool(EfiLoaderData, mapsize, (void **) &map);
ST->BootServices->GetMemoryMap(&mapsize, map, &mapkey, &descriptorsize, &descriptorversion);
printf("Memory map size: %d descriptors\n", mapsize / descriptorsize);

for (int i = 0; i < mapsize / descriptorsize; i++) {
    efi_memory_descriptor_t *desc = (efi_memory_descriptor_t *)(map + i * descriptorsize);
    memory_size += desc->NumberOfPages * EFI_PAGE_SIZE;
}

printf("Memory size: %d bytes\n", memory_size);

I tried using sizeof(efi_memory_descriptor_t) too instead of descriptorsize to calculate the number of entries but nothing changes.

Here's a screenshot of the program's output: VirtualBox with an efi shell running 3 times the code above

I use a VirtualBox (v7.0.4) virtual machine with 64MB ram size, no storage device, and a usb drive attached to load the program from.


Solution

  • map is a pointer to efi_memory_descriptor_t, so map + i * descriptorsize is scaling by both descriptorsize and sizeof (efi_memory_descriptor_t).

    I suggest using (uint8_t *)map + i * descriptorsize.

    Note, descriptorsize may not be equal to sizeof (efi_memory_descriptor_t), so it is correct to use descriptorsize.