这里提供一个在一个EFI程序中启动另外一个EFI 的例子,没有使用 UEFI Shell API ,放置在 ESP 分区后,可以启动当前的 Windows。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/SimpleFileSystem.h>
#include <Guid/FileInfo.h>
/**
* 启动指定路径的 EFI 应用程序
*/
EFI_STATUS
StartEfiApplication (
IN EFI_HANDLE ParentImageHandle,
IN CHAR16 *ApplicationPath
)
{
EFI_STATUS Status;
EFI_HANDLE ChildImageHandle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_LOADED_IMAGE_PROTOCOL *ParentLoadedImage;
UINTN ExitDataSize;
CHAR16 *ExitData;
Print(L"=== Starting EFI Application: %s ===\n", ApplicationPath);
// 步骤 1: 获取父镜像的 LoadedImage 协议
Status = gBS->HandleProtocol(
ParentImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID**)&ParentLoadedImage
);
if (EFI_ERROR(Status)) {
Print(L"ERROR: Failed to get parent LoadedImage protocol: %r\n", Status);
return Status;
}
Print(L"SUCCESS: Got parent LoadedImage protocol\n");
// 步骤 2: 构建目标应用的设备路径
DevicePath = FileDevicePath(ParentLoadedImage->DeviceHandle, ApplicationPath);
if (DevicePath == NULL) {
Print(L"ERROR: Failed to create device path for %s\n", ApplicationPath);
return EFI_OUT_OF_RESOURCES;
}
Print(L"SUCCESS: Created device path\n");
// 步骤 3: 加载目标镜像
Status = gBS->LoadImage(
FALSE, // BootPolicy - FALSE 表示不是启动策略
ParentImageHandle, // ParentImageHandle - 父镜像句柄
DevicePath, // DevicePath - 目标文件的设备路径
NULL, // SourceBuffer - NULL 表示从设备路径加载
0, // SourceSize - 0 表示从设备路径加载
&ChildImageHandle // ImageHandle - 返回的子镜像句柄
);
// 释放设备路径内存
FreePool(DevicePath);
if (EFI_ERROR(Status)) {
Print(L"ERROR: LoadImage failed: %r\n", Status);
return Status;
}
Print(L"SUCCESS: Image loaded successfully, Handle = 0x%lx\n", (UINTN)ChildImageHandle);
// 步骤 4: 启动镜像
Print(L"Starting image...\n");
Status = gBS->StartImage(
ChildImageHandle, // ImageHandle - 要启动的镜像句柄
&ExitDataSize, // ExitDataSize - 返回退出数据大小
&ExitData // ExitData - 返回退出数据
);
// 步骤 5: 处理启动结果
if (EFI_ERROR(Status)) {
Print(L"ERROR: StartImage failed: %r\n", Status);
// 如果有退出数据,显示它
if (ExitData != NULL && ExitDataSize > 0) {
Print(L"Exit Data Size: %d bytes\n", ExitDataSize);
Print(L"Exit Data: %s\n", ExitData);
// 释放退出数据内存
gBS->FreePool(ExitData);
}
} else {
Print(L"SUCCESS: Image started and returned: %r\n", Status);
// 处理正常退出的数据
if (ExitData != NULL && ExitDataSize > 0) {
Print(L"Application returned data: %s\n", ExitData);
gBS->FreePool(ExitData);
}
}
// 步骤 6: 卸载镜像(如果需要)
Print(L"Unloading image...\n");
gBS->UnloadImage(ChildImageHandle);
Print(L"=== Application execution completed ===\n\n");
return Status;
}
/**
* 检查文件是否存在
*/
EFI_STATUS
CheckFileExists (
IN EFI_HANDLE DeviceHandle,
IN CHAR16 *FilePath
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
EFI_FILE_PROTOCOL *Root;
EFI_FILE_PROTOCOL *File;
// 获取文件系统协议
Status = gBS->HandleProtocol(
DeviceHandle,
&gEfiSimpleFileSystemProtocolGuid,
(VOID**)&FileSystem
);
if (EFI_ERROR(Status)) {
return Status;
}
// 打开根目录
Status = FileSystem->OpenVolume(FileSystem, &Root);
if (EFI_ERROR(Status)) {
return Status;
}
// 尝试打开目标文件
Status = Root->Open(
Root,
&File,
FilePath,
EFI_FILE_MODE_READ,
0
);
if (!EFI_ERROR(Status)) {
Print(L"File exists: %s\n", FilePath);
File->Close(File);
} else {
Print(L"File not found: %s (Status: %r)\n", FilePath, Status);
}
Root->Close(Root);
return Status;
}
/**
* 主入口函数
*/
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_INPUT_KEY Key;
// 清屏
gST->ConOut->ClearScreen(gST->ConOut);
Print(L"UEFI StartImage Example Application\n");
Print(L"====================================\n\n");
// 获取当前镜像信息
Status = gBS->HandleProtocol(
ImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID**)&LoadedImage
);
if (EFI_ERROR(Status)) {
Print(L"Failed to get LoadedImage protocol: %r\n", Status);
return Status;
}
// 示例 : 启动 Windows Boot Manager
Print(L"Example 1: Starting Windows Boot Manager\n");
CheckFileExists(LoadedImage->DeviceHandle, L"EFI\\Boot\\bootx64.efi");
Status = StartEfiApplication(ImageHandle, L"EFI\\Boot\\bootx64.efi");
Print(L"Windows Boot Manager result: %r\n\n", Status);
// 等待用户按键
Print(L"Press any key to exit...\n");
gST->ConIn->Reset(gST->ConIn, FALSE);
while (gST->ConIn->ReadKeyStroke(gST->ConIn, &Key) == EFI_NOT_READY) {
gBS->Stall(10000); // 等待 10ms
}
return EFI_SUCCESS;
}
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = sat
FILE_GUID = 4ea97c46-7491-2025-1125-747010f3ce5f
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = UefiMain
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
StartImageTest.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
UefiBootServicesTableLib
[Protocols]
gEfiLoadedImageProtocolGuid
gEfiSimpleFileSystemProtocolGuid
gEfiSimpleTextInProtocolGuid
gEfiSimpleTextOutProtocolGuid
[BuildOptions]
[Guids]