请保留-> 【原文: https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】
如何使用VFR文件,是我这一段时间比较感兴趣的课题。包括VFR文件在内,UNI文件、IDF文件,都属于资源文件。UNI文件的使用,在之前Hii的例子中,已经讨论过了。而如何使用VFR文件,一直没有涉及到。
接下来的几篇博客,将以修改BIOS Setup(当然,还是以OvmfPkg编译的镜像来做BIOS文件)为例,演示如何使用VFR文件和相关的资源文件。
本篇的例子以Intel提供的示例驱动MyWizardDriver为基础,添加了字符串和窗体,修改步骤如下。
1 修改MyWizardDriverNVDataStruc.h
增加GUID的声明(MYWIZARDDRIVER_FORMSET_GUID):
#define MYWIZARDDRIVER_FORMSET_GUID { 0x5411db09, 0xe5f7, 0x4158, {0xa5, 0xc5, 0x2d, 0xbe, 0xa4,0x95, 0x34, 0xff} }
在示例的修改中,都以“robin add”的方式标记了修改部分,如果是多行修改,则添加了“begin”和“end”的注释。
2 修改MyWizardDriver.vfr
将VFR文件中其他的内容全部删除,并添加自定义的窗体定义,内容如下:
#include “MyWizardDriverNVDataStruc.h”
formset
guid = MYWIZARDDRIVER_FORMSET_GUID,
……
endform;
endformset;
VFR文件中的定义,在程序演示之后,再描述其语法及如何与显示的对应关系。
3 修改MyWizardDriver.uni
添加自定义的字符串,在之前的博客中描述过UNI文件和字符串定义,这里就不详细解释了。
#string STR_SAMPLE_FORM_SET_TITLE #language en “My Wizard DriverSample Formset”
#string STR_SAMPLE_FORM_SET_HELP #language en “Help for SampleFormset”
……
4 修改MyWizardDriver.h
添加头文件:
#include <Protocol/HiiConfigRouting.h>
#include <Protocol/FormBrowser2.h>
#include <Protocol/HiiString.h>
#include <Library/DevicePathLib.h>
并增加自定义的数据结构,代码添加后如下图:
5 修改MyWizardDriver.c
添加全局变量定义:
修改函数MyWizardDriverDriverEntryPoint()。修改的内容较多,注意查看源代码。最主要的代码,是通过SetVariable()把窗体添加到了BIOS Setup中。
代码准备完毕,需要将其编译,同时必须编译OVMF镜像。代码仍旧放在RobinPkg中,编译命令如下:
build -p RobinPkg\RobinPkg.dsc -m RobinPkg\Drivers\MyWizardDriver\MyWizardDriver.inf -a X64
以及编译OVMF镜像:
build -p OvmfPkg\OvmfPkgX64.dsc -a X64
奇怪的是,我编译出来的几个OVMF镜像都有点问题,测试的时候不正常,用以前编译的某个OVMF镜像可以正常测试。现在搞不清楚到底是什么原因导致的,在文末所提供的链接中,我把测试环境全部给出了,包括OVMF镜像和批处理。
把编译好的MyWizardDriver.efi拷贝到指定的文件夹hd-contents中,启动Qemu模拟环境:
qemu-system-x86_64.exe -bios OVMF.fd -hda fat:rw:hda-contents -net none
进入UEFI Shell,执行如下命令:
Shell> FS0:
FS0:\> load MyWizardDriver.efi
FS0:\> exit
进入到BIOS Setup中,依次选择Device Manager-My Wizard DriverSample Formset,可以看到如图4所示的界面,表示添加窗体成功:
可以使用空格或者回车键,修改选项。修改选项的时候,右下角会出现“Configuration changed”的黄色字符串。
More: VFR文件语法
窗体(Forms)是用户交互的组织形式,最终是以IFR(Internal Forms Representation)的二进制形式进入到EDK2的框架中的。IFR是由VFR文件生成的,类似于obj文件相对于源文件的关系。从平台框架的角度,窗体处于交互的中心位置:
站在程序员的角度,所有资源文件,最终都是用户UI的一部分,其结构图如下:
VFR文件采用的是BNF语法,与DSC文件采用“#”作为注释标志不同,它使用“//”作为注释标志。另外还有两个关键字是“#define”和“#include”,用来定义和包含头文件的,类似于C的语法。
formset是VFR文件中最重要的部分,用来组成窗体的最常用的结构。其示例如下:
formset
guid = {0xcc5ebb4f, 0xf562, 0x11e7, {0x92, 0x11, 0xf4, 0x8c, 0x50, 0x49, 0xe3, 0xa4}},
title = STRING_TOKEN(STR_SAMPLE_FORM_SET_TITLE),
help = STRING_TOKEN(STR_SAMPLE_FORM_SET_HELP),
classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID
form formid = 1, title = STRING_TOKEN(STR_SAMPLE_FORM1_TITLE);
…
endform;
endformset;
formset是关键字,用来标志整个窗体的开始,与标志窗体结束的endformset成对出现。其中各关键字的含义为:
guid: 标志本formset的GUID值;
title:在界面中标志本formset的字符串标题;
help:在界面上显示本formset的帮助信息;
classguid: 本formaset所挂载页面的GUID值。
本formset的选择项,在最初始页面的Device Manager下,如图7所示。
在formaset的集合中,可以用“form”和“endform”定义一个完整的页面,比如这篇博客中给出的示例(RobinPkg\Drivers\MyWizardDriver\MyWizardDriver.vfr):
form formid = 1, title = STRING_TOKEN(STR_SAMPLE_FORM1_TITLE); // “My Wizard Driver”
subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT); //”My Wizard DriverConfiguration”
subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2); //”Device XYZ Configuration”
checkbox varid =MWD_IfrNVData.MyWizardDriverChooseToEnable,
prompt =STRING_TOKEN(STR_CHECK_BOX_PROMPT), //”Enable My XYZ Device”
help = STRING_TOKEN(STR_CHECK_BOX_HELP), //”This is the help message …
flags = CHECKBOX_DEFAULT ,
key = 0,
default = 1,
endcheckbox;
endform;
在界面上是这样的:
VFR文件的内容比较多,特别是其使用方法,需要仔细研究UEFI spec中Hii部分,才能大致掌握。我在日常的开发中,基本不会用到VFR文件,这些相对比较新的知识,很能让我沉迷其中。
后续还会不定期研究VFR文件、UNI文件和IDF文件的用法,特别是我最关心的本地化显示部分。
另外,由于原来提供代码的百度云,所取的名字比较不雅观(女儿当时乱按的,我没注意……),我会逐渐将代码转移到gitee上去。
本篇的代码:
Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目代码位于:/RobinPkg/Drivers/ MyWizardDriver
其他工具和测试环境:/60 VFR file and other Res
6,433 total views, 1 views today
期待,最近也在 研究这些文件的用法