Hii&IFR

Hii

        Hii(HUMAN INTERFACE INFRASTRUCTURE)人机界面基础设施,这是一组协议,允许UEFI驱动程序提供向平台固件注册用户界面和配置内容的能力。与传统的选项rom不同,驱动程序和控制器的配置会延迟,直到平台管理实用程序选择使用这些协议的服务为止。UEFI驱动程序不允许在这些协议的上下文之外执行类似于设置的操作。这意味着驱动程序不允许在此协议的上下文之外与用户进行交互。

        下面的示例显示了一个基本的平台配置。驱动程序和应用程序将元素(如字体、字符串、图像和表单)安装到HII DataBase中,该数据库作为整个平台的中央存储库。IFR Browser使用这些元素在Display Devices上呈现用户界面,并通过HID Devices接收来自用户的信息。完成后,用户在IFR Browser中所做的更改将被保存到UEFI Global Variable Store存储(通过GetVariable函数和SetVariable函数,或者驱动程序或应用程序提供的私有变量存储)。

IFR

        IFR是针对hii相关对象的二进制编码。

        每个对象都具有(至少)三个属性:

        Opcode,操作码,枚举所有不同的的Hii相关对象。

        Length,长度,操作码自身的长度。

        Scope,这将打开一个新的作用域。某些对象描述的属性或功能只适用于当前范围,而不是整个表单。该范围一直扩展到特殊的结束操作码,它标志着当前范围的结束。

        每个对象都以EFI_IFR_OP_HEADER开头,它描述了操作码的上述三个属性。

        二进制对象由一个EFI_IFR_OP_HEADER组成,它包含一个8位Op、一个7位Length和一个1位Scope。Length指定了整个对象的长度,包括Header。

        当设置了作用域位时,它标记了一个新作用域的开始,该新作用域应用于所有后续操作码,直到找到匹配的EFI_IFR_END_OP来关闭该作用域。这些操作码也可以打开新的作用域,从而创建嵌套作用域。

        以OVMF.fd中PlatformForms为例,其下包含vfr文件,该文件构筑了OVMF的Bios中的OVMF setting界面。可以看到其内部主要实现了一个修改分辨率操作,当分辨率被修改后,会在下次boot时启用,目前可以得知的是,类似于这种非默认值的修改,其值都是存储在了NVram里,如前文提到的global variable store或驱动指定的存储区,这能使得其在掉电后不被擦除,但是也可以确定修改并不能修改到OVMF.fd上,因为当关闭qemu,重新起OVMF.fd会发现,分辨率又恢复了default值。

        该界面其实是由ifr驱动的,而ifr文件是由vfr文件经过vfrcompile工具编译得来的,主要关注其得到的二进制.c文件与.lst文件,这两个文件与OVMF.fd有直接联系

        通过观察其生成的.c文件可以看到该vfr文件是如何在OVMF.fd中以二进制形式存储的,其主要构成形式为三部分:ARRAY LENGTH、PACKAGE HEADER、PACKAGE DATA

        ARRAY LENGTH:主要标识了总长度,其0xB2即为178,意味着该package总长度为178字节,可以自己数数。

        PACKAGE HEADER:包头,主要标识了该package的总长度,其实就是除去 ARRAY LENGTH,此处为0xAE,就是174字节,而最后有个0x02其实是标识该package的类型,此处为0x02,就是FORMS。

        PACKAGE DATA:此处就是package数据了,此处的所有数据可以分析.lst文件,两者是一样的。

        根据前面提到的IFR中每个对象有至少有三个属性,分别是OP、SCOPE、LENGTH,我们来看PACKAGE DATA。

        首先就是第一个对象,第一个字节0x0E就是其OP、根据操作码表可以得知是EFI_IFR_FORM_SET_OP,而第二个字节0xA7最高1位代表SCOPE,置1开启作用域,低7位代表LENGTH,此处位39字节,由此便可红色框出该对象的范围。

        该范围所表示的其实就是EFI_IFR_FORM_SET结构体,

        可以看到Header就是前两个字节0x0E、0xA7,

        接着是GUID,从0x1C--0xB1,

        接下来是FormSetTitle,0x02,0x00,

        Help,0x03,0x00,

        Flags,0x01,

        此处还有ClassGuid,从0x71--0x0E。

        接下来便是第二个对象,其操作码0x5C,表示EFI_IFR_DEFAULTSTORE_OP,SCOPE+LENGTH为0x06,SCOPE为0,LENGTH为6字节,即到下一个0x5C处。

        以此类推。

#define EFI_IFR_FORM_OP                0x01
#define EFI_IFR_SUBTITLE_OP            0x02
#define EFI_IFR_TEXT_OP                0x03
#define EFI_IFR_IMAGE_OP               0x04
#define EFI_IFR_ONE_OF_OP              0x05
#define EFI_IFR_CHECKBOX_OP            0x06
#define EFI_IFR_NUMERIC_OP             0x07
#define EFI_IFR_PASSWORD_OP            0x08
#define EFI_IFR_ONE_OF_OPTION_OP       0x09
#define EFI_IFR_SUPPRESS_IF_OP         0x0A
#define EFI_IFR_LOCKED_OP              0x0B
#define EFI_IFR_ACTION_OP              0x0C
#define EFI_IFR_RESET_BUTTON_OP        0x0D
#define EFI_IFR_FORM_SET_OP            0x0E
#define EFI_IFR_REF_OP                 0x0F
#define EFI_IFR_NO_SUBMIT_IF_OP        0x10
#define EFI_IFR_INCONSISTENT_IF_OP     0x11
#define EFI_IFR_EQ_ID_VAL_OP           0x12
#define EFI_IFR_EQ_ID_ID_OP            0x13
#define EFI_IFR_EQ_ID_VAL_LIST_OP      0x14
#define EFI_IFR_AND_OP                 0x15
#define EFI_IFR_OR_OP                  0x16
#define EFI_IFR_NOT_OP                 0x17
#define EFI_IFR_RULE_OP                0x18
#define EFI_IFR_GRAY_OUT_IF_OP         0x19
#define EFI_IFR_DATE_OP                0x1A
#define EFI_IFR_TIME_OP                0x1B
#define EFI_IFR_STRING_OP              0x1C
#define EFI_IFR_REFRESH_OP             0x1D
#define EFI_IFR_DISABLE_IF_OP          0x1E
#define EFI_IFR_TO_LOWER_OP            0x20
#define EFI_IFR_TO_UPPER_OP            0x21
#define EFI_IFR_MAP_OP                 0x22
#define EFI_IFR_ORDERED_LIST_OP        0x23
#define EFI_IFR_VARSTORE_OP            0x24
#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25
#define EFI_IFR_VARSTORE_EFI_OP        0x26
#define EFI_IFR_VARSTORE_DEVICE_OP     0x27
#define EFI_IFR_VERSION_OP             0x28
#define EFI_IFR_END_OP                 0x29
#define EFI_IFR_MATCH_OP               0x2A
#define EFI_IFR_GET_OP                 0x2B
#define EFI_IFR_SET_OP                 0x2C
#define EFI_IFR_READ_OP                0x2D
#define EFI_IFR_WRITE_OP               0x2E
#define EFI_IFR_EQUAL_OP               0x2F
#define EFI_IFR_NOT_EQUAL_OP           0x30
#define EFI_IFR_GREATER_THAN_OP        0x31
#define EFI_IFR_GREATER_EQUAL_OP       0x32
#define EFI_IFR_LESS_THAN_OP           0x33
#define EFI_IFR_LESS_EQUAL_OP          0x34
#define EFI_IFR_BITWISE_AND_OP         0x35
#define EFI_IFR_BITWISE_OR_OP          0x36
#define EFI_IFR_BITWISE_NOT_OP         0x37
#define EFI_IFR_SHIFT_LEFT_OP          0x38
#define EFI_IFR_SHIFT_RIGHT_OP         0x39
#define EFI_IFR_ADD_OP                 0x3A
#define EFI_IFR_SUBTRACT_OP            0x3B
#define EFI_IFR_MULTIPLY_OP            0x3C
#define EFI_IFR_DIVIDE_OP              0x3D
#define EFI_IFR_MODULO_OP              0x3E
#define EFI_IFR_RULE_REF_OP            0x3F
#define EFI_IFR_QUESTION_REF1_OP       0x40
#define EFI_IFR_QUESTION_REF2_OP       0x41
#define EFI_IFR_UINT8_OP               0x42
#define EFI_IFR_UINT16_OP              0x43
#define EFI_IFR_UINT32_OP              0x44
#define EFI_IFR_UINT64_OP              0x45
#define EFI_IFR_TRUE_OP                0x46
#define EFI_IFR_FALSE_OP               0x47
#define EFI_IFR_TO_UINT_OP             0x48
#define EFI_IFR_TO_STRING_OP           0x49
#define EFI_IFR_TO_BOOLEAN_OP          0x4A
#define EFI_IFR_MID_OP                 0x4B
#define EFI_IFR_FIND_OP                0x4C
#define EFI_IFR_TOKEN_OP               0x4D
#define EFI_IFR_STRING_REF1_OP         0x4E
#define EFI_IFR_STRING_REF2_OP         0x4F
#define EFI_IFR_CONDITIONAL_OP         0x50
#define EFI_IFR_QUESTION_REF3_OP       0x51
#define EFI_IFR_ZERO_OP                0x52
#define EFI_IFR_ONE_OP                 0x53
#define EFI_IFR_ONES_OP                0x54
#define EFI_IFR_UNDEFINED_OP           0x55
#define EFI_IFR_LENGTH_OP              0x56
#define EFI_IFR_DUP_OP                 0x57
#define EFI_IFR_THIS_OP                0x58
#define EFI_IFR_SPAN_OP                0x59
#define EFI_IFR_VALUE_OP               0x5A
#define EFI_IFR_DEFAULT_OP             0x5B
#define EFI_IFR_DEFAULTSTORE_OP        0x5C
#define EFI_IFR_FORM_MAP_OP            0x5D
#define EFI_IFR_CATENATE_OP            0x5E
#define EFI_IFR_GUID_OP                0x5F
#define EFI_IFR_SECURITY_OP            0x60
#define EFI_IFR_MODAL_TAG_OP           0x61
#define EFI_IFR_REFRESH_ID_OP          0x62
#define EFI_IFR_WARNING_IF_OP          0x63
#define EFI_IFR_MATCH2_OP              0x64

           分解第一个对象的二进制内容,可以看到如下,其中尤其注意FormSetTitle,此处的0x02对应了AutoGen文件中的STR_FORMSET_TITLE,其实就是将uni文件中的字符串转换成了二进制存储在AutoGen文件中。

// 第一个对象
// OP
0x0E,  
// SCOPE + LENGTH
0xA7,  
// OVMF_PLATFORM_CONFIG_GUID
0x1C,  0xC5,  0x35,  0x72,  0x80,  0x0C,  0xAB,  0x4C,  0x87,  0xAC,  0x3B,  0x08,  0x4A,  0x63,  0x04,  0xB1,  
// FormSetTitle:字符串Token,在AutoGen中定义,对应的是STR_FRONT_PAGE_TITLE,值就是0x0002
0x02,  0x00,  
// Help:字符串Token,在AutoGen中定义,对应的是STR_FORMSET_HELP,值就是0x0003
0x03,  0x00,  
// Flags
0x01,  
// EFI_HII_PLATFORM_SETUP_FORMSET_GUID
0x71,  0x99,  0x03,  0x93,  0x45,  0x85,  0x04,  0x4B,  0xB4,  0x5E,  0x32,  0xEB,  0x83,  0x26,  0x04,  0x0E

         根据对第一个对象进行全分解,可以得出ifr在OVMF.fd中到底是如何存放的

         拆解第二个第三个对象,可以看到0x5C代表DEFAULTSTORE操作码,其结构体如下,而结构体内的DefaultId应该是由其下面的define声明的内容。

// 第二个对象
// EFI_IFR_DEFAULTSTORE_OP
0x5C,  
// SCOPE + LENGTH
0x06,  
// DefaultName:NULL
0x00,  0x00,  
// DefaultId:EFI_HII_DEFAULT_CLASS_STANDARD
0x00,  0x00,  

// 第三个对象
// EFI_IFR_DEFAULTSTORE_OP
0x5C,  
// SCOPE + LENGTH
0x06,  
// DefaultName:NULL
0x00,  0x00,  
// DefaultId:EFI_HII_DEFAULT_CLASS_MANUFACTURING
0x01,  0x00, 


#define EFI_HII_DEFAULT_CLASS_STANDARD       0x0000
#define EFI_HII_DEFAULT_CLASS_MANUFACTURING  0x0001
#define EFI_HII_DEFAULT_CLASS_SAFE           0x0002
#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000
#define EFI_HII_DEFAULT_CLASS_PLATFORM_END   0x7fff
#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000
#define EFI_HII_DEFAULT_CLASS_HARDWARE_END   0xbfff
#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000
#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END   0xffff

        在platformforms.vfr中还有一组比较特殊的操作码需要分析,那就是label,label在vfr文件中非常简短,就一个label LABEL_RES_NEXT,但是,这一段却直接表示的是前文提到的OVMF的分辨率。

        label相当于一个VFR中的一个占位符,本身不会产生可显示的内容,而是需要通过代码动态的增加显示内容,具体如何增加,就是使用HiiCreateXXX()函数在增加form组件。

        所以可以知道OVMF中的分辨率其实是HiiCreateXXX()产生的。

        那么看label的ifr文件,首先依旧是OP:0x5F,表示EFI_IFR_GUID_OP,这里可能会好奇为什么是GUID_OP,不是LABEL_OP,我们看它的结构体也会发现很奇怪,对不上,其实GUID_OP代表的是可扩展的GUID操作码。

        其实label的真实定义在 MdeModuleHii.h中,这里涉及到一个GUID,EFI_IFR_TIANO_GUID,该GUID下包含了IFR的扩展操作码,即LABEL、BANNER、TIMEOUT、CLASS、SUBCLASS,也就是说当读到操作码5F后,首先会定位到EFI_IFR_GUID结构体,但是该结构体又是一个包含了以上几种扩展操作码的集合,因此这样去理解前面的ifr就很容易了。

        根据EFI_IFR_GUID_LABEL结构体来看ifr,5F、15代表Header,即OP以及SCOPE+LENGTH,接下来的16位对应着EFI_IFR_TIANO_GUID,根据上图定义的LABEL为0x0,EFI_IFR_TIANO_GUID后的00就代表着此处为一个label,最后的2字节0100,代表着label number为1。

FCE Tool

流程

Read

        FCE执行代码如下

  

        得到的txt文件中的某一个Form如图,图中第一个16进制数000A表示该UQI长度,即10个

         Form在文档中声明的格式如下

        其中Question Type有5种类型,举例处为CHECKBOX。

        如果是ONE_OF、NUMERIC、CHECKBOX,那么这个值为一个16进制数。

        如果是ORDERED_LIST,值为一个包含数组大小的16进制数

        如果是STRING,值为一个带有双引号的字符串

Update

verify

Updateq

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值