对于概念验证项目,我使用 CONFIG_EFI_STUB 构建了一个 Linux 内核映像,我从 u-boot 预引导的 Shell.efi 启动该映像。从 linux shell 挂载 efivarfs 后,Shell.efi 设置的环境变量可见。
sh-5.1# mount -t efivarfs efivarfs /sys/firmware/efi/efivars
sh-5.1# cd /sys/firmware/efi/efivars
sh-5.1# mount | grep efivars
efivarfs on /sys/firmware/efi/efivars type efivarfs (ro,relatime)
sh-5.1# ls
AuditMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
DeployedMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
OsIndications-8be4df61-93ca-11d2-aa0d-00e098032b8c
OsIndicationsSupported-8be4df61-93ca-11d2-aa0d-00e098032b8c
PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c
PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c
SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
TEST2-8be4df61-93ca-11d2-aa0d-00e098032b8c
VendorKeys-8be4df61-93ca-11d2-aa0d-00e098032b8c
sh-5.1# hexdump TEST2-8be4df61-93ca-11d2-aa0d-00e098032b8c
0000000 0007 0000 0022 0048 0049 0022
000000c
其中 TEST2... 是我从 Shell.efi 设置的环境变量。
但是,如果我尝试从 Linux 设置 EFI 变量(在以读写模式手动安装之后),它就会退出。
sh-5.1# mount -o remount,rw -t efivarfs efivarfs /sys/firmware/efi/efivars
sh-5.1# mount | grep efivars
efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,relatime)
sh-5.1# printf "\x07\x00\x00\x00\x00" > TESTVAR-8be4df61-93ca-11d2-aa0d-00e098032b8c
sh: printf: write error: Invalid argument
我确实注意到 u-boot 的 EFI lib 中的 SetVariable 实现是一个返回 EFI_UNSUPPORTED 的存根函数。
/**
* efi_set_variable_runtime() - runtime implementation of SetVariable()
*
* @variable_name: name of the variable
* @vendor: vendor GUID
* @attributes: attributes of the variable
* @data_size: size of the buffer with the variable value
* @data: buffer with the variable value
* Return: status code
*/
static efi_status_t __efi_runtime EFIAPI
efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data)
{
return EFI_UNSUPPORTED;
}
在这样的设置中,有哪些方法可以正确支持功能性 SetVariable 运行时服务?如果我从头开始实施某些东西,我是否应该注意任何陷阱/注意事项?
我尝试在 efi_set_variable_runtime() 中添加调试 printk(),但这会导致分段错误。如何为运行时服务启用调试日志记录?
在 EFI 运行时,U-Boot 没有任何设备驱动程序(某些主板上的重新启动/关闭电源除外)。它既不能打印到控制台,也不能在任何地方存储变量。
U-Boot 中 EFI 变量的一种实现使用 eMMC 的重播保护内存块 (RPMB) 进行存储。用作 OP-TEE 模块的 StandaloneMM 实现了必要的逻辑。请参阅https://u-boot.readthedocs.io/en/latest/develop/uefi/uefi.html#using-op-tee-for-efi-variables。
补丁集(https://lore.kernel.org/linux-efi/[email protected]/)建议通过与所述 OP-TEE 模块通信来在 Linux 中实现 SetVariable()并让 Linux 写入 RPMB 分区。