0

I am looking at using Bootservices function LoadImage to load a UEFI application image from memory. Function parameters are:

typedef
EFI_STATUS
LoadImage (
  IN BOOLEAN BootPolicy,
  IN EFI_HANDLE ParentImageHandle,
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  IN VOID *SourceBuffer OPTIONAL,
  IN UINTN SourceSize,
  OUT EFI_HANDLE *ImageHandle
  );

I have sourcebuffer in memory and populated with the PE/COFF image to load.

I pass that in under SourceBuffer and set DevicePath to the following:

MEMMAP_DEVICE_PATH mempath[2];
        mempath[0].Header.Type = HARDWARE_DEVICE_PATH;
    mempath[0].Header.SubType = HW_MEMMAP_DP;
    mempath[0].Header.Length[0] = (UINT8)sizeof(mempath);
    mempath[0].Header.Length[1] = (UINT8)(sizeof(mempath)>> 8);
    mempath[0].MemoryType = EfiLoaderCode;
    mempath[0].StartingAddress = (UINT32)buff_ptr;
    mempath[0].EndingAddress = (UINT32)(buff_ptr + BUFF_SIZE);

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

When I call load image the application hangs. I have set up visual studio to allow me to debug UEFI EDK2 source and have isolated where i'm stuck. Below is the EDK2 call that I appear to be stuck in. DevicePath is set to the mempath I setup above. Am I configuring my path incorrectly such that I never exit the below?

EFI_STATUS
EFIAPI
CoreLocateDevicePath (
  IN EFI_GUID                       *Protocol,
  IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath,
  OUT EFI_HANDLE                    *Device
  )
{
......
      EFI_DEVICE_PATH_PROTOCOL    *SourcePath;
  SourcePath = *DevicePath;
  TmpDevicePath = SourcePath;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//I NEVER GET OUT OF THIS LOOP!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  while (!IsDevicePathEnd (TmpDevicePath)) {
    if (IsDevicePathEndInstance (TmpDevicePath)) {
      break;
    }
    TmpDevicePath = NextDevicePathNode (TmpDevicePath);
  }

For more context this is the UDK callstack of where i'm stuck

DxeCore.dll!CoreLocateDevicePath(GUID * Protocol, EFI_DEVICE_PATH_PROTOCOL * * DevicePath, void * * Device) Line 452    C
DxeCore.dll!CoreLoadImageCommon(unsigned char BootPolicy, void * ParentImageHandle, EFI_DEVICE_PATH_PROTOCOL * FilePath, void * SourceBuffer, unsigned int SourceSize, unsigned __int64 DstBuffer, unsigned int * NumberOfPages, void * * ImageHandle, unsigned __int64 * EntryPoint, unsigned int Attribute) Line 1089 C
DxeCore.dll!CoreLoadImage(unsigned char BootPolicy, void * ParentImageHandle, EFI_DEVICE_PATH_PROTOCOL * FilePath, void * SourceBuffer, unsigned int SourceSize, void * * ImageHandle) Line 1425    C
MyApplication.dll!efi_main(void * ImageHandle, EFI_SYSTEM_TABLE * SystemTable) Line 2588    C
Without Me It Just Aweso
  • 4,593
  • 10
  • 35
  • 53
  • The `Length` field is 2-byte Why the manual byte-wise assignment? If your build architecture has the same endianness as your target architecture, it's a straight assignment. – unixsmurf Jul 09 '15 at 15:14
  • I get compile errors when trying to assign directly with out dereferencing length. I could cast it to a short and assign directly that way I suppose – Without Me It Just Aweso Jul 10 '15 at 17:15

1 Answers1

1

Found my answer, sharing here for others:

I based my original mempath off of the grub source:http://git.savannah.gnu.org/cgit/grub.git/tree/grub-core/loader/arm64/linux.c?id=7a210304ebfd6d704b4fc08fe496a0c417441879#n249

I changed the type of end point to instance, the size field of the header. I properly exit the loop now. My original header had the size of the entire structure, so I believe when trying to iterate to the next endpoint it was winding up with an invalid one, instead of going to my correct second element. Here is what I used:

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);
Without Me It Just Aweso
  • 4,593
  • 10
  • 35
  • 53
  • 1
    (Sorry for the delay, have been a bit preoccupied.) You've also changed the mempath[0].Length contents from "sizeof(mempath)" to "sizeof(MEMMAP_DEVICE_PATH)". How is mempath defined? Could you just check if this change in itself resolves the issue you were seeing? The UEFI description of the meaning of "End this instance..." does not seem to be valid for this use. – unixsmurf Jul 13 '15 at 11:55
  • Good catch, I kept tweaking everything that i'd forgotten about that change. I went back and checked and looks like the size change is what made it work. Edited my above – Without Me It Just Aweso Jul 13 '15 at 15:04
  • 1
    Glad to hear it works! Could you do one final edit - adding your definition of mempath to the question and answer, so that the problem and solution may be more clear to future readers? – unixsmurf Jul 13 '15 at 15:13
  • Added definition of mempath back to original question. Thanks for all your help! – Without Me It Just Aweso Jul 13 '15 at 16:17
  • If you have time I have yet another question.. seems like I get through one hoop just to fail on the next: http://stackoverflow.com/questions/31390855/uefi-loadimage-unsupported-type – Without Me It Just Aweso Jul 13 '15 at 18:33