如何加载存储在 Windows FAT32 分区中的 EFI 二进制文件

How to load an EFI Binary stored in Windows FAT32 Partition

我正在编写一个 UEFI 应用程序 (A),它将加载另一个 UEFI 应用程序 (B)。这个另一个 UEFI 应用程序 (B) 存储在 Windows 分区 (FAT32) 之一上。我正在尝试从 (A) 加载 (B)。 我需要从 (A)

执行两件事
  1. 首先找到存储(B)的Windows分区(卷)。
  2. 加载并启动图像 (B)。

到目前为止,我已经能够编写以下代码。

EFI_STATUS
UefiMain(
    EFI_HANDLE          image_handle,
    EFI_SYSTEM_TABLE    *st
) {
    EFI_BOOT_SERVICES * bs = st->BootServices;
    
    // set the gloabl service table before we do anything else
    g_st = st;
    
    EFI_HANDLE*         handle;
    UINTN               n_handle ;
    EFI_STATUS          status;

    status = bs->LocateHandleBuffer(ByProtocol,
                                &gEfiSimpleFileSystemProtocolGuid,
                                NULL,
                                &n_handle,
                                &handle);

    if (EFI_ERROR (status)) 
    {
        print((CHAR16 *) L"LocateHandle Failed : ");
        print_hex_dword(status);
        print((CHAR16 *) L"\n");
        return EFI_SUCCESS;
    }

    print((CHAR16 *) L" n_handle : ");
    print_hex_dword(n_handle);
    print((CHAR16 *) L"\n");
    
    for (UINTN i=0; i<n_handle; i++) 
    {
            
        EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *protocol;
        status = bs->OpenProtocol(handle[i],
                                        &gEfiSimpleFileSystemProtocolGuid,
                                        (void**)&protocol,
                                        image_handle,
                                        NULL,
                                        EFI_OPEN_PROTOCOL_GET_PROTOCOL);

        if (EFI_ERROR (status)) 
        {
            print((CHAR16 *) L"OpenProtocol Failed : ");
            print_hex_dword(status);
            print((CHAR16 *) L"\n");
            return EFI_SUCCESS;
        }

        EFI_FILE_PROTOCOL *volume_root;
            
        status = protocol->OpenVolume(protocol, &volume_root);
        if (EFI_ERROR (status)) 
        {
            print((CHAR16 *) L"OpenVolume Failed : ");
            print_hex_dword(status);
            print((CHAR16 *) L"\n");
            return EFI_SUCCESS;
        }
        
        EFI_FILE_PROTOCOL* root;
        status = volume_root->Open(volume_root,
                                                &root,
                                                (CHAR16 *)L"MY_FOLDER\myB.efi",
                                                EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM);
        
        if (EFI_ERROR (status)) 
        {
            print((CHAR16 *) L"Open Failed :");
            print_hex_dword(status);
            print((CHAR16 *) L"\n");
            continue;
        }
        else
        {
            print((CHAR16 *) L"Open is Success\n");
        }

        //get file info, two try process
        EFI_FILE_INFO* file_info = 0;
        UINTN file_info_size = 0;
        status = root->GetInfo(root, &FileInfoGuid, &file_info_size, 0 );

        if (status != EFI_BUFFER_TOO_SMALL )
        {
            //ErrorPrint(L"Failed to stat file '%s'. (Error %d)\r\n", filename, res);
            print((CHAR16 *) L"GetInfo Failed :");
            print_hex_dword(status);
            print((CHAR16 *) L"\n");
            return EFI_NOT_FOUND ;
        }

        status = bs->AllocatePool(EfiLoaderData, file_info_size, (void**) &file_info);
        if (status)
        {
            //ErrorPrint(L"Failed to allocate file info memory. (Error %d)\r\n", res);
            print((CHAR16 *) L"AllocatePool Failed :");
            print_hex_dword(status);
            print((CHAR16 *) L"\n");
            return EFI_OUT_OF_RESOURCES ;
        }

        status = root->GetInfo(root, &FileInfoGuid, &file_info_size,(void*) file_info);

        print((CHAR16 *) L"FileSize :");
        print_hex_dword(file_info->FileSize);
        print((CHAR16 *) L"\n");
    
    }
    
    return EFI_SUCCESS;
}

我无法继续进行。 我相信我需要为 (B) 应用程序获取 DevicePath,但我不确定该怎么做。 任何指针都会有所帮助。

谢谢。

一旦你成功打开文件,你可以使用FileDevicePath(handle[i], L"MY_FOLDER\myB.efi")(如果使用EDK2 or GNU-EFI你应该有)得到一个指向文件的EFI_DEVICE_PATH。然后你可以像下面这样加载图像

// Set this from within the loop or break with an appropriate i.
EFI_DEVICE_PATH *path = FileDevicePath(handle[i], L"MY_FOLDER\myB.efi");

EFI_HANDLE *img;
status = bs->LoadImage(false, image_handle, path, NULL, 0, &img)

if (EFI_ERROR(status)) {
     print((CHAR16*) L"Failed to load image!");
     return status;
}

status = bs->StartImage(img, NULL, NULL);

// We'll get here if the child image exits or if it fails to load
if (EFI_ERROR(status)) {
    print((CHAR16*) L"Failed to start image!");
}