2016-11-30 3 views
1

Je travaille sur un chargeur de démarrage en utilisant GNU-EFI. Jusqu'à présent, j'ai pu lire la variable Boot#### NVRAM, j'ai donc une population semi-FilePathList[], qui ressemble à ceci (imprimé DevicePathToStr):UEFI Résoudre le chemin complet

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

Lorsqu'il est passé à LoadImage il échoue avec EFI_NOT_FOUND . Si je comprends bien (UEFI Doc Section 3.1.2), j'ai besoin d'ajouter le chemin complet avant ce que j'ai déjà. J'ai découvert que le chemin correct est PciRoot(0x0)/Pci(0x1, 0x1)/Ata(0x0), mais je ne sais pas comment je trouve ce chemin par programme en fonction de ce que j'ai afin qu'il puisse être ajouté.

Le code que j'ai jusqu'à maintenant est le suivant, excusez s'il vous plaît la faible qualité, je viens d'essayer de faire fonctionner quelque chose jusqu'à présent.

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

Quelles sont les fonctions et les flux sont nécessaires pour me qualifier complètement la FilePathList de sorte qu'il peut être utilisé avec LoadImage?

Répondre

1

Ayez confiance que lorsque j'ai demandé de l'aide, je me débrouille. L'idée générale est d'utiliser LocateHandleBuffer pour trouver toutes les poignées pour SIMPLE_FILE_SYSTEM_PROTOCOL. Avec ces poignées, comparez le chemin (en utilisant DevicePathFromHandle) à ce que nous avons déjà pour trouver le périphérique approprié. LoadImage travaille maintenant pour moi.

exemple de code suivant (buf est la valeur de la variable Boot#### de 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");