接口

UEFI中操作变量的接口主要是下面的几个:

获取变量的接口:

/**Returns the value of a variable.@param[in]       VariableName  A Null-terminated string that is the name of the vendor'svariable.@param[in]       VendorGuid    A unique identifier for the vendor.@param[out]      Attributes    If not NULL, a pointer to the memory location to return theattributes bitmask for the variable.@param[in, out]  DataSize      On input, the size in bytes of the return Data buffer.On output the size of data returned in Data.@param[out]      Data          The buffer to return the contents of the variable.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_GET_VARIABLE)(IN     CHAR16                      *VariableName,IN     EFI_GUID                    *VendorGuid,OUT    UINT32                      *Attributes,    OPTIONALIN OUT UINTN                       *DataSize,OUT    VOID                        *Data);

设置变量的接口:

/**Sets the value of a variable.@param[in]  VariableName       A Null-terminated string that is the name of the vendor's variable.Each VariableName is unique for each VendorGuid. VariableName mustcontain 1 or more characters. If VariableName is an empty string,then EFI_INVALID_PARAMETER is returned.@param[in]  VendorGuid         A unique identifier for the vendor.@param[in]  Attributes         Attributes bitmask to set for the variable.@param[in]  DataSize           The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is set, then a SetVariable() call with a DataSize of zero will not cause any change to the variable value (the timestamp associated with the variable may be updated however even if no new data value is provided,see the description of the EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). @param[in]  Data               The contents for the variable.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SET_VARIABLE)(IN  CHAR16                       *VariableName,IN  EFI_GUID                     *VendorGuid,IN  UINT32                       Attributes,IN  UINTN                        DataSize,IN  VOID                         *Data);

获取下一个变量的接口:

/**Enumerates the current variable names.@param[in, out]  VariableNameSize The size of the VariableName buffer.@param[in, out]  VariableName     On input, supplies the last VariableName that was returnedby GetNextVariableName(). On output, returns the Nullterminatedstring of the current variable.@param[in, out]  VendorGuid       On input, supplies the last VendorGuid that was returned byGetNextVariableName(). On output, returns theVendorGuid of the current variable.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)(IN OUT UINTN                    *VariableNameSize,IN OUT CHAR16                   *VariableName,IN OUT EFI_GUID                 *VendorGuid);

获取系统中的变量信息:

/**Returns information about the EFI variables.@param[in]   Attributes                   Attributes bitmask to specify the type of variables onwhich to return information.@param[out]  MaximumVariableStorageSize   On output the maximum size of the storage spaceavailable for the EFI variables associated with theattributes specified.@param[out]  RemainingVariableStorageSize Returns the remaining size of the storage spaceavailable for the EFI variables associated with theattributes specified.@param[out]  MaximumVariableSize          Returns the maximum size of the individual EFIvariables associated with the attributes specified.@retval EFI_SUCCESS                  Valid answer returned.@retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied@retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and theMaximumVariableStorageSize,RemainingVariableStorageSize, MaximumVariableSizeare undefined.**/
typedef
EFI_STATUS
(EFIAPI *EFI_QUERY_VARIABLE_INFO)(IN  UINT32            Attributes,OUT UINT64            *MaximumVariableStorageSize,OUT UINT64            *RemainingVariableStorageSize,OUT UINT64            *MaximumVariableSize);

参数说明已在注释中,这里需要关心的是Attributes这个参数,它具体有以下的取值:

///
/// Attributes of variable.
///
#define EFI_VARIABLE_NON_VOLATILE                            0x00000001
#define EFI_VARIABLE_BOOTSERVICE_ACCESS                      0x00000002
#define EFI_VARIABLE_RUNTIME_ACCESS                          0x00000004
///
/// This attribute is identified by the mnemonic 'HR'
/// elsewhere in this specification.
///
#define EFI_VARIABLE_HARDWARE_ERROR_RECORD                   0x00000008
///
/// Attributes of Authenticated Variable
///
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS              0x00000010
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS   0x00000020
#define EFI_VARIABLE_APPEND_WRITE                            0x00000040

其中常用的就是前面的三种:

EFI_VARIABLE_NON_VOLATILE:表示设置变量时将变量写入到非易失介质中,比如SpiFlash;

EFI_VARIABLE_BOOTSERVICE_ACCESS:表示设置的变量在UEFI阶段都可以访问,更具体的说是在调用gBS->ExitBootServices()之前都可以访问;

EFI_VARIABLE_RUNTIME_ACCESS:表示设置的变量在OS下都可以访问,当然前提是OS是UEFI兼容的。

接口初始化

变量的接口是在gRT中的,它们并非一开始就可以使用,必须要到UEFI的DXE阶段才可以使用。

并且,也不是DXE阶段一开始就可以使用,从DxeMain.c中可以看到,最初的时候gRT表实际上是空的。

在DXE的运行过程中,会加载一个个的模块,来填满整个表。

对于变量,大致就是像下面这样的代码:

  SystemTable->RuntimeServices->GetVariable         = RuntimeServiceGetVariable;SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;SystemTable->RuntimeServices->SetVariable         = RuntimeServiceSetVariable;SystemTable->RuntimeServices->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;//// Now install the Variable Runtime Architectural Protocol on a new handle//NewHandle = NULL;Status = gBS->InstallMultipleProtocolInterfaces (&NewHandle,&gEfiVariableArchProtocolGuid,NULL,&gEfiVariableWriteArchProtocolGuid,NULL,NULL);

变量的初始化有不同的分类,分别在不同的模块中实现,并且只需要其中的一个模块运行就可以了。

下面是一个大致的模块分类(名称类似,但又可能不同):

1. EmuVariableRuntimeDxe.inf

这种形式的变量初始化模块的特点是,所有变量都存放在内存中,相当于前面提到的属性EFI_VARIABLE_NON_VOLATILE并没有什么作用。

2. VariableRuntimeDxe.inf

这里就是最一般的形式。

3. VariableSmmRuntimeDxe.inf

这种形式是一般形式的安全加强版,变量存放在非易失介质时需要通过SMM模式来完成,因此变量的有效性和可靠性会更高。

EmuVariableRuntimeDxe

下面以EmuVariableRuntimeDxe.inf模块为例,说明变量的初始化。

简单来说,初始化分为三个部分:

1.    初始化mVariableModuleGlobal

2.    为全局变量gRT赋值;

3.    安装相关的Protocol和事件(该事件用于物理地址到虚拟地址的转变)。

mVariableModuleGlobal的类型是ESAL_VARIABLE_GLOBAL,结构如下:

typedef struct {VARIABLE_GLOBAL VariableGlobal[2];UINTN           VolatileLastVariableOffset;UINTN           NonVolatileLastVariableOffset;UINTN           CommonVariableTotalSize;UINTN           HwErrVariableTotalSize;CHAR8           *PlatformLangCodes;CHAR8           *LangCodes;CHAR8           *PlatformLang;CHAR8           Lang[ISO_639_2_ENTRY_SIZE + 1];
} ESAL_VARIABLE_GLOBAL;

VariableGlobal是一个数组,它有两个元素,表示的分别是物理内存和虚拟内存,因为需要有对OS的支持,所以才会有虚拟内存这一块。

VARIABLE_GLOBAL的结构体如下:

typedef struct {EFI_PHYSICAL_ADDRESS  VolatileVariableBase;EFI_PHYSICAL_ADDRESS  NonVolatileVariableBase;EFI_LOCK              VariableServicesLock;
} VARIABLE_GLOBAL;

EFI_PHYSICAL_ADDRESS就是UINT64。

VariableServicesLock是一个用于变量的锁,它的类型EFI_LOCK的结构体如下:

typedef struct {EFI_TPL         Tpl;EFI_TPL         OwnerTpl;EFI_LOCK_STATE  Lock;
} EFI_LOCK;

EFI_TPL是UINTN,EFI_LOCK_STATE有以下的几种状态:

typedef enum {EfiLockUninitialized = 0,EfiLockReleased      = 1,EfiLockAcquired      = 2
} EFI_LOCK_STATE;

不过关于锁的东西并不是这里需要关注的重点。

mVariableModuleGlobal的初始化位于VariableCommonInitialize(),具体的流程如下:

其中需要注意两个结构体:

///
/// Variable Store region header.
///
typedef struct {////// Variable store region signature.///EFI_GUID  Signature;////// Size of entire variable store,/// including size of variable store header but not including the size of FvHeader.///UINT32  Size;////// Variable region format state.///UINT8   Format;////// Variable region healthy state.///UINT8   State;UINT16  Reserved;UINT32  Reserved1;
} VARIABLE_STORE_HEADER;

这个是整个变量存储空间的头部。

然后每个变量都有一个自己的头部:

///
/// Single Variable Data Header Structure.
///
typedef struct {////// Variable Data Start Flag.///UINT16      StartId;////// Variable State defined above.///UINT8       State;UINT8       Reserved;////// Attributes of variable defined in UEFI specification.///UINT32      Attributes;////// Size of variable null-terminated Unicode string name.///UINT32      NameSize;////// Size of the variable data without this header.///UINT32      DataSize;////// A unique identifier for the vendor that produces and consumes this varaible.///EFI_GUID    VendorGuid;
} VARIABLE_HEADER;

初始化的内容就是这些,完成初始化后就可以使用变量的存取了。

之后介绍变量读写的实现。

GetVariable

GetVariable()的流程大致如下:

有几点需要注意:

1. 从RuntimeServiceGetVariable()到EmuGetVariable()多了一个参数:

EFI_STATUS
EFIAPI
RuntimeServiceGetVariable (IN CHAR16        *VariableName,IN EFI_GUID      *VendorGuid,OUT UINT32       *Attributes OPTIONAL,IN OUT UINTN     *DataSize,OUT VOID         *Data)
{return EmuGetVariable (VariableName,VendorGuid,Attributes OPTIONAL,DataSize,Data,&mVariableModuleGlobal->VariableGlobal[Physical]);
}

mVariableModuleGlobal->VariableGlobal[Physical],表示的是在UEFI下的物理地址。

2. FindVariable (VariableName, VendorGuid,&Variable, Global);函数中最重要的是第三个参数Variable,它也是函数的输出,它的结构如下:

typedef struct {VARIABLE_HEADER *CurrPtr;VARIABLE_HEADER *EndPtr;VARIABLE_HEADER *StartPtr;BOOLEAN         Volatile;
} VARIABLE_POINTER_TRACK;

这个输出的结构反映了当前的变量保存区域。

当找到变量后(没找到关系也不大,下图以找到为例),上述的值如图中所示:

上述的立方体区域实际上有两个,一个存放易失变量一个存放非易失变量,Volatile根据在那块区域找到的来确定。

3. FindVariable()函数出入的VariableName参数如果是空的,而VendorGuid非空,则直接返回下一个非易失变量。

4. UpdateVariableInfo()部分是用来统计UEFI下的变量总体信息的,并不是变量实现的一部分,这里先不关注。

SetVariable

具体的流程如下:

【UEFI基础】UEFI变量基础相关推荐

  1. 【UEFI基础】UEFI变量基础2

    说明 之前已经写过一篇变量相关的文章[UEFI基础]UEFI变量基础,该文章使用的是模拟的变量,而本文更接近于实际的变量模块. 环境设置 为了测试BIOS的变量功能,需要修改QEMU的启动选项,如下所 ...

  2. Linux7-常用文件管理命令及系统变量基础

    文件管理工具 cp命令 用于实现文件复制功能 明确源文件和目标文件 用法 单源复制 cp [OPTION]- [-T] SOURCE DEST 多源复制 cp [OPTION]- SOURCE- DI ...

  3. Shell基础-环境变量配置文件

    Shell基础-环境变量配置文件 Shell基础-环境变量配置文件 source 配置文件 或者 . 配置文件: 把环境变量写入配置文件后,需要用户重新登陆才能生效,而是用source命令,则能直接生 ...

  4. Python基础之变量学习

    Python基础之变量学习 一.变量定义与理解 1.变量意义 2.变量类型 3.变量命名规范 二.变量使用 三.常量的使用 1.常量的理解 2.常量的规范 四.数据的类型 1.数字 2.文字 3.布尔 ...

  5. [GO语言基础] 三.变量声明、数据类型、标识符及编程练习12题

    作为网络安全初学者,会遇到采用Go语言开发的恶意样本.因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识:另一方面是分享与读者,希望大家一起进步.前文介绍了Go的编译运行 ...

  6. js php 数据类型判断,【js基础】变量类型判断

    类型判断方法比较: 如果需要想详细了解,请看下文: 注:原封不动复制备份,防止删帖 在JavaScript中,有5种基本数据类型和1种复杂数据类型,基本数据类型有:Undefined, Null, B ...

  7. 1.2编程基础之变量定义、赋值及转换 10 Hello, World 的大小

    http://noi.openjudge.cn/ch0102/10/ #include <bits/stdc++.h> using namespace std; int main( voi ...

  8. 变量的三重属性_TypeScript基础入门 - 变量声明(三)

    转载地址TypeScript基础入门 - 变量声明(三)​www.gowhich.com 项目实践仓库 https://github.com/durban89/typescript_demo.gitt ...

  9. Python基础-高级变量类型

    Python基础-高级变量类型 1.高级变量类型 """ 数值型:int float bool compex 非数值型:str list set dict tuple & ...

最新文章

  1. 汇编语言的准备知识--给初次接触汇编者 之三
  2. Sqlserver别太信任SysComments表中的text字段
  3. (STL,set)安迪的第一个字典
  4. eclipse的编辑器样式风格设置
  5. Hibernate原生SQL查询
  6. ld: symbol(s) not found for architecture arm64
  7. igbt原理动画演示视频_IGBT的结构与工作原理 测量方法详细讲解
  8. Pywin32操控Excel——2. 筛选与排序
  9. LeetCode之K sum problem
  10. 解决关键词这个问题,ASO优化效果事半功倍
  11. l那是计算机房吗,机房设计常用计算公式
  12. 利用蒙特卡洛(Monte Carlo)方法计算π值
  13. java操作题35套
  14. 【zz北邮人】[经历][完稿]cs硕士妹子找工作经历【阿里人搜等互联网】
  15. 谷歌浏览器代理服务器有问题
  16. 中国人为什么喜欢蹲着?
  17. Ubuntu 删除文件和文件夹
  18. 刨析django----celery
  19. 爬虫实战:如何爬取高德地图?
  20. 来来来,一起了解下MTK(联发科)

热门文章

  1. 《大清相国》的读后感
  2. Python爬虫之Requests的基础运用
  3. 《麦肯锡工作法——麦肯锡精英的39个工作习惯》——职场工作守则
  4. 谷歌浏览器插件最新版 v0.3.0 抓取1688、京东、拼多多 商品图片|文描|视频|规格|属性等信息 并打包下载
  5. 谈谈“.花季(滑稽)护航”
  6. 15条搜狗快速排名策略,让您站在搜索引擎的前列!
  7. Java信息管理系统界面设计(包括登录界面及界面切换)
  8. 成长秘籍|程序员节快乐,高德技术大佬荐书(含福利)
  9. ocr tesseract
  10. 南阳理工计算机与科学技术,南阳理工学院计算机科学与技术咋样