2016-11-30 20 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

私が助けを求めたときに、私はそれを解決します。

SIMPLE_FILE_SYSTEM_PROTOCOLのすべてのハンドルを見つけるには、LocateHandleBufferを使用するのが一般的な考えです。これらのハンドルで、適切なデバイスを見つけるためにパス(DevicePathFromHandleを使用)を比較してください。​​は現在私のために働いています。

以下のサンプルコード(bufGetVariableからBoot####変数の値である):

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");