UEFI解决完整路径 [英] UEFI Resolve full path

查看:616
本文介绍了UEFI解决完整路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用GNU-EFI进行各种引导加载程序.到目前为止,我已经能够读取Boot#### NVRAM变量,所以我有一个半填充的FilePathList[],它看起来像这样(用DevicePathToStr打印):

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

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

当传递给LoadImage时,它会失败,并显示EFI_NOT_FOUND.据我了解,(UEFI文档第3.1.2节) ,我需要在已有路径之前添加完整路径.我发现正确的路径是PciRoot(0x0)/Pci(0x1, 0x1)/Ata(0x0),但是我不确定如何根据自己的方式以编程方式找到该路径,因此可以将其作为前缀.

When passed to LoadImage it fails with EFI_NOT_FOUND. As I understand it (UEFI Doc Section 3.1.2), I need to add the full path before what I already have. I've found out that the correct path is PciRoot(0x0)/Pci(0x1, 0x1)/Ata(0x0), but I am unsure how I programmatically find this path based on what I have so it can be prepended.

到目前为止,我的代码如下,请原谅我的代码质量低下,到目前为止,我一直在尝试使某些代码正常工作.

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.

   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一起使用?

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

推荐答案

当我寻求帮助时,请相信我会解决的.

Trust that when I've asked for help I work it out.

通常的想法是使用LocateHandleBuffer查找SIMPLE_FILE_SYSTEM_PROTOCOL的所有句柄.使用这些句柄,将路径(使用DevicePathFromHandle)与我们已经找到合适设备所需的路径进行比较. LoadImage现在对我有用.

The general idea is to use LocateHandleBuffer to find all handles for SIMPLE_FILE_SYSTEM_PROTOCOL. With these handles, compare the path (using DevicePathFromHandle) to what we already have to find the appropriate device. LoadImage now works for me.

下面的示例代码(bufGetVariableBoot####变量的值):

Sample code below (buf is the value of the Boot#### variable from 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");

这篇关于UEFI解决完整路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆