UEFI开发学习 - Variable Services
创始人
2025-05-31 10:33:45
0

Variable Services是Runtime Services的一部分,提供关于Variable的一些服务,Variable被定义为键值对,由标识信息加上属性(键)和任意数据(值)组成。Variable用于存储在平台实现的EFI环境和EFI OS加载器以及在EFI环境中的其他应用程序之间传递数据。(1、一个Guid可以对应多个Variable,一个Variable中包含多种不同数据类型的数据(结构体)?;2、Setup界面中的一些值就是Variable,通过这种方式来存储。)
UEFI规范为Variable Services定义了四个接口,如下表所示:

Name Type Description
GetVariable Runtime Returns the value of a variable.
GetNextVariableName Runtime Enumerates the current variable names.
SetVariable Runtime Sets the value of a variable.
QueryVariableInfo Runtime Returns information about the EFI variables.
2 接口
2.1 GetVariable这个接口的作用是返回一个指定Variable的值。
每个供应商可以使用唯一的VendorGuid创建和管理自己的变量,而不会有名称冲突的风险。当一个变量被设置时,它的Attributes被提供来指示系统应该如何存储和维护这个数据变量。属性会影响何时可以访问变量以及数据的波动性。如果EFI_BOOT_SERVICES.ExitBootServices()已经被执行,没有设置EFI_VARIABLE_RUNTIME_ACCESS属性的变量将不可见,GetVariable()将会返回一个EFI_NOT_FOUND错误。
如果Data缓冲区太小,无法保存变量的内容,则返回错误EFI_BUFFER_TOO_SMALL,并将DataSize设置为获取数据所需的缓冲区大小。
函数原型为:

typedef
EFI_STATUS
GetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes OPTIONAL,
IN OUT UINTN *DataSize,
OUT VOID *Data OPTIONAL
);
1
2
3
4
5
6
7
8
9
2.2 GetNextVariableName
这个函数的作用是枚举当前变量名。
GetNextVariableName()被调用多次以检索系统中当前可用的所有变量的VariableName和VendorGuid。在每次调用GetNextVariableName()时,前面的结果都被传递到接口中,在输出时,接口返回下一个变量名数据。当返回整个变量列表时,返回错误EFI_NOT_FOUND。
注意,如果返回EFI_BUFFER_TOO_SMALL,则返回Variable Name缓冲区对于下一个变量来说太小了。当出现这种错误时,VariableNameSize将被更新以反映所需的缓冲区大小。在调用GetNextVariableName()的所有情况下,VariableName分配的实际缓冲区大小。变量名不能小于在变量名缓冲区输入时传递给GetNextVariableName()变量名字符串的大小。
一旦执行EFI_BOOT_SERVICES.ExitBootServices(),仅在引导服务期间可见的变量将不再返回。要获取GetNextVariableName()返回的变量的数据内容或属性,需要使用GetVariable()接口。
函数原型为:

typedef
EFI_STATUS
GetNextVariableName (
IN OUT UINTN *VariableNameSize,
IN OUT CHAR16 *VariableName,
IN OUT EFI_GUID *VendorGuid
);
1
2
3
4
5
6
7
2.3 SetVariable
这个函数的作用是设置变量的值。此服务可用于创建新变量、修改现有变量的值或删除现有变量。
变量存储在固件中,并且可以在整个电源周期中保持它们的值。每个供应商都可以创建和管理自己的变量,而不用冒使用唯一变量VendorGuid而产生的命名冲突的风险。VendorGuid已经被UEFI规范用来定义一些Global Variable,可以在第三章Boot Manager下的Table3-1看到相关定义。
每个变量都具有定义固件如何存储和维护数据值的Attributes。如果EFI_VARIABLE_NON_VOLATILE属性没有设置,固件将变量存储在普通内存中,在整个电源周期不维护。这些变量用于将信息从一个组件传递到另一个组件。这方面的一个例子是固件的语言代码支持变量。它是在固件初始化时创建的,以供可能需要该信息的EFI组件访问,但不需要备份到非易失性存储。
EFI_VARIABLE_NON_VOLATILE变量存储在存储容量有限的固定硬件中;有时是严重有限的容量。软件应该只在绝对必要时使用非易失性变量。此外,如果软件使用非易失性变量,则应尽可能使用仅在引导服务时可访问的变量。
函数原型为:

typedef
EFI_STATUS
SetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
);
1
2
3
4
5
6
7
8
9
2.4 QueryVariableInfo
这个函数的作用是返回关于EFI变量的信息。
QueryVariableInfo()函数允许调用者获得关于可用于存储EFI变量的最大存储空间,可用于存储EFI变量的最大剩余存储空间的大小和每个EFI变量的最大空间,与指定的属性相关联。
函数原型为:

typedef
EFI_STATUS
QueryVariableInfo (
IN UINT32 Attributes,
OUT UINT64 *MaximumVariableStorageSize,
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
);
1
2
3
4
5
6
7
8
2.5 相关定义
2.5.1 Attribute
上述有几个接口函数有Attribute这个参数,这个参数是比较重要的,它具体有以下取值:

//*******************************************************
// Variable Attributes
//*******************************************************
#define EFI_VARIABLE_NON_VOLATILE 0x00000001
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008
//This attribute is identified by the mnemonic ‘HR’ elsewhere
//in this specification.
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
//NOTE: EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated
//and should be considered reserved.
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS \ 0x00000020
#define EFI_VARIABLE_APPEND_WRITE 0x00000040
#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS 0x00000080
//This attribute indicates that the variable payload begins
//with an EFI_VARIABLE_AUTHENTICATION_3 structure, and
//potentially more structures as indicated by fields of this
//structure. See definition below and in SetVariable().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
其中常用的就是前面三种:
(1)EFI_VARIABLE_NON_VOLATILE(NV):表示设置变量时将变量写入到非易失性介质中,比如SPI Flash;
(2)EFI_VARIABLE_BOOTSERVICE_ACCESS(BS):表示设置的变量在UEFI阶段都可以访问,更具体地说是在调用gBS->ExitBootServices()之前都可以访问,它对于操作系统是不可见的;
(3)EFI_VARIABLE_RUNTIME_ACCESS(RT):表示设置的变量在OS下都可以访问,当然前提是OS是UEFI兼容的。

UEFI规范定义了一些Global Variable,可以在第三章Boot Manager下的Table3-1看到相关定义。

3 相关Protocol
在PI规范中定义了两个Protocol,这两个Protocol与上述的接口初始化有关。详细信息在PI规范的DXE Architectural Protocols章节。

3.1 Variable Architectural Protocol
EFI_VARIABLE_ARCH_PROTOCOL
提供获取和设置环境变量所需的服务。该协议必须由DXE驱动程序生成,并且只能由DXE Foundation使用。
生成此协议的DXE驱动程序必须是运行时驱动程序。这个驱动程序负责初始化UEFI Runtime Services表的GetVariable(), GetNextVariableName(), SetVariable()和QueryVariableInfo()字段。在UEFI Runtime Services表的三个字段初始化后,驱动程序必须安装EFI_VARIABLE_ARCH_PROTOCOL_GUID的新句柄与NULL接口指针。该协议的安装会通知DXE Foundation,只读和易变环境变量相关的服务现在可用,DXE Founation必须更新UEFI Runtime Services表的32位CRC。环境变量服务的完整实现是在此协议和EFI_VARIABLE_ARCH_PROTOCOL都安装后。**需要对volatile环境变量进行只读访问或读/写访问的DXE驱动程序必须在其依赖表达式中具有此架构协议。**需要对非易失性(nonvolatile)环境变量进行写访问的DXE驱动程序必须在依赖项表达式中包含EFI_VARIABLE_WRITE_ARCH_PROTOCOL。

3.2 Variable Write Architectural Protocol
EFI_VARIABLE_WRITE_ARCH_PROTOCOL
提供设置非易失性环境变量所需的服务。该协议必须由运行时DXE驱动程序生成,并且只能由DXE Foundation使用。
生成此协议的DXE驱动程序必须是运行时驱动程序。这个驱动程序可能会更新UEFI Runtime Services表的SetVariable()字段。初始化UEFI Runtime Services表后,驱动程序必须将EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID安装到一个新的句柄上,该句柄的接口指针为NULL。环境变量的完整实现是在此协议和EFI_VARIABLE_ARCH_PROTOCOL都安装后。**需要对volatile环境变量进行只读访问或读写访问的DXE驱动程序必须在依赖表达式包含此架构协议:EFI_VARIABLE_WRITE_ARCH_PROTOCOL。**需要对非易失性(nonvolatile)环境变量进行访问的DXE驱动程序必须在其依赖项表达式中具有这种架构协议。

4 接口初始化
上述接口是在gRT中的,它们并非一开始就可以使用,必须要到UEFI的DXE阶段才可以使用。并且,也不是DXE阶段一开始就可以使用。在DXE的运行过程中,会加载一个个的模块,来填满整个表。
上述接口的初始化有不同的分类,分别在不同的模块中实现,并且只需要其中的一个模块运行就可以了。
(关于接口的初始化也有点模糊,为什么有不同的分类,而且还要在不同的模块中实现)。

MyVariable.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include //ShellCEntryLib call user interface ShellAppMain
EFI_STATUS
EFIAPI
MyHVariableAppEntry(IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable
)
{EFI_STATUS                         Status = EFI_SUCCESS;UINTN                              DataSize;UINT64                             CSDNEnable = 1;EFI_GUID  gEfiCsdnEnableGuid = { 0xb71604d2, 0xb8ba, 0x4d9c, { 0x78, 0x88, 0xac, 0xcf, 0x1d, 0xa2, 0x26, 0xc3 }};DataSize = sizeof (CSDNEnable);Status = gRT->SetVariable (L"CSDNEnable",&gEfiCsdnEnableGuid,EFI_VARIABLE_NON_VOLATILE |EFI_VARIABLE_BOOTSERVICE_ACCESS |EFI_VARIABLE_RUNTIME_ACCESS,DataSize,&CSDNEnable);ASSERT(Status);DEBUG ((EFI_D_ERROR," [CSDN]: Setvariable CSDNEnable 0x%x.\n", CSDNEnable));CSDNEnable = 0;DataSize = sizeof (CSDNEnable);Status = gRT->GetVariable (L"CSDNEnable",&gEfiCsdnEnableGuid,NULL,&DataSize,&CSDNEnable);ASSERT(Status);if (CSDNEnable) {DEBUG ((EFI_D_ERROR, "[CSDN] CSDNEnable\n"));}return EFI_SUCCESS;
}

MyVariable.inf

[Defines]INF_VERSION = 0x00010006BASE_NAME = MyVariableFILE_GUID = 69A6DE6D-FA9F-485E-9A3E-EA70FDCFC82AMODULE_TYPE = UEFI_APPLICATIONVERSION_STRING = 1.0ENTRY_POINT = MyHVariableAppEntry[Sources]MyVariable.c[Packages]MdePkg/MdePkg.decShellPkg/ShellPkg.decMdeModulePkg/MdeModulePkg.dec[LibraryClasses]UefiShellCEntryLibBaseLibBaseMemoryLibDebugLibPrintLibDevicePathLibUefiBootServicesTableLibMemoryAllocationLibUefiLibPcdLib

相关内容

热门资讯

Scala中Array常用的方...         在scala中,Array有大量的方法。定义一个数组arr后ÿ...
C++基础学习笔记(四)——核... 参考链接:https://www.bilibili.com/video/BV1et41...
超详细-安装vCenterv ... 目录 介绍: 第一阶段安装: 第二阶段安装: 最近在玩虚拟...
第14届蓝桥杯STEMA测评真... [导读]:超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成,...
ChatGPT助力校招----... 1 ChatGPT每日一题:简述SPI通信协议 问题:简述SPI通信协议...
新版PMP考试难不难? 1.新版考试题量和答题时间的变化? 总题量从200道减少到180道,所以...
HBase客户端、服务器端、列... HBase客户端、服务器端、列簇设计、HDFS相关优化,HBase写性能优化切入点&#...
linux 全局环境变量删除后... linux 全局环境变量删除后 还有 仍然存在1、编辑 /etc/profile2、设置REDISC...
网站流量飙升背后:外贸企业谷歌... 自从我涉足外贸行业,我逐渐认识到谷歌SEO优化在提升网站流量和吸引潜在客户方面的重要性...
一、trino406系列 之 ... 文章目录前言Trino不是什么?Trino是什么?概览服务类型Coord...
基于Java+SpringBo...  博主介绍:专注于Java技术领域和毕业项目实战 🍅文末获取源码联系&...
财经时评|破除“内卷式”竞争 ... 作者 中国汽车工程学会理事长张进华“十四五”以来,我国智能网联新能源汽车产业坚持以科技创新引领和推动...
二十六、对象的实例化内存布局与... 一、对象的实例化 1.判断对象对用的类是否加载、链接、初始化。 2.为对象分配内存。 3.处理并发...
C语言简单工厂模式和工程创建 一,设计模式概念引入① 什么是设计模式设计模式通常被面向对象的软件开发人员所采用&#x...
新势力车企5月销量:零跑汽车再... 红星资本局6月1日消息,今日,新势力车企陆续公布5月销量数据。零跑汽车(09863.HK)再创历史新...
150.网络安全渗透测试—[C... 我认为,无论是学习安全还是从事安全的人多多少少都会有些许的情怀和使命感!...
微服务注册中心做了什么事——服... 是否被一大堆的注册中心八股文淹没,不知道哪个是哪个,有啥区别甚至于不知道...
财经时评|反内卷不能只靠自觉 ... 作者 汽车工业协会原常务副会长兼秘书长、中国动力电池产业联盟理事长董扬去年四季度以来,政府工作报告及...
Lua打表 参考:https://www.likecs.com/show-308547984.ht...
Python-伪数据构造库fa... 目录 radar lipsum fake2db radar 可用来生成随机时间 import r...