Page 1 of 1

EFI GetMemoryMap returning strange results

Posted: Sun Jan 12, 2025 3:27 pm
by Beachhouse13
Hello OS devs. I am having an issue getting the memory map from EFI. Some of the background info, my OS uses multiboot2, which uses the MULTIBOOT_HEADER_TAG_EFI_BS and MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 tags to use EFI and is already in 64-bit mode when my code starts. I have been able to get the EFI_BOOT_SERVICES table from multiboot2 through the MULTIBOOT_TAG_TYPE_EFI64 tag. I wrote a function to output the header of the boot services table and the results are as expected:
Boot Services Signature: 0x56524553544F4F42
Boot Services Revision: 0x0000000000020046
Boot Services Header Size: 0x0000000000000178

The revision is a little suspect with the 6, as I do not believe this is per the EFI specs, but could be an emulator specific variation.

Here is the code that use to get the memory:

Code: Select all

        EFI_SYSTEM_TABLE *efi_system_table = (EFI_SYSTEM_TABLE *)efi64_tag->pointer;
        EFI_BOOT_SERVICES *boot_services = (EFI_BOOT_SERVICES *)efi_system_table->BootServices;
        inspect_boot_services(efi_system_table);

        uint8_t memory_map[4096];
        EFI_MEMORY_MAP_INFO mmap_info = {
          .MemoryMapSize = 0,
          .MapKey = 0,
          .DescriptorSize = 0,
          .DescriptorVersion = 0
        };

        size_t mmap_num = 0;

        // call GetMeoryMap once. EFI will populate errorous values with correct ones.
        EFI_STATUS status = boot_services->GetMemoryMap(
            &mmap_info.MemoryMapSize,
            (EFI_MEMORY_DESCRIPTOR *)memory_map,
            &mmap_info.MapKey,
            &mmap_info.DescriptorSize,
            &mmap_info.DescriptorVersion);
As expected, the GetMemoryMap returns EFI_BUFFER_TOO_SMALL and populates the .MemoryMapSize value. But this comes out to be 0x107FDC, which is way to large. In addition the descriptor size is changed to 0x1470, and the descriptor version is changed to 0x55D. These are way off as well. And it doesn’t matter if I put in the expected descriptor size of 0x24, and version of 0x1, it will still change the values.

To make maters worse, if I try to rung GetMemoryMap again, even with a fresh set of data, the CPU will crash (but that’s an issue for another day).

After much debugging, I feel it comes down to some little thing that I am doing wrong in my code, or a problem with emulation. I am using QEMU version 8.1.0 and windows 10.0.19045.5247.

Here is my code for my EFI tables which may have the issue:

Code: Select all

typedef uint64_t EFI_STATUS;
typedef struct
{
    uint64_t Signature;
    uint32_t Revision;
    uint32_t HeaderSize;
    uint32_t CRC32;
    uint32_t Reserved;
} EFI_TABLE_HEADER;
typedef struct
{
    // Table Header
    EFI_TABLE_HEADER Hdr;

    // Task Priority Services
    void *RaiseTPL;
    void *RestoreTPL;

    // Memory Services
    EFI_STATUS (*AllocatePages)
    (uint32_t Type, uint32_t MemoryType, uint64_t Pages, uint64_t *Memory);
    EFI_STATUS (*FreePages)
    (uint64_t Memory, uint64_t Pages);
    EFI_STATUS (*GetMemoryMap)
    (
        uint64_t *MemoryMapSize,
        void *MemoryMap,
        uint64_t *MapKey,
        uint64_t *DescriptorSize,
        uint32_t *DescriptorVersion);
    EFI_STATUS (*AllocatePool)
    (uint32_t PoolType, uint64_t Size, void **Buffer);
    EFI_STATUS (*FreePool)
    (void *Buffer);
    …
} EFI_BOOT_SERVICES;
Any help finding where my error is would be greatly appreciated.

Re: EFI GetMemoryMap returning strange results

Posted: Sun Jan 12, 2025 6:50 pm
by zaval
in your definitions, you use uint64_t where the UEFI specification uses UINTN. they are of the same size only in 64 bits, this is already what you should change in your definitions. next, instead of using that EFI_MEMORY_MAP_INFO thing, what is this, just use local stack variables of the required type. finally, use AllocatePages() for the memory map buffer after you got the map size, not this lame byte buffer of page size. btw, memory map will be often bigger, than that. The cause of this issue is most probably type mismatch in that map info structure.

Re: EFI GetMemoryMap returning strange results

Posted: Sun Jan 12, 2025 7:21 pm
by Octocontrabass
Beachhouse13 wrote: Sun Jan 12, 2025 3:27 pmHere is my code for my EFI tables which may have the issue:
You forgot EFIAPI. Or are you passing options to make your compiler follow the Microsoft x64 ABI everywhere?