UEFI Resolve полный путь

Я работаю над своего рода загрузчиком с использованием GNU-EFI. До сих пор я был в состоянии прочитать Boot#### Переменная NVRAM, поэтому у меня полузаполненная FilePathList[], который выглядит так (напечатано с DevicePathToStr):

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

Когда прошло LoadImage это терпит неудачу с EFI_NOT_FOUND, Насколько я понимаю (UEFI Doc Section 3.1.2), мне нужно добавить полный путь до того, что у меня уже есть. Я узнал, что правильный путь PciRoot(0x0)/Pci(0x1, 0x1)/Ata(0x0), но я не уверен, как я программно нахожу этот путь, основываясь на том, что у меня есть, чтобы к нему можно было присоединиться.

Код, который у меня есть, следующий: прошу прощения за низкое качество, я просто пытался заставить что-то работать до сих пор.

   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->GetVariable, 5,
         L"BootOrder", /*VariableName*/
         &vendor, /*VendorGuid*/
         &Attr, /*Attributes*/
         &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->GetVariable, 5,
            name,
            &vendor,
            &Attr,
            &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]&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"&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 < *FilePathListLength+1; i++) {
      Print(L"        &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"    &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->LoadImage, 6,
   /* status = BS->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");

Какие функции и потоки необходимы мне для полной квалификации FilePathList так что это может быть использовано с LoadImage?

1 ответ

Решение

Поверьте, когда я обращаюсь за помощью, я решаю это.

Общая идея заключается в использовании LocateHandleBuffer найти все ручки для SIMPLE_FILE_SYSTEM_PROTOCOL, С помощью этих ручек сравните путь (используя DevicePathFromHandle) к чему мы уже должны найти подходящее устройство. LoadImage сейчас у меня работает.

Пример кода ниже (buf это значение Boot#### переменная от GetVariable):

   Print(L"Description = %s\n", (CHAR16*)buf + 3);
   EFI_DEVICE_PATH *BootX = (EFI_DEVICE_PATH*) (((UINT8*)buf) + (sizeof(UINT32) + sizeof(UINT16) + StrSize(buf+3)));

   UINTN NoHandles = 0;
   EFI_HANDLE *handles = NULL;
   EFI_GUID SimpleFileSystemGUID = SIMPLE_FILE_SYSTEM_PROTOCOL;
   status = uefi_call_wrapper(BS->LocateHandleBuffer,
         5,
         ByProtocol,
         &SimpleFileSystemGUID,
         NULL,
         &NoHandles,
         &handles
         );
   if (status != EFI_SUCCESS)
      Print(L"Failed to LocateHandleBuffer (%d)\n", status);
   else
      Print(L"LocateHandleBuffer OK (%d handles)\n", NoHandles);

   EFI_DEVICE_PATH *prefix;
   UINTN index;
   for (index = 0; index < NoHandles; index++) {
      prefix = DevicePathFromHandle(handles[index]);
      while(!IsDevicePathEnd(NextDevicePathNode(prefix))) prefix = NextDevicePathNode(prefix);
      if(LibMatchDevicePaths(prefix, BootX)) {
         break;
      } else {
         FreePool(prefix);
      }
   }

   prefix = DevicePathFromHandle(handles[index]);
   // prefix ends with the same node that BootX starts with
   // so skip forward BootX so we can prepend prefix
   BootX = NextDevicePathNode(BootX);
   EFI_DEVICE_PATH *fullpath = AppendDevicePath(prefix, BootX);
   Print(L"Booting: %s\n", DevicePathToStr(fullpath));

   /* 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->LoadImage, 6,
   /* status = BS->LoadImage( */
         TRUE, /* BootPolicy */
         ImageHandle, /* ParentImageHandle */
         fullpath, /* 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");
Другие вопросы по тегам