概要
参考资料:efi-human-interface-infrastructure-specification-v092.pdf、SetupDesignGuide.pdf
Hii:Human Interface Infrastructure 的缩写。
其在UEFI中的体现是 BIOS Setup的内容显示。
gEfiHiiStringProtocolGuid、
gEfiHiiDatabaseProtocolGuid、
gEfiHiiConfigRoutingProtocolGuid,
//常用的几个Protocol
整体架构流程
HiiDataBase由多个PackageList组成,每个PackageList对应一个HiiHandle数据存放在一块连续内存,通过HiiHandle可以找到对应的PackageList;每个PackageList由多个Package组成。
EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}};
EFI_HII_DATABASE_PROTOCOL
///
/// Database manager for HII-related data structures.
///
struct _EFI_HII_DATABASE_PROTOCOL {
EFI_HII_DATABASE_NEW_PACK NewPackageList;
EFI_HII_DATABASE_REMOVE_PACK RemovePackageList;
EFI_HII_DATABASE_UPDATE_PACK UpdatePackageList;
EFI_HII_DATABASE_LIST_PACKS ListPackageLists;
EFI_HII_DATABASE_EXPORT_PACKS ExportPackageLists;
EFI_HII_DATABASE_REGISTER_NOTIFY RegisterPackageNotify;
EFI_HII_DATABASE_UNREGISTER_NOTIFY UnregisterPackageNotify;
EFI_HII_FIND_KEYBOARD_LAYOUTS FindKeyboardLayouts;
EFI_HII_GET_KEYBOARD_LAYOUT GetKeyboardLayout;
EFI_HII_SET_KEYBOARD_LAYOUT SetKeyboardLayout;
EFI_HII_DATABASE_GET_PACK_HANDLE GetPackageListHandle;
};
常用的几个接口函数:ListPackageLists(导出HiiHandles)、ExportPackageLists(根据HiiHandle导出对应的PackageList)、GetPackageListHandle(获取HiiHandle对应的DriverHandle,用于获取DevicePath等用途)
/**
This function returns a list of the package handles of the
specified type that are currently active in the database. The
pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package
handles to be listed.
@param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
@param PackageType Specifies the package type of the packages
to list or EFI_HII_PACKAGE_TYPE_ALL for
all packages to be listed.
@param PackageGuid If PackageType is
EFI_HII_PACKAGE_TYPE_GUID, then this is
the pointer to the GUID which must match
the Guid field of
EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it
must be NULL.
@param HandleBufferLength On input, a pointer to the length
of the handle buffer. On output,
the length of the handle buffer
that is required for the handles found.
@param Handle An array of EFI_HII_HANDLE instances returned.
@retval EFI_SUCCESS The matching handles are outputted successfully.
HandleBufferLength is updated with the actual length.
@retval EFI_BUFFER_TOO_SMALL The HandleBufferLength parameter
indicates that Handle is too
small to support the number of
handles. HandleBufferLength is
updated with a value that will
enable the data to fit.
@retval EFI_NOT_FOUND No matching handle could be found in database.
@retval EFI_INVALID_PARAMETER HandleBufferLength was NULL.
@retval EFI_INVALID_PARAMETER The value referenced by HandleBufferLength was not
zero and Handle was NULL.
@retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but
PackageGuid is not NULL, PackageType is a EFI_HII_
PACKAGE_TYPE_GUID but PackageGuid is NULL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HII_DATABASE_LIST_PACKS)(
IN CONST EFI_HII_DATABASE_PROTOCOL *This,
IN UINT8 PackageType,
IN CONST EFI_GUID *PackageGuid,
IN OUT UINTN *HandleBufferLength,
OUT EFI_HII_HANDLE *Handle
);
/**
This function will export one or all package lists in the
database to a buffer. For each package list exported, this
function will call functions registered with EXPORT_PACK and
then copy the package list to the buffer. The registered
functions may call EFI_HII_DATABASE_PROTOCOL.UpdatePackageList()
to modify the package list before it is copied to the buffer. If
the specified BufferSize is too small, then the status
EFI_OUT_OF_RESOURCES will be returned and the actual package
size will be returned in BufferSize.
@param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
@param Handle An EFI_HII_HANDLE that corresponds to the
desired package list in the HII database to
export or NULL to indicate all package lists
should be exported.
@param BufferSize On input, a pointer to the length of the
buffer. On output, the length of the
buffer that is required for the exported
data.
@param Buffer A pointer to a buffer that will contain the
results of the export function.
@retval EFI_SUCCESS Package exported.
@retval EFI_OUT_OF_RESOURCES BufferSize is too small to hold the package.
@retval EFI_NOT_FOUND The specified Handle could not be found in the
current database.
@retval EFI_INVALID_PARAMETER BufferSize was NULL.
@retval EFI_INVALID_PARAMETER The value referenced by BufferSize was not zero
and Buffer was NULL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HII_DATABASE_EXPORT_PACKS)(
IN CONST EFI_HII_DATABASE_PROTOCOL *This,
IN EFI_HII_HANDLE Handle,
IN OUT UINTN *BufferSize,
OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer
);
/**
Return the EFI handle associated with a package list.
@param This A pointer to the EFI_HII_PROTOCOL instance.
@param PackageListHandle An EFI_HII_HANDLE that corresponds
to the desired package list in the
HIIdatabase.
@param DriverHandle On return, contains the EFI_HANDLE which
was registered with the package list in
NewPackageList().
@retval EFI_SUCCESS The DriverHandle was returned successfully.
@retval EFI_INVALID_PARAMETER The PackageListHandle was not valid.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HII_DATABASE_GET_PACK_HANDLE)(
IN CONST EFI_HII_DATABASE_PROTOCOL *This,
IN EFI_HII_HANDLE PackageListHandle,
OUT EFI_HANDLE *DriverHandle
);
如何遍历?
遍历整个HiiDataBase首先从HiiHandles入手,因为每个HiiHandle就是一个PackageList,所以便利每个HiiHandle时导出一个PackageList。
EDK2中的例子有:
//
// Get all the Hii handles
//
HiiHandles = HiiGetHiiHandles (NULL);
ASSERT (HiiHandles != NULL);
//
// Search for formset of each class type
//
for (Index = 0; HiiHandles[Index] != NULL; Index++) {
Status = HiiGetFormSetFromHiiHandle (HiiHandles[Index], &Buffer, &BufferSize);
if (EFI_ERROR (Status)) {
continue;
}
/**
This function allows a caller to extract the form set opcode form the Hii Handle.
The returned buffer is allocated using AllocatePool().The caller is responsible
for freeing the allocated buffer using FreePool().
@param Handle The HII handle.
@param Buffer On return, points to a pointer which point to the buffer that contain the formset opcode.
@param BufferSize On return, points to the length of the buffer.
@retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
@retval EFI_NOT_FOUND Can't find the package data for the input Handle.
@retval EFI_INVALID_PARAMETER The input parameters are not correct.
@retval EFI_SUCCESS Get the formset opcode from the hii handle successfully.
**/
EFI_STATUS
EFIAPI
HiiGetFormSetFromHiiHandle (
IN EFI_HII_HANDLE Handle,
OUT EFI_IFR_FORM_SET **Buffer,
OUT UINTN *BufferSize
)
{
EFI_STATUS Status;
UINTN PackageListSize;
UINTN TempSize;
EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
UINT8 *Package;
UINT8 *OpCodeData;
UINT8 *FormSetBuffer;
UINT8 *TempBuffer;
UINT32 Offset;
UINT32 Offset2;
UINT32 PackageListLength;
EFI_HII_PACKAGE_HEADER PackageHeader;
TempSize = 0;
FormSetBuffer = NULL;
TempBuffer = NULL;
//
// Get HII PackageList
//
PackageListSize = 0;
HiiPackageList = NULL;
Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
return Status;
}
HiiPackageList = AllocatePool (PackageListSize);
if (HiiPackageList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
ASSERT_EFI_ERROR (Status);
//
// Get Form package from this HII package List
//
Status = EFI_NOT_FOUND;
Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
while (Offset < PackageListLength) {
Package = ((UINT8 *)HiiPackageList) + Offset;
CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
Offset += PackageHeader.Length;
if (PackageHeader.Type != EFI_HII_PACKAGE_FORMS) {
continue;
}
//
// Search FormSet Opcode in this Form Package
//
Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
while (Offset2 < PackageHeader.Length) {
OpCodeData = Package + Offset2;
Offset2 += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
if (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode != EFI_IFR_FORM_SET_OP) {
continue;
}
if (FormSetBuffer != NULL) {
TempBuffer = ReallocatePool (
TempSize,
TempSize + ((EFI_IFR_OP_HEADER *)OpCodeData)->Length,
FormSetBuffer
);
if (TempBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
CopyMem (TempBuffer + TempSize, OpCodeData, ((EFI_IFR_OP_HEADER *)OpCodeData)->Length);
FormSetBuffer = NULL;
} else {
TempBuffer = AllocatePool (TempSize + ((EFI_IFR_OP_HEADER *)OpCodeData)->Length);
if (TempBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
CopyMem (TempBuffer, OpCodeData, ((EFI_IFR_OP_HEADER *)OpCodeData)->Length);
}
TempSize += ((EFI_IFR_OP_HEADER *)OpCodeData)->Length;
FormSetBuffer = TempBuffer;
Status = EFI_SUCCESS;
//
// One form package has one formset, exit current form package to search other form package in the packagelist.
//
break;
}
}
Done:
FreePool (HiiPackageList);
*BufferSize = TempSize;
*Buffer = (EFI_IFR_FORM_SET *)FormSetBuffer;
return Status;
}
if (PackageHeader.Type != EFI_HII_PACKAGE_FORMS) {
continue;
}
//**这里表示只要Type为 EFI_HII_PACKAGE_FORMS 的 PackageList 其余定义如下**
//
// Value of HII package type
//
#define EFI_HII_PACKAGE_TYPE_ALL 0x00
#define EFI_HII_PACKAGE_TYPE_GUID 0x01
#define EFI_HII_PACKAGE_FORMS 0x02
#define EFI_HII_PACKAGE_STRINGS 0x04
#define EFI_HII_PACKAGE_FONTS 0x05
#define EFI_HII_PACKAGE_IMAGES 0x06
#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07
#define EFI_HII_PACKAGE_DEVICE_PATH 0x08
#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09
#define EFI_HII_PACKAGE_ANIMATIONS 0x0A
#define EFI_HII_PACKAGE_END 0xDF
#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF
进入PackageList后就是遍历Form Package,根据不同的OpCode做对应操作:
**((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode != EFI_IFR_FORM_SET_OP**
//
// IFR Opcodes
//
#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_ANIMATION_OP 0x1F
#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
这些OpCode分别对应vfr文件的定义:
formset
guid = PLAT_OVER_MNGR_GUID,
title = STRING_TOKEN(STR_ENTRY_TITLE),
help = STRING_TOKEN(STR_TITLE_HELP),
varstore PLAT_OVER_MNGR_DATA,
varid = VARSTORE_ID_PLAT_OVER_MNGR,
name = Data,
guid = PLAT_OVER_MNGR_GUID;
form formid = FORM_ID_DEVICE,
title = STRING_TOKEN(STR_TITLE);
text
help = STRING_TOKEN(STR_FIRST_REFRESH_HELP),
text = STRING_TOKEN(STR_FIRST_REFRESH),
flags = INTERACTIVE,
key = KEY_VALUE_DEVICE_REFRESH;
checkbox varid = Data.PciDeviceFilter,
prompt = STRING_TOKEN(STR_PCI_DEVICE_FILTER_PROMPT),
help = STRING_TOKEN(STR_PCI_DEVICE_FILTER_HELP),
flags = INTERACTIVE,
key = KEY_VALUE_DEVICE_FILTER,
endcheckbox;
label FORM_ID_DEVICE;
label LABEL_END;
subtitle text = STRING_TOKEN(STR_NULL_STRING);
goto FORM_ID_DEVICE,
prompt = STRING_TOKEN(STR_CLEAR_ALL),
help = STRING_TOKEN(STR_CLEAR_ALL_HELP),
flags = INTERACTIVE | RESET_REQUIRED,
key = KEY_VALUE_DEVICE_CLEAR;
endform;
form formid = FORM_ID_DRIVER,
title = STRING_TOKEN(STR_TITLE);
goto FORM_ID_DEVICE,
prompt = STRING_TOKEN(STR_GOTO_PREVIOUS),
help = STRING_TOKEN(STR_NULL_STRING),
flags = INTERACTIVE,
key = KEY_VALUE_DRIVER_GOTO_PREVIOUS;
goto FORM_ID_ORDER,
prompt = STRING_TOKEN(STR_TITLE_ORDER),
help = STRING_TOKEN(STR_TITLE_ORDER_HELP),
flags = INTERACTIVE,
key = KEY_VALUE_DRIVER_GOTO_ORDER;
label FORM_ID_DRIVER;
label LABEL_END;
endform;
form formid = FORM_ID_ORDER,
title = STRING_TOKEN(STR_TITLE);
goto FORM_ID_DRIVER,
prompt = STRING_TOKEN(STR_GOTO_PREVIOUS),
help = STRING_TOKEN(STR_NULL_STRING),
flags = INTERACTIVE,
key = KEY_VALUE_ORDER_GOTO_PREVIOUS;
label FORM_ID_ORDER;
label LABEL_END;
subtitle text = STRING_TOKEN(STR_NULL_STRING);
text
help = STRING_TOKEN (STR_NULL_STRING),
text = STRING_TOKEN (STR_SAVE_AND_EXIT),
flags = INTERACTIVE | RESET_REQUIRED,
key = KEY_VALUE_ORDER_SAVE_AND_EXIT;
endform;
endformset;
**//以及**
efivarstore CONSOLE_PREF_VARSTORE_DATA,
attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attributes
name = ConsolePref,
guid = CONSOLE_PREF_FORMSET_GUID;
oneof varid = ConsolePref.Console,
prompt = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT),
help = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP),
flags = NUMERIC_SIZE_1 | INTERACTIVE,
option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT;
option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0;
endoneof;
//通过HiiGetString 函数来提取对应StringId 所对应的内容。StringId == STRING_TOKEN(STR_CONSOLE_PREF_SERIAL)
String = HiiGetString (gStringPackHandle, StringId, NULL);
小结
HiiDatabase保存了所有在Setup中显示的静态内容,动态内容有些设备无法获取到。注意:有些设备的PackageListGuid是固定的有些则是运行时生成的。