20

UEFI开发探索61-VFR文件和其他资源文件2(NVRAM上存储数据)

 3 years ago
source link: http://yiiyee.cn/blog/2020/07/04/uefi%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a261-vfr%e6%96%87%e4%bb%b6%e5%92%8c%e5%85%b6%e4%bb%96%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b62%ef%bc%88nvram%e4%b8%8a%e5%ad%98%e5%82%a8%e6%95%b0%e6%8d%ae%ef%bc%89/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

UEFI开发探索61-VFR文件和其他资源文件2(NVRAM上存储数据)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

NVRAM全称为Non-Volatile Ram(非易失性内存) ,Legacy BIOS下这块是使用CMOS来实现的,UEFI下则可以直接在ROM中分出一部分来实现。(问题来了,在UEFI下CMOS到底怎么用的呢? 有机会再研究一下)

UEFI下,对NVRAM的使用如图1所示。

图 1 配置参数存储于NVRAM

在上一篇博客代码的基础上,进行部分修改,将用户的选择存储于NVRAM,修改步骤如下。

1 更新MyWizardDriver.c

获取HII相关的几个Protocol指针:

  EFI_HII_STRING_PROTOCOL         *HiiString;
  EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
  EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;

添加相应的代码(Line228~Line261):

  // Locate Hii Database protocol
  //
  Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  PrivateData->HiiDatabase = HiiDatabase;

PrivateData->HiiConfigRouting = HiiConfigRouting;

后续的代码中,获取Hii Database protocol的代码注释掉。(Line289~Line298以及Line310)

2 更新HiiConfigAccess.c

添加外部变量的声明(Line14 and Line15):

extern EFI_GUID   mMyWizardDriverFormSetGuid;
extern CHAR16     mIfrVariableName[];

然后对三个函数进行改造,之前这三个函数都没有实现具体功能:

MyWizardDriverHiiConfigAccessExtractConfig()、MyWizardDriverHiiConfigAccessRouteConfig()和MyWizardDriverHiiConfigAccessCallback()。

具体的代码就不贴出来了,到文末给的地址将代码下载下来查看即可。

3 几个重要Porotocol

(1)gEfiHiiDatabaseProtocolGuid。 EFI_HII_DATABASE_PROTOCOL的GUID,定义于EdkCompatibilityPkg\Foundation\Efi\Protocol\HiiDatabase\HiiDatabase中 。访问HII仓库的Protocol,UEFI Spec 2.8 34.8节详细描述其用法。

(2) gEfiHiiStringProtocolGuid。EFI_HII_STRING_PROTOCOL的GUID,定义于EdkCompatibilityPkg\Foundation\Efi\Protocol\HiiString\HiiString.c中。访问字符串资源的Protocol,UEFI Spec 2.8 的34.3节描述其用法,在之前的博客中使用过它。

(3)  gEfiFormBrowser2ProtocolGuid。EFI_FORM_BROWSER2_PROTOCOL的GUID,定义于EdkCompatibilityPkg\Foundation\Efi\Protocol\FormBrowser2\FormBrowser2.c中,是Setup界面的基础引擎。UEFI Spec 2.8 的35.6节描述其用法。

(4) gEfiHiiConfigRoutingProtocolGuid。EFI_HII_CONFIG_ROUTING_PROTOCOL的GUID,定义于EdkCompatibilityPkg\Foundation\Efi\Protocol\HiiConfigRouting\HiiConfigRouting.c中,这是一个全局处理Setup界面交互的protocol。UEFI Spec 2.8 的35.4节描述其用法。

Variable是UEFI环境中的Key/Value对(想起了离散数学的二元组),用于在平台上存储数据,允许EFI执行环境中和EFI OS Loader中使用,在操作系统下也可以通过API访问。在大多数情况下,Variable是持续存在的(不因掉电而消失)。在本篇中,用到了Rutime Services中处理Variable的相关Protocol,正好趁机会整理下。

(5)  typedef  EFI_STATUS GetVariable (
IN CHAR16 *VariableName,  //Variable的字符串名
IN EFI_GUID *VendorGuid,   //Variable的唯一GUID
OUT UINT32 *Attributes OPTIONAL, //属性,如果定义非空,则返回其相关性质,
               //见MdePkg\Include\Uefi\UefiMultiPhase.h中相关宏定义
IN OUT UINTN *DataSize, //指明输入或者输出的数据缓冲区长度
OUT VOID *Data OPTIONAL //数据缓冲区
);

每个厂商都会创建并维护自己的Variable,为了与其他Variable不冲突,使用VendorGuid来唯一标志这些Variable。各种属性中,EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS比较特殊,其返回的数据接口有标准定义,可以在UEFI标准中查看。

(6)  typedef EFI_STATUS GetNextVariableName (
IN OUT UINTN *VariableNameSize, //VariableName的字节长度,必须保证足够容纳字

  // 符串(包含NULL字符)
IN OUT CHAR16 *VariableName, //作为输入时,需提供由此函数返回最后一个Variable

  // 字符串名;作为输出时,返回Variable字符串
IN OUT EFI_GUID *VendorGuid //作为输入时,需提供由此函数返回的最后一个

  // VendorGuid; 作为输出时,返回当前Variable的GUID
);

为了熟悉这个函数的用法,我参照ShellProtocol中的函数,自己写了个ListVariable的工程例子。具体见篇末的链接。

这是个粗糙的例子,屏幕显示都没有考虑,Variable太多,只能显示最后一屏:

图2 显示Variable

实际上,Shell命令dmpstore可以列出所有的Variable,以及其中的内容,在后面的实验中我们会用到。

(7)  typedef EFI_STATUS SetVariable (
IN CHAR16 *VariableName,  // VariableName的字节长度,必须保证足够容纳字符串(包//含NULL字符)
IN EFI_GUID *VendorGuid,  //Variable的唯一GUID
IN UINT32 Attributes,     //属性,见函数GetVariable中的说明
IN UINTN DataSize,  //一般用作数据缓冲区的长度,不过,当Attributes为下列值时,作用

  //不同 (具体查看UEFI规格书):
//EFI_VARIABLE_APPEND_WRITE,
//EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
//EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS,
//EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
IN VOID *Data      // Variable的内容
);

这是个非常复杂的函数,UEFI规范中用了足足7页来介绍(UEFI Spec 2.8 p235-p241),这里没法展开讨论,还是通过实例的学习,稍微体会其用法吧。

4 编译及测试

为演示Variable的用法,我在HiiConfigAccess.c的Line271开始,添加了几行代码:

//robin add 2020-07-01 22:46:51
  PrivateData->Configuration.MyWizardDriverStringData[0]=0x31;
  PrivateData->Configuration.MyWizardDriverStringData[1]=0x32;
  PrivateData->Configuration.MyWizardDriverStringData[2]=0x33;
  PrivateData->Configuration.MyWizardDriverStringData[3]=0x34;
  PrivateData->Configuration.MyWizardDriverStringData[4]=0x35;

将工程拷贝到RobinPkg的Driver文件夹下,编译:

C:\MyWorkspace>build -a X64 -p RobinPkg\RobinPkg.dsc
-m RobinPkg\Drivers\MyWizardDrv01\MyWizardDriver.inf

使用上一篇中的调试环境,配合dmpstore工具,测试结果如下:

图3 测试过程

加载完驱动后,进入BIOS Setup,修改自定义的选项,然后退出。再次进入UEFI Shell后,可以查看Variable,可以看出所修改的部分已经改变了。

Gitee地址:https://gitee.com/luobing4365/uefi-exolorer
项目代码位于:/RobinPkg/Drivers/ MyWizardDrv01
              /RobinPkg/Applications/ListVariable

734 total views, 2 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK