UEFI实战--------HII之uni文件
创始人
2024-06-01 12:15:30
0

uni文件
HII的实现涉及到多种不同类型的文件,uni文件是其中最简单的一种,它用来存放各种语言的字符串以实现本地化。本节主要参考自《edk-ii-uni-specification.pdf》,后面简称为参考文档。

关于uni文件的作用,在参考文档中做了如下的说明:

RFC4646标准中定义了语言标签(Tags for Identifying Languages),在这个标准下,每一个语言标签由一个由2个小写字母组成的语言标签和一个由2个大写字母组成的国家/区域的国际域名缩写构成,比如en-US表示美式英语,zh-CN表示简体中文,在uni文件中,就用这个来表示本地化语言。UCS-2表示用2个字节表示的通用字符集,UCS-2中的2表示的是2个字节,所以uni文件最终转换成二进制的时候,每个字符都是由2个字节组成的。

总的来说,uni文件提供了一系列的**标记(Token)**用来指代字符串,这些字符串可以有不同的语言实现,但是在代码调用中都可以使用这些统一的标记来引用。以前面出现过的Front Page为例:

这里的Select Language就对应一个在uni文件中定义的标记(具体在MdeModulePkg\Application\UiApp\FrontPageStrings.uni文件中):

#string STR_LANGUAGE_SELECT #language en-US “Select Language”
#language fr-FR “Choisir la Langue”

可以看到,这里实际上支持两种语言,一种是英语一种是法语,所以Front Page中可以进行切换:

而在我们的代码中,实际上使用的都只是STR_LANGUAGE_SELECT这个标记:

HiiCreateOneOfOpCode (
StartOpCodeHandle,
FRONT_PAGE_KEY_LANGUAGE,
0,
0,
STRING_TOKEN (STR_LANGUAGE_SELECT), // 这个就是uni文件中定义的Token
STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
EFI_IFR_FLAG_CALLBACK,
EFI_IFR_NUMERIC_SIZE_1,
OptionsOpCodeHandle,
NULL
);

至于具体如何切换,这里暂不深入。

BNF语法表示
uni文件使用一种特定的语法来描述,并且使用了BNF的方式来描述这种语法,所以这里先简单介绍BNF。

BNF全称是巴科斯-诺尔形式(Backus-Naur form),前两个词表示的是人名。BNF是一种形式化的语法表示方式,用来描述语法的一种形式体系,是一种典型的元语言,目前基本所有的编程语言都会用它来表示该语言的语法规则。这里使用uni文件以及之后介绍的vfr文件,也都有对应BNF来描述,不过使用的是扩展的版本,称为EBNF。

要详细介绍EBNF使用规则过于复杂,这里根据实际的示例说明。比如下面的示例来自参考文档,它定义了最基本的一些语法概念:

::= " "
::= {(\u0041-\u005A)} ; Characters A - Z
{(\u0061-\u007A)} ; Characters a - z
::= (\u0030-\u0039) ; Characters 0 - 9
::= +
::= {} {}
::= “//” *
::=
::= (\u0001-\uF6FF)
::= {(\u0020-\uF6FF)} {}
::= “\x” [{} {}]{4} “”
::= (\u0021-\uF6FF)
::=
[ [ ]+]+
::= “language” ::= {}
{(\u0041-\u0046)} ; Characters A - F
{(\u0061-\u0066)} ; Characters a - f
::= * “#”
::= “string”
::= [{} {} {}]*
::=
::= {2,8} [ ]
::= “-” [{} {}]{1,8}
::= “-” [{} {}]{1,}
::= \u0022 ; Double Quote Character, "
::=

::= {} {}
::= “” {“narrow”} {“wide”} {}
{“n”} {“r”} {“t”} {“nbr”} {“”} {“'”}

BNF使用<>来定义一个符号,::=表示的意思是“被定义为”,""里面表示的是真正的字符,所以第一句:

::= " "
1
表示的就是定义了一个符号US,它表示的意思是“单个空格”。

::= {(\u0041-\u005A)} ; Characters A - Z
{(\u0061-\u007A)} ; Characters a - z

;之后的内容是注释,所以上面的话可以写成一句:

::= {(\u0041-\u005A)}{(\u0061-\u007A)}
1
{}表示重复,[]表示可选,()表示分组。不过这样似乎也不能解释上面的代码,可以明确的是表示的是a-z或A-Z中的一个字母。同理表示一个数字。

*表示0个或以上;+表示1个或以上;所以下述语句:

::= +
::= {} {}

表示多个空格。{}表示一行的结尾,所以表示若干个空格组成的一行。

以此类推,之后的内容就不多做介绍了,最终对于所有编程语言的语句都可以通过上述的方式来描述。

语言基础
关于uni文件中的语法可以用一句BNF表示:

::= *

+

以一个实际的例子做对比:

这里可以很明确的看到各个部分。

不过上述例子中还有一部分没有包含进去,就是/=#,它应该属于的一部分,称为ControlRefactor:

::= “/”
::= “=”
::= (0x0021 - 0xF6FF)

其中#的值是0x0023,所以是一个NewCtrlChar。不过目前不清楚这句代码的作用,似乎跟之后和中每行开头的#有关,但是也不是所有的uni文件中都包含它,没有它也能够正常使用字符串。

另外也不是所有的uni文件都包含,关于这些,在参考文档中并没有特别说明原因。

和两部分都比较简单,这里主要说明下,它的定义如下:

::= {} {}
{} {}
{} {}
{}

这里简单说明:

也可以包含,事实上注释可以出现在任何的位置,关于注释的表达式,就是以//开头的行;
空白行也随时可以出现;
是以#string开头的一个字符串(中间可以换行),它算是中最重要的部分,包含了真正用来定义并在其它文件中使用的标记;
在前面已有说明,含义不明;
也可以出现在中;
同样含义不明;
是用来包含其它uni文件的,像下面那样:
#include “MiscBaseBoardManufacturer.uni”
1
上述的定义中,最重要的就是了,它的定义如下:

::= “#string”
[]
[]+
::= “#language” lang-code
::= [] []+
::= [“#font” font-identifier> ]
::=

下面是一个具体的例子:

对于没有找到具体的例子。这里说明下它的定义:

“#fontdef” font-identifier
::= font-name font-size [ font-style-list]
font-style-list ::= [fs-entries]
fs-entries ::= font-style [“|” font-style]*
font-style ::= {“bold”} {“italic”} {“underline”} {“dblunder”}
{“shadow”} {“emboss”} {“normal”}
font-size ::= (1-9) (0-9)*

font是一个需要额外讨论的问题,这里暂时不介绍。

解析和使用
uni文件的解析和使用有两种方式,一种是将字符串解析成数组,然后通过代码手动来安装;另一种是将字符串解析为二进制放到BIOS中,然后会生成自动代码来安装,后续要使用的时候就直接通过打开指定GUID(gEfiHiiPackageListProtocolGuid)的Protocol来获取。

对应的代码示例是MdeModulePkg\Application\UiApp\UiApp.inf。首先通过inf文件查看其中使用的uni文件,有如下的几处:

[Defines]
MODULE_UNI_FILE = UiApp.uni

[Sources]
FrontPageStrings.uni

[UserExtensions.TianoCore.“ExtraFiles”]
UiAppExtra.uni

这个示例中使用到了3处uni文件,这里分别说明:

MODULE_UNI_FILE对应的是模块本身的摘要和描述,一般情况下UEFI中的模块默认有一个英文版本的摘要和描述,如果要增加其它语言版本,就可以通过这个MODULE_UNI_FILE指定uni文件来实现,当然它本身也还可以是英文的。本例中它的内容如下:
#string STR_MODULE_ABSTRACT
#language en-US
“UiApp module is driver for BDS phase.”

#string STR_MODULE_DESCRIPTION
#language en-US
“UiApp module is driver for BDS phase.”

它不会被包含到BIOS二进制里面,不用特别关注。

[Sources]中的是实际BIOS使用的字符串,后面会详细介绍。
[UserExtensions.TianoCore.“ExtraFiles”]中的文件也不会被BIOS二进制包含,对应文件UiAppExtra.uni中的内容:
#string STR_PROPERTIES_MODULE_NAME #language en-US “UiApp module”
1
它用于UEFI发布,也可以不用特别关注。

所以实际上真正有用的仅仅是在[Sources]中的uni文件。

在build工具中会通过uni文件生成hpk二进制文件,对应的文件名可以在BaseTools\Source\Python\AutoGen\ModuleAutoGen.py中找到:

gAutoGenStringFormFileName = “%(module_name)sStrDefs.hpk”
1
所以本例中生成的就是UiAppStrDefs.hpk(注意替换的是%(module_name)s):

hpk文件是一种压缩文件,可以通过工具查看,这里有一个在线的版本:https://filext.com/file-extension/HPK,得到的内容:

对应的FrontPageStrings.uni文件的内容:

/=#

#langdef en-US “English”
#langdef fr-FR “Français”
#langdef en “Standard English”
#langdef fr “Standard Français”

#string STR_FRONT_PAGE_TITLE #language en-US “Front Page”
#language fr-FR “Front Page”
#string STR_FRONT_PAGE_COMPUTER_MODEL #language en-US “”
#language fr-FR “”
#string STR_FRONT_PAGE_CPU_MODEL #language en-US “”
#language fr-FR “”
#string STR_FRONT_PAGE_CPU_SPEED #language en-US “”
#language fr-FR “”
#string STR_FRONT_PAGE_MEMORY_SIZE #language en-US “”
#language fr-FR “”
#string STR_FRONT_PAGE_BIOS_VERSION #language en-US “”
#language fr-FR “”
#string STR_FRONT_PAGE_BANNER_0_LEFT #language en-US “Wonder Computer Model 1000Z Manufactured by Intel®”
#language fr-FR “Demander le Modèle d’Ordinateur 1000Z A Fabriqué par Intel®”
#string STR_FRONT_PAGE_BANNER_0_RIGHT #language en-US “OK”
#language fr-FR “Bon”
#string STR_FRONT_PAGE_BANNER_1_LEFT #language en-US “2 Pentium® X Xeon processors running at 800Thz”
#language fr-FR “2 processeurs Pentium® X Xeon tournants à 800Thz”
#string STR_FRONT_PAGE_BANNER_1_RIGHT #language en-US “24 TB System RAM”
#language fr-FR “24 TB RAM de Système”
#string STR_FRONT_PAGE_BANNER_2_LEFT #language en-US “ACME® EFI BIOS Version 13.5 Release 1039.92”
#language fr-FR “ACME® EFI BIOS Version 13.5 Release 1039.92”
#string STR_FRONT_PAGE_BANNER_3_LEFT #language en-US “Serial Number: 1Z123456789MARMAR (Need SMBIOS entries)”
#language fr-FR “Numéro de série: 1Z123456789MARMAR (Les entrées de SMBIOS de besoin)”
#string STR_CONTINUE_PROMPT #language en-US “Continue”
#language fr-FR “Continuer”
#string STR_CONTINUE_HELP #language en-US “This selection will direct the system to continue to booting process”
#language fr-FR “Cette sélection dirigera le système pour continuer au processus d’amorçage”
#string STR_LANGUAGE_SELECT #language en-US “Select Language”
#language fr-FR “Choisir la Langue”
#string STR_LANGUAGE_SELECT_HELP #language en-US “This is the option one adjusts to change the language for the current system”
#language fr-FR “Ceci est l’option qu’on ajuste pour changer la langue pour le système actuel”
#string STR_MISSING_STRING #language en-US “Missing String”
#language fr-FR “Missing String”
#string STR_EMPTY_STRING #language en-US “”
#language fr-FR “”
#string STR_RESET_STRING #language en-US “Reset”
#language fr-FR “Reset”
#string STR_RESET_STRING_HELP #language en-US “Reset the current setting.”
#language fr-FR “Reset the current setting.”
#string STR_CUSTOMIZE_BANNER_LINE4_LEFT #language en-US “”
#language fr-FR “”
#string STR_CUSTOMIZE_BANNER_LINE4_RIGHT #language en-US “”
#language fr-FR “”
#string STR_CUSTOMIZE_BANNER_LINE5_LEFT #language en-US “”
#language fr-FR “”
#string STR_CUSTOMIZE_BANNER_LINE5_RIGHT #language en-US “”
#language fr-FR “”
#string STR_TEST_KEY_USED #language en-US “WARNING: Test key detected.”
#language fr-FR “WARNING: Test key detected.”
#string STR_NULL_STRING #language en-US " "
#language fr-FR " "

可以看到hpk文件中并没有包含上述所有的字符串,那是因为对于没有在代码中用到的标记,就不会包含到hpk文件中的。

除了二进制文件,在AutoGen.c中同样可以看到字符串转换成的数组:

//
//Unicode String Pack Definition
//
unsigned char UiAppStrings[] = {

// STRGATHER_OUTPUT_HEADER
0x26, 0x04, 0x00, 0x00,

// PACKAGE HEADER

0xB4, 0x01, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x65, 0x6E,
0x2D, 0x55, 0x53, 0x00,

// PACKAGE DATA

// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
0x14, 0x45, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68, 0x00, 0x00,
0x00,
// 0x0002: STR_FRONT_PAGE_TITLE:0x0002
0x14, 0x46, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61,
0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
// 0x0003: STR_FRONT_PAGE_COMPUTER_MODEL:0x0003
0x14, 0x00, 0x00,
// 0x0004: STR_FRONT_PAGE_CPU_MODEL:0x0004
0x14, 0x00, 0x00,
// 0x0005: STR_FRONT_PAGE_CPU_SPEED:0x0005
0x14, 0x00, 0x00,
// 0x0006: STR_FRONT_PAGE_MEMORY_SIZE:0x0006
0x14, 0x00, 0x00,
// 0x0007: STR_FRONT_PAGE_BIOS_VERSION:0x0007
0x14, 0x00, 0x00,
// 0x0008: STR_CONTINUE_PROMPT:0x0008
0x14, 0x43, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x75, 0x00, 0x65,
0x00, 0x00, 0x00,
// 0x0009: STR_LANGUAGE_SELECT:0x0009
0x14, 0x53, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00, 0x4C,
0x00, 0x61, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x75, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00,
0x00,
// 0x000A: STR_LANGUAGE_SELECT_HELP:0x000A
0x14, 0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x74, 0x00, 0x69,
0x00, 0x6F, 0x00, 0x6E, 0x00, 0x20, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x20, 0x00, 0x61,
0x00, 0x64, 0x00, 0x6A, 0x00, 0x75, 0x00, 0x73, 0x00, 0x74, 0x00, 0x73, 0x00, 0x20, 0x00, 0x74,
0x00, 0x6F, 0x00, 0x20, 0x00, 0x63, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x65,
0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x6E,
0x00, 0x67, 0x00, 0x75, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x66, 0x00, 0x6F,
0x00, 0x72, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x63, 0x00, 0x75,
0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x20, 0x00, 0x73, 0x00, 0x79,
0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x00, 0x00,
// 0x000B: STR_MISSING_STRING:0x000B
0x14, 0x4D, 0x00, 0x69, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x20,
0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x00, 0x00,
// 0x000C: STR_EMPTY_STRING:0x000C
0x14, 0x00, 0x00,
// 0x000D: STR_RESET_STRING:0x000D
0x14, 0x52, 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00,
// 0x000E: STR_CUSTOMIZE_BANNER_LINE4_LEFT:0x000E
0x14, 0x00, 0x00,
// 0x000F: STR_CUSTOMIZE_BANNER_LINE4_RIGHT:0x000F
0x14, 0x00, 0x00,
// 0x0010: STR_CUSTOMIZE_BANNER_LINE5_LEFT:0x0010
0x14, 0x00, 0x00,
// 0x0011: STR_CUSTOMIZE_BANNER_LINE5_RIGHT:0x0011
0x14, 0x00, 0x00,
// 0x0012: STR_TEST_KEY_USED:0x0012
0x14, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x4E, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x47, 0x00, 0x3A,
0x00, 0x20, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x20, 0x00, 0x6B, 0x00, 0x65,
0x00, 0x79, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74,
0x00, 0x65, 0x00, 0x64, 0x00, 0x2E, 0x00, 0x00, 0x00,
// 0x0013: STR_NULL_STRING:0x0013
0x14, 0x20, 0x00, 0x00, 0x00,
0x00,
// PACKAGE HEADER

0xBC, 0x01, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x66, 0x72,
0x2D, 0x46, 0x52, 0x00,

// PACKAGE DATA

// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
0x14, 0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0xE7, 0x00, 0x61, 0x00, 0x69, 0x00, 0x73,
0x00, 0x00, 0x00,
// 0x0002: STR_FRONT_PAGE_TITLE:0x0002
0x14, 0x46, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61,
0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
// 0x0003: STR_FRONT_PAGE_COMPUTER_MODEL:0x0003
0x14, 0x00, 0x00,
// 0x0004: STR_FRONT_PAGE_CPU_MODEL:0x0004
0x14, 0x00, 0x00,
// 0x0005: STR_FRONT_PAGE_CPU_SPEED:0x0005
0x14, 0x00, 0x00,
// 0x0006: STR_FRONT_PAGE_MEMORY_SIZE:0x0006
0x14, 0x00, 0x00,
// 0x0007: STR_FRONT_PAGE_BIOS_VERSION:0x0007
0x14, 0x00, 0x00,
// 0x0008: STR_CONTINUE_PROMPT:0x0008
0x14, 0x43, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x75, 0x00, 0x65,
0x00, 0x72, 0x00, 0x00, 0x00,
// 0x0009: STR_LANGUAGE_SELECT:0x0009
0x14, 0x43, 0x00, 0x68, 0x00, 0x6F, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x72, 0x00, 0x20,
0x00, 0x6C, 0x00, 0x61, 0x00, 0x20, 0x00, 0x4C, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x75,
0x00, 0x65, 0x00, 0x00, 0x00,
// 0x000A: STR_LANGUAGE_SELECT_HELP:0x000A
0x14, 0x43, 0x00, 0x65, 0x00, 0x63, 0x00, 0x69, 0x00, 0x20, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74,
0x00, 0x20, 0x00, 0x6C, 0x00, 0x27, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F,
0x00, 0x6E, 0x00, 0x20, 0x00, 0x71, 0x00, 0x75, 0x00, 0x27, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x20,
0x00, 0x61, 0x00, 0x6A, 0x00, 0x75, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70,
0x00, 0x6F, 0x00, 0x75, 0x00, 0x72, 0x00, 0x20, 0x00, 0x63, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6E,
0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x20, 0x00, 0x6C,
0x00, 0x61, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x75, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6F,
0x00, 0x75, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x79,
0x00, 0x73, 0x00, 0x74, 0x00, 0xE8, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x20, 0x00, 0x61, 0x00, 0x63,
0x00, 0x74, 0x00, 0x75, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x00, 0x00,
// 0x000B: STR_MISSING_STRING:0x000B
0x14, 0x4D, 0x00, 0x69, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x20,
0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x00, 0x00,
// 0x000C: STR_EMPTY_STRING:0x000C
0x14, 0x00, 0x00,
// 0x000D: STR_RESET_STRING:0x000D
0x14, 0x52, 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00,
// 0x000E: STR_CUSTOMIZE_BANNER_LINE4_LEFT:0x000E
0x14, 0x00, 0x00,
// 0x000F: STR_CUSTOMIZE_BANNER_LINE4_RIGHT:0x000F
0x14, 0x00, 0x00,
// 0x0010: STR_CUSTOMIZE_BANNER_LINE5_LEFT:0x0010
0x14, 0x00, 0x00,
// 0x0011: STR_CUSTOMIZE_BANNER_LINE5_RIGHT:0x0011
0x14, 0x00, 0x00,
// 0x0012: STR_TEST_KEY_USED:0x0012
0x14, 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x4E, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x47, 0x00, 0x3A,
0x00, 0x20, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x20, 0x00, 0x6B, 0x00, 0x65,
0x00, 0x79, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74,
0x00, 0x65, 0x00, 0x64, 0x00, 0x2E, 0x00, 0x00, 0x00,
// 0x0013: STR_NULL_STRING:0x0013
0x14, 0x20, 0x00, 0x00, 0x00,
0x00,
// PACKAGE HEADER

0x58, 0x00, 0x00, 0x04, 0x31, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x65, 0x6E,
0x00,

// PACKAGE DATA

// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
0x14, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64,
0x00, 0x20, 0x00, 0x45, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68,
0x00, 0x00, 0x00,
0x21, 0x12, 0x00,
0x00,
// PACKAGE HEADER

0x5A, 0x00, 0x00, 0x04, 0x31, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x66, 0x72,
0x00,

// PACKAGE DATA

// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
0x14, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64,
0x00, 0x20, 0x00, 0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0xE7, 0x00, 0x61, 0x00, 0x69,
0x00, 0x73, 0x00, 0x00, 0x00,
0x21, 0x12, 0x00,
0x00,

};

比较hpk二进制文件,可以看到跟数组是有对应关系的:

AutoGen.c中生成的字符串来自脚本BaseTools\Source\Python\AutoGen\GenC.py:

if EDK2Module:FilterInfo = [EDK2Module] + [Info.PlatformInfo.Platform.RFCLanguages]
else:FilterInfo = [EDK2Module] + [Info.PlatformInfo.Platform.ISOLanguages]
Header, Code = GetStringFiles(Info.UnicodeFileList, SrcList, IncList, Info.IncludePathList, ['.uni', '.inf'], Info.Name, CompatibleMode, ShellMode, UniGenCFlag, UniGenBinBuffer, FilterInfo)
if CompatibleMode or UniGenCFlag:AutoGenC.Append("\n//\n//Unicode String Pack Definition\n//\n")AutoGenC.Append(Code)AutoGenC.Append("\n")

从这里可以看到一点,AutoGen.c中的字符串数组并不是一定会生成的,而是有一定的条件(if CompatibleMode or UniGenCFlag:)。在更上层的函数调用中有:

Create code for a module

@param Info The ModuleAutoGen object

@param AutoGenC The TemplateString object for C code

@param AutoGenH The TemplateString object for header file

@param StringH The TemplateString object for header file

@param UniGenCFlag UniString is generated into AutoGen C file when it is set to True

@param UniGenBinBuffer Buffer to store uni string package data

@param StringIdf The TemplateString object for header file

@param IdfGenCFlag IdfString is generated into AutoGen C file when it is set to True

@param IdfGenBinBuffer Buffer to store Idf string package data

def CreateCode(Info, AutoGenC, AutoGenH, StringH, UniGenCFlag, UniGenBinBuffer, StringIdf, IdfGenCFlag, IdfGenBinBuffer):
CreateHeaderCode(Info, AutoGenC, AutoGenH)

这里可以看到# @param UniGenCFlag UniString is generated into AutoGen C file when it is set to True,它可以确定是否要在AutoGen.c中创建字符串数组变量。而UniGenCFlag 来自:

AutoGenUniIdf = self.BuildType != ‘UEFI_HII’
1
对于UiApp模块来说,它的BuildType是UEFI_APPLICATION,所以AutoGenUniIdf就是True,这样就一定会在AutoGen.c中创建字符串数组。

而另外一个变量来自CompatibleMode:

if 'BUILD' in Info.BuildOption and Info.BuildOption['BUILD']['FLAGS'].find('-c') > -1:CompatibleMode = True
else:CompatibleMode = False

它判断构建参数,可以通过Makefile看到,也可以通过修改对应的Python脚本增加打印查看,比如当前模块:

Building … defaultdict(, {‘ASLPP’: defaultdict(, {‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\cl.exe’, ‘FLAGS’: ’ /nologo /E /C /FIAutoGen.h’, ‘FAMILY’: ’ MSFT’}), ‘PKCS7SIGN’: defaultdict(, {‘PATH’: ‘Pkcs7Sign’, ‘GUID’: ’ 4AAFD29D-68DF-49EE-8AA9-347D375665A7’, ‘FAMILY’: ’ MSFT’}), ‘VPDTOOL’: defaultdict(, {‘PATH’: ‘BPDG’, ‘GUID’: ’ 8C3D856A-9BE6-468E-850A-24F7A8D38E08’, ‘FAMILY’: ’ MSFT’}), ‘ASLDLINK’: defaultdict(, {‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\link.exe’, ‘FLAGS’: ’ /NODEFAULTLIB /ENTRY:ReferenceAcpiTable /SUBSYSTEM:CONSOLE’, ‘FAMILY’: ’ MSFT’}), ‘GENFW’: defaultdict(, {‘PATH’: ‘GenFw’, ‘FLAGS’: ’ ‘, ‘FAMILY’: ’ MSFT’}), ‘SLINK’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\lib.exe’, ‘FLAGS’: ’ /NOLOGO /LTCG’}), ‘OBJCOPY’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘ADDDEBUGFLAG’: ’ --add-gnu-debuglink=(DEBUGDIR)/(DEBUG_DIR)/(DEBUGD​IR)/(MODULE_NAME).debug’, ‘PATH’: ‘echo’, ‘FLAGS’: ’ objcopy not needed for’}), ‘DEPS’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ /showIncludes’}), ‘ASM’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ /nologo /c /WX /W3 /Cx /Zd /Zi’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\ml64.exe’}), ‘CC’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1b2s /GL /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Z7 /Gw /D DISABLE_NEW_DEPRECATED_INTERFACES /D ENABLE_MD5_DEPRECATED_INTERFACES’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\cl.exe’}), ‘ASMLINK’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\WINDDK\3790.1830\bin\bin16\link16.exe’, ‘FLAGS’: ’ /nologo /tiny’}), ‘TIANO’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘TianoCompress’, ‘GUID’: ’ A31280AD-481E-41B6-95E8-127F4C984779’}), ‘LZMA’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘LzmaCompress’, ‘GUID’: ’ EE4E5898-3914-4259-9D6E-DC7BD79403CF’}), ‘VFR’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘VfrCompile’, ‘FLAGS’: ’ -l -n’}), ‘ASLCC’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\cl.exe’, ‘FLAGS’: ’ /nologo /c /FIAutoGen.h /TC /Dmain=ReferenceAcpiTable’}), ‘APP’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\cl.exe’, ‘FLAGS’: ’ /nologo /E /TC’}), ‘NASM’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ -Ox -f win64 -g’, ‘PATH’: ‘C:\nasm\nasm’}), ‘OPTROM’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘EfiRom’, ‘FLAGS’: ’ -e’}), ‘DTC’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ -H epapr’, ‘PATH’: ‘dtc’}), ‘MAKE’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86\nmake.exe’, ‘FLAGS’: ’ /nologo’}), ‘SYMRENAME’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘echo’, ‘FLAGS’: ’ Symbol renaming not needed for’}), ‘ASM16’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86\ml.exe’}), ‘LZMAF86’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘LzmaF86Compress’, ‘GUID’: ’ D42AE6BD-1352-4bfb-909A-CA72A6EAE889’}), ‘CRC32’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘GenCrc32’, ‘GUID’: ’ FC1BCDB0-7D31-49AA-936A-A4600D9DD083’}), ‘BROTLI’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘BrotliCompress’, ‘GUID’: ’ 3D532050-5CDA-4FD0-879E-0F7F630D5AFB’}), ‘RC’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x86\rc.exe’}), ‘PP’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\cl.exe’, ‘FLAGS’: ’ /nologo /E /TC /FIAutoGen.h’}), ‘VFRPP’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\cl.exe’, ‘FLAGS’: ’ /nologo /E /TC /DVFRCOMPILE /FIKaTeX parse error: Expected 'EOF', got '}' at position 24: …NAME)StrDefs.h'}̲), 'DLINK': def…(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG’, ‘PATH’: ‘C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x64\link.exe’}), ‘RSA2048SHA256SIGN’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘Rsa2048Sha256Sign’, ‘GUID’: ’ A7717414-C616-4977-9420-844712A735BF’}), ‘ASL’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’: ‘C:\ASL\iasl.exe’, ‘FLAGS’: ’ ‘, ‘OUTFLAGS’: ’ -p’}), ‘NASMB’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ -f bin’}), ‘DLINK2’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘FLAGS’: ’ /WHOLEARCHIVE’}), ‘DTCPP’: defaultdict(, {‘FAMILY’: ’ MSFT’, ‘PATH’:
‘cpp’}), ‘BUILD’: defaultdict(, {‘FLAGS’: ‘’})})
1
2
这里面并没有-c这个参数,所以CompatibleMode的值就是False。不过因为AutoGenUniIdf是True,所以还是会创建字符串数组的。

对应的有另外一个示例MdeModulePkg\Universal\HiiResourcesSampleDxe\HiiResourcesSampleDxe.inf,它的类型是UEFI_HII的,且没有-c参数,所以就不会在AutoGen.c中创建字符串数组。查看HiiResourcesSampleDxe.inf这个模块,有一个选项:

[Defines]

This flag specifies whether HII resource section is generated into PE image.

UEFI_HII_RESOURCE_SECTION = TRUE

UEFI_HII_RESOURCE_SECTION表示是否要将hpk文件放到efi二进制中。默认是FALSE的,所以对于UiApp来说hpk文件是不会包含在二进制中。当值是TRUE的时候,这个模块就变成了UEFI_HII,此时如果不涉及兼容性的话,就不会在AutoGen.c中创建字符串了,如果将上述代码加到UiApp这个模块中,就会报错:

f:\gitee\edk2-beni\MdeModulePkg\Application\UiApp\FrontPage.c(285): error C2065: ‘UiAppStrings’: undeclared identifier
1
这两种创建字符串的方式目前都有在使用,且使用hpk二进制文件的方式似乎比较新一点(不过也是2010年的事情了)。

以上介绍的是创建字符串资源的方式,下面介绍如何使用。

对于通过中间文件生成数组的方式,直接在代码中使用该数组即可,比如这里使用的UiAppStrings,可以找到对应的安装资源的代码,位于MdeModulePkg\Application\UiApp\FrontPage.c:

//
// Publish our HII data
//
gFrontPagePrivate.HiiHandle = HiiAddPackages (
&mFrontPageGuid,
gFrontPagePrivate.DriverHandle,
FrontPageVfrBin,
UiAppStrings,
NULL
);
ASSERT (gFrontPagePrivate.HiiHandle != NULL);

对于使用二进制文件过的方式,可以参看前面提到的HiiResourcesSampleDxe.inf模块,在MdeModulePkg\Universal\HiiResourcesSampleDxe\HiiResourcesSample.c代码中有:

//
// Retrieve HII package list from ImageHandle
//
Status = gBS->OpenProtocol (
ImageHandle,
&gEfiHiiPackageListProtocolGuid,
(VOID **) &PackageList,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}

//
// Publish HII package list to HII Database.
//
Status = gHiiDatabase->NewPackageList (
gHiiDatabase,
PackageList,
mDriverHandle,
&mHiiHandle
);
if (EFI_ERROR (Status)) {
return Status;
}
————————————————

相关内容

热门资讯

什么味道让人向往 - 高中(... 什么味道让人向往 - 高中 篇一高中生活,是一个人成长的黄金时期。在这个阶段,我们不仅需要学习知识,...
走向高一作文800字(优选6... 走向高一作文800字 篇一初升高中,迎来了新的挑战和机遇。对于即将步入高一的我来说,这是一个新的起点...
社会主义核心价值观征文【精简... 社会主义核心价值观征文 篇一社会主义核心价值观是指在中国共产党的领导下,以马克思主义、毛泽东思想、邓...
泪高一作文(推荐6篇) 泪高一作文 篇一我的初中生活泪高一,初中三年的生活即将结束,回首走过的路,我心中充满了感慨和不舍。在...
原来如此高一作文(优秀3篇) 原来如此高一作文 篇一:如何做一个高效学习者随着高中的到来,我们迎来了新的学习阶段。在这个阶段,我们...
擦干你的泪水高一作文【优秀3... 擦干你的泪水高一作文 篇一擦干你的泪水泪水,是我们内心最真实的情感的流露。有时,它是因为伤心,因为失...
高二语文作文:我的幸福我做主... 高二语文作文:我的幸福我做主 篇一我的幸福我做主现代社会,人们对于幸福的追求变得越来越强烈。但是,什...
我的自述作文高一800字【精... 我的自述作文高一800字 篇一初入高中,我怀着憧憬和紧张的心情踏入了新的学校。在这个全新的环境中,我...
西游记优美的四字词语【精彩5... 西游记优美的四字词语 篇一西游记是中国古典文学的经典之作,无论是故事情节还是人物形象都给人留下了深刻...
高中作文素材积累(通用5篇) 高中作文素材积累 篇一:人与自然的关系人类与自然的关系是一个永恒的话题,它涉及到人类的生存与发展,也...
阅读,伴我一路成长高一作文(... 阅读,伴我一路成长高一作文 篇一阅读是我的伴侣,伴我一路成长。从小学到初中,我一直喜欢看各种各样的书...
精神应与物质并存高二议论文(... 精神应与物质并存高二议论文 篇一在当今社会,人们常常陷入对精神和物质的对立中。有人认为精神追求比物质...
我当小警察高二作文(优质3篇... 我当小警察高二作文 篇一我当小警察近日,我有幸参加了学校组织的“我当小警察”活动。这是一次非常有意义...
那一刻,我们的距离是0高一作... 那一刻,我们的距离是0高一作文 篇一那一刻,我们的距离是0我记得那是一个阳光明媚的下午,我和同学们聚...
夜凉如水花满枝桠高二作文【精... 夜凉如水花满枝桠高二作文 篇一夜凉如水花满枝桠夏夜的微风拂过,带着一丝丝清凉,仿佛水滴在心头涟漪开来...
笨女孩也是天使高二作文【优秀... 笨女孩也是天使高二作文 篇一我曾经是一个笨女孩,总是在学习上犯错误,常常被同学笑话。但我相信,即使是...
绵山游记高一作文【实用3篇】 绵山游记高一作文 篇一绵山游记绵山,位于四川省南充市嘉陵区,是一座著名的山岳旅游胜地。我有幸在暑假期...
优秀的男孩们高二作文【精彩3... 优秀的男孩们高二作文 篇一优秀的男孩们男孩们,你们是社会的未来,是家庭的希望,是校园的风景。作为高二...
高三责任与担当作文800字【... 高三责任与担当作文800字 篇一高三,是每个学生都期待的一年,也是每个学生都感到压力巨大的一年。在这...
记忆中的红薯粉高一作文【精简... 记忆中的红薯粉高一作文 篇一红薯粉是我童年时的美味回忆。每逢夏日,妈妈总是会准备一碗清爽可口的红薯粉...