How to load an EFI Binary stored in Windows FAT32 Partition
I am writing an UEFI application (A) which will load another UEFI application (B). This another UEFI application (B) is stored on one of the Windows Partition (FAT32). I am trying to load (B) from (A). Two things I need to perform from (A)
- First of all locate the Windows Partition (Volume) where (B) is stored.
- Load and Start Image (B).
So far I have been able to write following code.
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;
}
I am not able to proceed further. I believe that I will need to get DevicePath for the (B) application but I am not sure how to do that. Any pointer will be helpful.
Thanks.
Once you've successfully opened the file, you can use FileDevicePath(handle[i], L"MY_FOLDER\\myB.efi")
(which you should have if using EDK2 or GNU-EFI) to get an EFI_DEVICE_PATH
which points to the file. Then you can load the image with something like as follows
// 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!");
}