2016-11-30 4 views
1

GNU-EFI를 사용하는 부트 로더에서 작업 중입니다. 지금까지 내가 Boot#### NVRAM 변수를 읽을 수 있었다, 그래서 나는이 반 채워 FilePathList[]을, (DevicePathToStr 인쇄) 다음과 같습니다 LoadImage에 전달하면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"); 
나를 완전히 그래서이 LoadImage 함께 사용할 수있는 FilePathList을 한정에 필요한 어떤 기능과 흐름

?

답변

1

내가 도움을 요청했을 때 그것을 해결해 줄 것을 믿어 라.

SIMPLE_FILE_SYSTEM_PROTOCOL의 모든 핸들을 찾으려면 LocateHandleBuffer을 사용하는 것이 일반적입니다. 이 핸들을 사용하여 경로 (DevicePathFromHandle 사용)를 이미 적절한 장치를 찾아야하는 것과 비교하십시오. LoadImage이 이제 저에게 효과적입니다.

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

샘플 코드 (bufGetVariable에서 Boot#### 변수의 값이다)