2016-11-30 369 views
1

我正在使用GNU-EFI進行各種引導加載程序。到目前爲止,我已經能夠閱讀Boot#### NVRAM變量,所以我有一個半填充FilePathList[],它看起來像這樣(印有DevicePathToStr):UEFI解決完整路徑

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

當傳遞給​​它失敗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因此它可與​​使用需要?

回答

1

相信當我尋求幫助時,我會努力工作。

總體思路是使用LocateHandleBuffer查找SIMPLE_FILE_SYSTEM_PROTOCOL的所有句柄。使用這些手柄,比較路徑(使用DevicePathFromHandle)與我們已經找到適當設備的路徑。​​現在適合我。下面

示例代碼(bufBoot####可變的從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");