UEFI应用调用gRT->GetVariable()返回Not Found问题求助
在搭载Ubuntu系统的QEMU环境中,编写的UEFI应用调用gRT->GetVariable()读取名为my_variable的变量时,返回Not Found状态,但通过Ubuntu脚本设置变量后,在UEFI Shell中使用dmpstore命令可确认变量存在,值为0x64(100),且具备Non-Volatile、Boot Service Access、Runtime Service Access属性,符合UEFI应用访问的要求。
UEFI应用读取变量的核心代码:
EFI_STATUS EFIAPI UefiMain( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT8 CheckValue; UINTN DataSize = sizeof(CheckValue); UINT32 Attributes; Status = gRT->GetVariable( L"my_variable", &MyGuid, &Attributes, &DataSize, &CheckValue ); if (EFI_ERROR(Status)) { Print(L"Error: variable not found. Returning\n"); return EFI_SUCCESS; } if (CheckValue != 100) { Print(L"Variable is not set to 100. Returning\n"); return EFI_SUCCESS; } // 后续逻辑(省略) return EFI_SUCCESS; }
Ubuntu设置变量的脚本:
#!/bin/bash VAR_NAME="my_variable" GUID="12345678-1234-1234-1234-123456789abc" DATA_FILE="/tmp/check_data" echo -ne '\x07\x00\x00\x00\x64' > "$DATA_FILE" sudo efivar --name "${GUID}-${VAR_NAME}" --write --data "$DATA_FILE" rm "$DATA_FILE"
1. 确认GUID完全匹配
UEFI变量通过GUID+变量名唯一标识,必须确保代码中的MyGuid定义与脚本中的GUID完全一致,包括字节序和大小写:
- 脚本中的GUID为
12345678-1234-1234-1234-123456789abc,对应的C语言GUID定义应为:
EFI_GUID MyGuid = { 0x12345678, 0x1234, 0x1234, {0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc} };
- 常见错误:Data4的字节顺序颠倒,或GUID某一段数值写错。
2. 检查变量名的Unicode编码一致性
UEFI变量名采用UTF-16LE编码,代码中L"my_variable"会生成正确的UTF-16LE字符串,需确保:
- 脚本中的
VAR_NAME与代码中的变量名完全一致(大小写、拼写无错误)。 - 纯ASCII名称无需额外编码处理,
efivar会自动转换为UTF-16LE。
3. 修正变量数据格式
脚本中写入的前4字节\x07\x00\x00\x00属于冗余数据,UEFI变量数据部分无需前缀,直接存储原始字节流即可,建议修改脚本:
echo -ne '\x64' > "$DATA_FILE"
冗余数据虽不会直接导致Not Found,但可能引发后续读取逻辑异常。
4. 解决QEMU与主机EFI变量隔离问题
这是最可能的根本原因:Ubuntu主机的efivar操作的是主机自身的UEFI变量存储,而QEMU运行OVMF固件时默认使用独立的变量镜像文件(如OVMF_VARS.fd),两者完全隔离。
解决方法:
- 在QEMU内部设置变量:启动QEMU进入UEFI Shell,执行命令:
setvar my_variable -guid 12345678-1234-1234-1234-123456789abc -nv -bs -rt -byte 0x64 - 保存OVMF变量镜像:在UEFI Shell中设置变量后,确保QEMU启动时加载修改后的
OVMF_VARS.fd。 - QEMU启动时注入变量:通过命令行参数直接传递变量(需QEMU支持):
qemu-system-x86_64 ... -global driver=efi-variable,property=variable-name,value="my_variable" -global driver=efi-variable,property=variable-guid,value="12345678-1234-1234-1234-123456789abc" -global driver=efi-variable,property=variable-data,value="\x64"
5. 验证UEFI应用的编译链接
确保代码中的MyGuid已正确定义并链接:
- 检查编译时是否存在
MyGuid未定义的警告/错误,未定义的GUID会导致传递给GetVariable的地址无效,进而返回Not Found。 - 确认GUID定义已包含在编译范围内,或通过头文件正确引入。
6. 检查变量属性的有效性
确保变量未被设置EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS或EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS属性,这类属性会限制未授权的读取操作。若存在此类属性,需重新设置变量时移除,或在代码中添加认证逻辑。
内容的提问来源于stack exchange,提问作者Cantaff0rd

