UEFI Resolve full path
<p>I'm working on a bootloader of sorts using GNU-EFI. So far I've been able to read the <code>Boot####</code> NVRAM variable, so I have a semi-populated <code>FilePathList[]</code>, which looks like this (printed with <code>DevicePathToStr</code>):</p>

<p><code>HD(Part2, SigCD0400E6-54F3-49F4-81F2-65B21E8278A8)/\EFI\Microsoft\Boot\bootmgfw.efi</code></p>

<p>When passed to <code>LoadImage</code> it fails with <code>EFI_NOT_FOUND</code>. As I understand it <a href="http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf" rel="nofollow noreferrer">(UEFI Doc Section 3.1.2)</a>, I need to add the full path before what I already have. I've found out that the correct path is <code>PciRoot(0x0)/Pci(0x1, 0x1)/Ata(0x0)</code>, but I am unsure how I programmatically find this path based on what I have so it can be prepended.</p>

<p>The code I have so far is as follows, please excuse the low quality, I've just been trying to get something working so far.</p>

<pre><code>   EFI_STATUS status;
   EFI_GUID vendor = EFI_GLOBAL_VARIABLE;
   UINT32 Attr;

   UINTN size = 256;
   UINT16 *buf = AllocateZeroPool(size);
   if (buf == NULL)
      Print(L"Failed to allocate buffer\n");

   status = uefi_call_wrapper(RT-&gt;GetVariable, 5,
         L"BootOrder", /*VariableName*/
         &amp;vendor, /*VendorGuid*/
         &amp;Attr, /*Attributes*/
         &amp;size, /*DataSize*/
         buf /*Data*/
         );
   if (status != EFI_SUCCESS)
      Print(L"Failed to read BootOrder (%d)\n", status);

   // should contain an int for the correct boot option
   UINT16 bootopt = buf[0];
   FreePool(buf);

   CHAR16 *name = AllocateZeroPool(18); // Bootxxxx\0 unicode
   SPrint(name, 18, L"Boot%04x", bootopt);

   Print(L"Next boot: %s\n", name);

   size = 0;
   do {
      buf = AllocateZeroPool(size);
      if (buf == NULL)
         Print(L"Failed to allocate buffer\n");

      status = uefi_call_wrapper(RT-&gt;GetVariable, 5,
            name,
            &amp;vendor,
            &amp;Attr,
            &amp;size,
            buf
            );
      if (status == EFI_SUCCESS) break;

      FreePool(buf);
      // if it fails, size is set to what it needs to be
      // handy that
   } while(status == EFI_BUFFER_TOO_SMALL);

   if (!(buf[0]&amp;LOAD_OPTION_ACTIVE)) Print(L"BootOption not active\n");
   Print(L"%s: 0x%r\n\n", name, buf);

   UINT8 *OrigFilePathList = ((UINT8*)buf) + (sizeof(UINT32) + sizeof(UINT16) + StrSize(buf+3));
   UINT16 *FilePathListLength = ((UINT16*)OrigFilePathList)+2;

   Print(L"&amp;OrigFilePathList = 0x%r\n", OrigFilePathList);
   Print(L"sizeof(_EFI_LOAD_OPTION) = %d\n", size);
   Print(L"struct _EFI_LOAD_OPTION {\n");
   Print(L"    Attributes = %d\n", *(UINT32 *)(buf));
   Print(L"    FilePathListLength = %d,\n", *FilePathListLength);
   Print(L"    Description = %s,\n", buf+3);
   Print(L"    FilePathList[] = {\n");

   UINT16 totallength = 0;

   UINT8 *FilePathList = OrigFilePathList;
   for (UINT8 i = 0; i &lt; *FilePathListLength+1; i++) {
      Print(L"        &amp;FilePathList[%d] = 0x%r\n", i, OrigFilePathList);
      Print(L"        FilePathList[%d].Type = %d ", i, *OrigFilePathList);
      switch (*OrigFilePathList) {
         case 0x01:
            Print(L"(Hardware Device Path)\n");
            break;
         case 0x02:
            Print(L"(ACPI Device Path)\n");
            break;
         case 0x03:
            Print(L"(Messaging Device Path)\n");
            break;
         case 0x04:
            Print(L"(Media Device Path)\n");
            break;
         case 0x05:
            Print(L"(BIOS Boot Specification Device Path)\n");
            break;
         case 0x7f:
            Print(L"(End Of Hardware Device Path)\n");
            break;
         default:
            Print(L"(Unknown Device Path)\n");
            break;
      }
      Print(L"        FilePathList[%d].SubType = %d\n", i, *(OrigFilePathList+1));
      Print(L"        FilePathList[%d].Length = %d\n", i, *(UINT16*)(OrigFilePathList+2));
      totallength += *(UINT16*)(OrigFilePathList+2);

      OrigFilePathList += *(UINT16*)(OrigFilePathList+2);
   }
   Print(L"    }\n");
   Print(L"    &amp;OptionalData = 0x%r\n", OrigFilePathList);
   Print(L"    OptionalDataLength = %d\n", size-totallength);
   Print(L"}\n");

   // The hard drive device path can be appended to the matching hardware
   // device path and normal boot behavior can then be used.

   // We need to locate the Type 1 FilePathList and prepend it to what we've already got

   // Need to prefix PciRoot(0x0)/Pci(0x1, 0x1)/Ata(0x0)
   // but automatically find it
   // in theory we should be able to use the list of handles to devices that support SIMPLE_FILE_SYSTEM_PROTOCOL
   // to find the right device

   Print(L"%s\n", DevicePathToStr((EFI_DEVICE_PATH *)FilePathList));

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

   EFI_HANDLE *NextHandle = AllocateZeroPool(sizeof(EFI_HANDLE));

   status = uefi_call_wrapper(BS-&gt;LoadImage, 6,
   /* status = BS-&gt;LoadImage( */
         TRUE, /* BootPolicy */
         ImageHandle, /* ParentImageHandle */
         (EFI_DEVICE_PATH *)FilePathList, /* DevicePath */
         NULL, /* SourceBuffer */
         0, /* SourceSize */
         NextHandle /* ImageHandle */
         );

   if (status != EFI_SUCCESS)
      Print(L"Failed to LoadImage (%d)\n", status);
   else
      Print(L"LoadImage OK\n");
</code></pre>

<p>What functions and flows are required for me to fully qualify the <code>FilePathList</code> so it can be used with <code>LoadImage</code>?</p>