1
votes

I am trying to load an UEFI application image from memory using Bootservices.loadImage. The buffer in memory is loaded with the binary contents of the HellowWorld.efi application. When I try to load it from memory I get that is an unsupported filetype.

However in digging through the UDK core while running I find that by the time I get to processing the fileheader I am not reading from my buffer correctly. Theirfore all of the magic numbers don't line up, so it sees it as an unrecognized file format. But I haven't been able to trace where along the way my pointer to my source gets messed up.

Im guessing the problem isint in the UDK source, so its in how i'm calling the function.

Code:

    #define SIZEOF_HELLO_EFI 39679
    UINT8 hexData[SIZEOF_HELLO_EFI] =  {//CONTENTS OF helloworld.efi
  0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
 0xFF, 0xFF, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 
0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 
0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 
0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 
0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 
0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 
0x45, 0x00, 0x00, 0x4C, 0x01, 0x07, 0x00, 0x24, 0x80, 0x00, 0x00, 0x00, 0x7E, 
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x06, 0x03, 0x0B, 0x01, 0x02, 
0x18, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x84, 0x00, 
0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    //CONTINUES FOR MANY MORE BYTES, BUT HERE IS THE HEADER INFO};
void copy_helloefi(UINT8* buff)
{
    int counter = 0;
    while(counter < SIZEOF_HELLO_EFI){
        buff[counter] = hexData[counter];
        counter++;
    }

}

EFI_STATUS
efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
        EFI_BOOT_SERVICES *BootServicesTable;
        UINT8* buff_ptr;
        EFI_STATUS status;
        MEMMAP_DEVICE_PATH mempath[2];
       EFI_HANDLE myLoadedImage = NULL;
        BootServicesTable = SystemTable->BootServices;
        BootServicesTable->AllocatePool(EfiLoaderCode, SIZEOF_HELLO_EFI, (void **)&buff_ptr);
        mempath[0].Header.Type = HARDWARE_DEVICE_PATH;
        mempath[0].Header.SubType = HW_MEMMAP_DP;
        mempath[0].Header.Length[0] = (UINT8)sizeof(MEMMAP_DEVICE_PATH);
        mempath[0].Header.Length[1] = (UINT8)(sizeof(MEMMAP_DEVICE_PATH)>> 8);
        mempath[0].MemoryType = EfiLoaderCode;
        mempath[0].StartingAddress = (UINT32)buff_ptr;
        mempath[0].EndingAddress = (UINT32)(buff_ptr + SIZEOF_HELLO_EFI);

        mempath[1].Header.Type = END_DEVICE_PATH_TYPE;
        mempath[1].Header.SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
        mempath[1].Header.Length[0] = (UINT8)sizeof(EFI_DEVICE_PATH);
        mempath[1].Header.Length[1] = (UINT8)(sizeof(EFI_DEVICE_PATH)>> 8);

        copy_helloefi(buff_ptr); //put the contents of helloworld.efi in buffer

        status = BootServicesTable->LoadImage(FALSE, ImageHandle, (EFI_DEVICE_PATH*)&mempath, &buff_ptr, SIZEOF_HELLO_EFI, &myLoadedImage);
        if (EFI_ERROR(status)) {
            Print((CHAR16*)L"Could not LoadImage %r %x \r\n", status, status);
        }
        Print((CHAR16*)L"Loaded Image Handle %x\r\n", myLoadedImage);

        //__debugbreak();
        BootServicesTable->FreePool(buff_ptr);
    return EFI_SUCCESS;
}

What am I doing wrong? HelloWorld.efi is PE/COFF, and if I directly invoke it it runs fine so I know its a valid efi binary.

1
I don't see any call to StartImage() above, but I do see a call to free the region the image has been copied into. Is this the code you are actually running? What does the copy function look like? - unixsmurf
I cant get past LoadImage so I don't even bother trying to start it. I believe I have to load it before I start it, correct? This is a copy and paste of my code. I have the helloWorld bytes defined in a large global array in the application. Copy function simply moves the bytes into the newly allocated buffer - Without Me It Just Aweso
Updated sample code to have full functions, its missing the helloworld global buffer because its huge. but its just the hex bytes from the efi application - Without Me It Just Aweso
OK, I would then be curious about what's actually in the hexData buffer (not all of it, obviously, but the MZ header and such). How are you generating the hex? Is the byte order correct? - unixsmurf
added the beginning of the buffer, containing the headers. The file is the helloworld example that comes with the UDK source. Im able to run it fine so I know its a working EFI PE/COFF and starts with the appropriate MZ header. byte order is a hexdump of the efi binary, stores as uint8s so endianness is not an issue. - Without Me It Just Aweso

1 Answers

1
votes

solved it, as expected it was something small and annoying but posting here to hopefully help others.

Fix was to send it buff_ptr as a void* not a void**

So update the invocation of loadimage to:

status = BootServicesTable->LoadImage(FALSE, ImageHandle, 
(EFI_DEVICE_PATH*)&mempath, buff_ptr, SIZEOF_HELLO_EFI, &myLoadedImage);

Then add this after it to actually run the loaded image

status = BootServicesTable->StartImage( myLoadedImage, (UINTN*)NULL, (CHAR16**)NULL);