3. UEFI应用退出与返回
任务目标
编写一个UEFI应用,演示两种退出方式:通过gRT->ResetSystem()直接重启系统,以及通过返回错误码将控制权交还固件。应用启动后打印当前退出模式,执行对应操作,并验证退出路径正确。
实现原理
UEFI应用由固件通过LoadImage/StartImage加载执行。应用退出有两种标准方式:
- 返回错误码:从入口点函数
efi_main()返回非EFI_SUCCESS值,固件会回收应用占用的资源并将控制权交还BDS(启动设备选择)阶段。 - 调用
gRT->ResetSystem():通过系统表获取Runtime Services指针,调用重启服务,立即复位系统。
本案例通过命令行参数(或编译期宏)选择退出模式,便于观察两种路径的行为差异。
完整代码
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
// 退出模式选择:0=返回错误码,1=ResetSystem重启
#define EXIT_MODE_RETURN 0
#define EXIT_MODE_RESET 1
EFI_STATUS
EFIAPI
efi_main (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINTN Mode = EXIT_MODE_RETURN; // 默认返回错误码
// 初始化控制台输出
Status = SystemTable->ConOut->Reset(SystemTable->ConOut, FALSE);
if (EFI_ERROR(Status)) {
return Status;
}
// 简单解析命令行参数(可选:通过Shell传递)
// 此处使用固定模式,实际可通过gRT->GetVariable或Shell参数扩展
// 为演示清晰,直接编译期决定模式
Print(L"UEFI Exit Demo Start...\r\n");
#if defined(EXIT_MODE) && (EXIT_MODE == EXIT_MODE_RESET)
Mode = EXIT_MODE_RESET;
#endif
if (Mode == EXIT_MODE_RESET) {
Print(L"Mode: ResetSystem - System will reboot in 3 seconds...\r\n");
// 延迟3秒便于观察
gBS->Stall(3000000); // 3,000,000 微秒 = 3秒
Print(L"Calling ResetSystem (EfiResetCold)...\r\n");
gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
// 不应执行到这里
Print(L"ERROR: ResetSystem returned!\r\n");
return EFI_DEVICE_ERROR;
} else {
Print(L"Mode: Return Error Code - Exiting to Firmware...\r\n");
Print(L"Returning EFI_INVALID_PARAMETER (0x%x)\r\n", EFI_INVALID_PARAMETER);
// 返回非成功码,固件回收资源并继续启动流程
return EFI_INVALID_PARAMETER;
}
}
编译与运行
环境依赖:EDK2开发环境(含OVMF模拟器或真实UEFI平台)。
- 将上述代码保存为
ExitDemo.c,放入EDK2应用工程目录(如OvmfPkg/ExitDemo/)。 - 创建
ExitDemo.inf文件:
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = ExitDemo
FILE_GUID = 8A2B3C4D-5E6F-4A7B-8C9D-0E1F2A3B4C5D
MODULE_TYPE = UEFI_APPLICATION
ENTRY_POINT = efi_main
[Sources]
ExitDemo.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiLib
UefiBootServicesTableLib
BaseMemoryLib
- 编译(以OVMF为例):
build -p OvmfPkg/OvmfPkgX64.dsc -m OvmfPkg/ExitDemo/ExitDemo.inf
- 运行:将生成的
ExitDemo.efi放入FAT格式的启动盘或OVMF虚拟磁盘,在UEFI Shell中执行:
fs0:\> ExitDemo.efi
验证方法
| 模式 | 预期行为 | 通过标准 |
|---|---|---|
| 默认(返回错误码) | 打印"Returning EFI_INVALID_PARAMETER"后Shell提示符立即返回 | Shell无挂起,可继续输入命令;固件未重启 |
ResetSystem模式(编译时加-DEXIT_MODE=1) | 打印重启提示,3秒后系统冷重启 | 观察OVMF窗口重新启动,出现固件Logo或Shell重新加载 |
判定说明:返回错误码模式若Shell卡死或系统重启,说明入口点未正确返回;ResetSystem模式若3秒后未重启,检查gRT指针是否有效(通常由EDK2自动初始化,无需手动获取)。
常见问题
- 编译报错
gRT未定义:需在.inf的[LibraryClasses]中添加UefiRuntimeServicesTableLib,并在源码包含Library/UefiRuntimeServicesTableLib.h。 - ResetSystem后仍打印错误信息:正常情况不会执行到该行;若出现,说明ResetSystem调用失败(极少见),可检查ResetType参数是否合法。
- 返回错误码后Shell无响应:确认返回的是非
EFI_SUCCESS值(如EFI_INVALID_PARAMETER),且未在返回前调用gBS->Exit()——两者只能选其一。