资讯详情

【UEFI实战】HII之uni文件

uni文件

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

关于uni参考文件中对文件的作用作了如下说明:

在这里插入图片描述

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

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

这里的对应一个在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根据实际示例,使用规则过于复杂。例如,以下示例来自参考文档,它定义了一些最基本的语法概念:

<US>    ::= " " <Letter>   ::= { 
        (\u0041-\u005A)} ; Characters A - Z     { 
        (\u0061-\u007A)} ; Characters a - z
<Digit> 		::= (\u0030-\u0039) ; Characters 0 - 9
<MS> 			::= <US>+
<ME> 			::= { 
        <MS>} { 
        <EOL>}
<CommentLine> 	::= "//" <US>* <PCHars> <EOL>
<BlankLine> 	::= <EOL>
<Chars> 		::= (\u0001-\uF6FF)
<PChars> 		::= { 
        (\u0020-\uF6FF)} { 
        <OpChar>}
<OpChars> 		::= "\x" [{ 
        <Letter>} { 
        <Digit>}]{ 
        4} "\"
<VChars> 		::= (\u0021-\uF6FF)
<UnicodeLines> 	::= <Token> <ME>
					[<Ldef> [<String> <ME>]+]+
<Ldef> 			::= <CtrlChar> "language" <MS> <LangCode> <M
<HexDigit> 		::= { 
        <Digit>}
					{ 
        (\u0041-\u0046)} ; Characters A - F
					{ 
        (\u0061-\u0066)} ; Characters a - f
<CtrlChar> 		::= <US>* "#"
<Token> 		::= <CtrlChar> "string" <MS> <Identifier>
<Identifier> 	::= <Letter> [{ 
        <Letter>} { 
        <Digit>} { 
        <UN>}]*
<LangCode> 		::= <RFC4646>
<RFC4646> 		::= <Letter>{ 
        2,8} [<ShortExt> <LongExt>*]
<ShortExt> 		::= "-" [{ 
        <Letter>} { 
        <Digit>}]{ 
        1,8}
<LongExt> 		::= "-" [{ 
        <Letter>} { 
        <Digit>}]{ 
        1,}
<UDblQuote> 	::= \u0022 ; Double Quote Character, "
<String> 		::= <UDblQuote> <SContent>* <UDblQuote>
<SContent> 		::= { 
        <PChars>} { 
        <Attributes>}
<Attributes> 	::= "\" {"narrow"} {"wide"} { 
        <UDblQuote>}
					{ 
        "n"} { 
        "r"} { 
        "t"} { 
        "nbr"} { 
        "\"} {"'"}

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

<US> 			::= " "

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

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

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

<Letter> 		::= { 
        (\u0041-\u005A)}{ 
        (\u0061-\u007A)}

{}表示重复,[]表示可选,()表示分组。不过这样似乎也不能解释上面的代码,可以明确的是<Letter>表示的是a-zA-Z中的一个字母。同理<Digit>表示一个数字。

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

<MS> 			::= <US>+
<ME> 			::= { 
        <MS>} { 
        <EOL>}

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

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

语言基础

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

<StringFileFormat> 	::= <CommentLine>*
						<LanguageDefs>
						<Content>+

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

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

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

<CtrlChar> 			::= "/"
<ControlRefactor> 	::= <CtrlChar> "=" <NewCtrlChar> <EOL>
<NewCtrlChar> 		::= (0x0021 - 0xF6FF)

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

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

<CommentLine><LanguageDefs>两部分都比较简单,这里主要说明下<Content>,它的定义如下:

<Content> 	::= { 
        <CommentLine>} { 
        <BlankLine>}
				{ 
        <UnicodeLines>} { 
        <ControlRefactor>}
				{ 
        <LanguageDefs>} { 
        <SecurityLines>}
				{ 
        <IncludeLines>}

这里简单说明:

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

上述<Content>的定义中,最重要的就是<UnicodeLines>了,它的定义如下:

<UnicodeLines> 	::= "#string" <MS> <Identifier> <ME>
					[<FontId>]
					[<LangLine>]+
<LangLine> 		::= "#language" <MS> lang-code <ME> <FontString>
<FontString> 	::= [<FontId>] [<strings>]+
<FontId> 		::= ["#font" <MS> font-identifier> <ME>]
<strings> 		::= <String> <ME>

下面是一个具体的例子:

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

"#fontdef" <MS> _font-identifier_ <MS> <FontOptions> <EOL>
<FontOptions> 	::= font-name <MS> font-size [<MS> font-style-list]
font-style-list ::= <UDblQuote> [fs-entries] <UDblQuote>
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"

它用于UEFI发布,也可以不用特别关注。

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

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

gAutoGenStringFormFileName = "%(module_name)sStrDefs.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 

标签: hpk无功功率变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台