UEFI開(kāi)發(fā)基礎(chǔ)HII代碼示例
代碼示例
代碼 https://gitee.com/jiangwei0512/edk2-beni
模塊
BeniPkg\DynamicCommand\SetupDynamicCommand\SetupDynamicCommand.inf。
這里通過(guò)一個(gè)命令setup來(lái)打開(kāi)圖形界面。圖形界面的form在Page.vfr中,還有若干的uni文件存放字符串,并通過(guò)如下的代碼來(lái)初始化:
EFI_HII_HANDLE
InitializeHiiPackage (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
EFI_HII_PACKAGE_LIST_HEADER *PackageList;
EFI_HII_HANDLE HiiHandle;
//
// 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 NULL;
}
//
// Publish HII package list to HII Database.
//
Status = gHiiDatabase->NewPackageList (
gHiiDatabase,
PackageList,
NULL,
&HiiHandle
);
if (EFI_ERROR (Status)) {
return NULL;
}
return HiiHandle;
}
這里使用了將資源放到二進(jìn)制中的方式。然后通過(guò)如下的代碼來(lái)顯示圖形:
VOID
DisplayPage (
VOID
)
{
EFI_STATUS Status;
EFI_BROWSER_ACTION_REQUEST ActionRequest;
Status = EFI_UNSUPPORTED;
ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
Status = gFormBrowser2->SendForm (
gFormBrowser2,
&mSetupHiiHandle,
1,
&mFrontPageGuid,
0,
NULL,
&ActionRequest
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "[BENI]SendForm failed. - %r\n", Status));
}
}
formset
一開(kāi)始使用的Page.vfr文件內(nèi)容:
// {76B732B8-B777-4ECF-A84E-7A8CA2484555}
#define FORMSET_GUID { 0x76b732b8, 0xb777, 0x4ecf, 0xa8, 0x4e, 0x7a, 0x8c, 0xa2, 0x48, 0x45, 0x55 }
formset
guid = BENI_FORMSET_GUID,
title = STRING_TOKEN(STR_PAGE_TITLE),
help = STRING_TOKEN(STR_EMPTY_STRING),
classguid = BENI_FORMSET_GUID,
endformset;
form
只有一個(gè)formset,此時(shí)什么也不會(huì)顯示出來(lái),還需要在里面加內(nèi)容,首先是一個(gè)form:
// {76B732B8-B777-4ECF-A84E-7A8CA2484555}
#define BENI_FORMSET_GUID { 0x76b732b8, 0xb777, 0x4ecf, 0xa8, 0x4e, 0x7a, 0x8c, 0xa2, 0x48, 0x45, 0x55 }
#define FRONT_PAGE_FORM_ID 0x1000
formset
guid = BENI_FORMSET_GUID,
title = STRING_TOKEN(STR_PAGE_TITLE_FORMSET),
help = STRING_TOKEN(STR_EMPTY_STRING),
classguid = BENI_FORMSET_GUID,
form
formid = FRONT_PAGE_FORM_ID,
title = STRING_TOKEN(STR_PAGE_TITLE_FORM);
endform;
endformset;
此時(shí)得到的結(jié)果:

標(biāo)題來(lái)自STR_PAGE_TITLE_FORM,而Esc=Exit是SendForm()自己生成的。
subtitle
之后就可以往form中添加內(nèi)容。首先增加一個(gè)靜態(tài)的字符串:
form
formid = FRONT_PAGE_FORM_ID,
title = STRING_TOKEN(STR_PAGE_TITLE_FORM);
subtitle text = STRING_TOKEN(STR_PAGE_STATIC_TEXT);
endform;
得到的結(jié)果:

可以看到SendForm()自己還生成了一個(gè)↑↓=Move Highlight。
oneof
然后增加選擇框(checkbox)并伴有變量,如下所示:
efivarstore BENI_SETUP_DATA,
attribute = 0x2, // EFI_VARIABLE_BOOTSERVICE_ACCESS
name = BeniSetupData,
guid = BENI_FORMSET_GUID;
form
formid = FRONT_PAGE_FORM_ID,
title = STRING_TOKEN(STR_PAGE_TITLE_FORM);
subtitle text = STRING_TOKEN(STR_PAGE_STATIC_TEXT);
oneof varid = BeniSetupData.Data1,
prompt = STRING_TOKEN(STR_SELECT_DATA_1_PROMPT),
help = STRING_TOKEN(STR_SELECT_DATA_1_HELP),
flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
option text = STRING_TOKEN(STR_SELECT_DATA_0), value = 0, flags = DEFAULT;
option text = STRING_TOKEN(STR_SELECT_DATA_1), value = 1, flags = 0;
endoneof;
oneof varid = BeniSetupData.Data2,
prompt = STRING_TOKEN(STR_SELECT_DATA_2_PROMPT),
help = STRING_TOKEN(STR_SELECT_DATA_2_HELP),
flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
option text = STRING_TOKEN(STR_SELECT_DATA_0), value = 0, flags = DEFAULT;
option text = STRING_TOKEN(STR_SELECT_DATA_1), value = 1, flags = 0;
endoneof;
endform;
對(duì)應(yīng)的變量結(jié)構(gòu)體:
//
// This is used in name of efivarstore.
//
#define BENI_SETUP_DATA_VAR_NAME L"BeniSetupData"
typedef struct {
UINT8 Data1;
UINT8 Data2;
UINT8 Rsvd1[2];
} BENI_SETUP_DATA;
顯示結(jié)果如下:

這里可以修改值,并且保存,但是因?yàn)楹蠖藳](méi)有代碼實(shí)現(xiàn),所以會(huì)報(bào)錯(cuò):

因此還需要增加后端的代碼,這主要包含幾個(gè)部分:變量的初始化,EFI_HII_CONFIG_ACCESS_PROTOCOL的實(shí)現(xiàn)和安裝。
這里首先初始化vfr中對(duì)應(yīng)的變量:
EFI_STATUS
PrepareData (
VOID
)
{
EFI_STATUS Status;
BENI_SETUP_DATA *Data;
UINTN DataSize;
Status = EFI_UNSUPPORTED;
Data = NULL;
DataSize = sizeof (BENI_SETUP_DATA);
Data = AllocateZeroPool (DataSize);
if (NULL == Data) {
DEBUG ((EFI_D_ERROR, "[BENI]%a %d Out of memory\n", __FUNCTION__, __LINE__));
return EFI_OUT_OF_RESOURCES;
}
Status = gRT->GetVariable (
BENI_SETUP_DATA_VAR_NAME,
&gBeniSetupFormSetGuid,
NULL,
&DataSize,
Data
);
if (EFI_ERROR (Status)) {
if (EFI_NOT_FOUND == Status) {
DEBUG ((EFI_D_ERROR, "[BENI]Initialize Setup data\n"));
Data->Data1 = 1;
Data->Data2 = 1;
DataSize = sizeof (BENI_SETUP_DATA);
Status = gRT->SetVariable (
BENI_SETUP_DATA_VAR_NAME,
&gBeniSetupFormSetGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
DataSize,
Data
);
DEBUG ((EFI_D_ERROR, "[BENI]Status: - %r\n", Status));
}
}
return Status;
}
這個(gè)本身意義不大,就是初始化和設(shè)置了一個(gè)變量而已,變量的值是1(所以顯示的不再是Zero,而是One),這在界面中也會(huì)體現(xiàn)出來(lái)。然后就是安裝EFI_HII_CONFIG_ACCESS_PROTOCOL:
mPrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
mPrivateData->ConfigAccess.RouteConfig = RouteConfig;
mPrivateData->ConfigAccess.Callback = DriverCallback;
//
// Publish sample formset.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&mPrivateData->DriverHandle,
&gEfiDevicePathProtocolGuid,
&mHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&mPrivateData->ConfigAccess,
NULL
);
這里的DriverCallback()等函數(shù)可以根據(jù)實(shí)際情況來(lái)實(shí)現(xiàn),目前只是增加了打印信息而已,在操作上述的選擇框時(shí)會(huì)被調(diào)用并輸出信息。
string
string是一個(gè)可編輯的字符串,編輯之后可以保存到變量,下面是一個(gè)示例:
string varid = BeniSetupData.DriverDescriptionData,
questionid = PAGE_DESCRIPTION_ID,
prompt = STRING_TOKEN(STR_STRING_DESC_PROMPT),
help = STRING_TOKEN(STR_STRING_HELPER),
flags = INTERACTIVE,
minsize = 6,
maxsize = 30,
endstring;
DriverDescriptionData是變量BeniSetupData的成員,它也可以預(yù)先初始化(本例中初始化成“Hello World”),PAGE_DESCRIPTION_ID可以在EFI_HII_CONFIG_ACCESS_PROTOCOL的Callback()中定位,此外還有一些幫助信息、大小和操作限制等等配置。
下面是顯示結(jié)果:

numeric
沒(méi)什么好說(shuō)的,就是數(shù)字:
numeric varid = BeniSetupData.Id,
prompt = STRING_TOKEN(STR_NUMERIC_ID_PROMPT),
help = STRING_TOKEN(STR_NUMERIC_ID_HELPER),
minimum = 0,
maximum = 1024,
endnumeric;
下面是顯示的結(jié)果:

跟string類(lèi)似,只不過(guò)只能輸入數(shù)字,通過(guò)flag的配置,可以選擇使用十進(jìn)制還是十六進(jìn)制。
text
跟subtitle不同的是,text可以被選中,下面是一個(gè)例子:
text
help = STRING_TOKEN(STR_TEXT_PROMPT),
text = STRING_TOKEN(STR_TEXT_HELPER),
flags = INTERACTIVE,
key = PAGE_TEXT_ID;
PAGE_TEXT_ID在EFI_HII_CONFIG_ACCESS_PROTOCOL的Callback()中使用:
EFI_STATUS
EFIAPI
DriverCallback (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
)
{
BENI_MODULE_START
if (Action == EFI_BROWSER_ACTION_CHANGING) {
switch (QuestionId) {
case PAGE_TEXT_ID:
DEBUG ((DEBUG_ERROR, "%a %d PAGE_TEXT_ID\n", __FUNCTION__, __LINE__));
break;
default:
break;
}
} else if (Action == EFI_BROWSER_ACTION_CHANGED) {
switch (QuestionId) {
case PAGE_TEXT_ID:
DEBUG ((DEBUG_ERROR, "%a %d PAGE_TEXT_ID\n", __FUNCTION__, __LINE__));
break;
default:
break;
}
}
BENI_MODULE_END
return EFI_SUCCESS;
}
顯示如下:

可以看到text那一行可以被選中,點(diǎn)擊之后可以看到打印信息:
[BENI]DriverCallback start... DriverCallback 138 PAGE_TEXT_ID [BENI]DriverCallback end... [BENI]DriverCallback start... DriverCallback 146 PAGE_TEXT_ID [BENI]DriverCallback end...
之所以能夠操作這一行,原始主要在于flags = INTERACTIVE,,這樣就會(huì)創(chuàng)建一個(gè)EFI_IFR_ACTION的操作碼,相當(dāng)于植入了一個(gè)可操作的動(dòng)作。
checkbox
勾選框,只有TRUE和FALSE,或者0和1兩個(gè)值。下面是一個(gè)示例:
grayoutif ideqval BeniSetupData.Disabled == 1;
text
help = STRING_TOKEN(STR_TEXT_PROMPT),
text = STRING_TOKEN(STR_TEXT_HELPER),
flags = INTERACTIVE,
key = PAGE_TEXT_ID;
endif;
checkbox varid = BeniSetupData.Disabled,
prompt = STRING_TOKEN(STR_CHECKBOXK_PROMPT),
help = STRING_TOKEN(STR_CHECKBOXK_HELPER),
flags = CHECKBOX_DEFAULT,
endcheckbox;
這里還使用了grayoutif,選中之后之前測(cè)試用的text會(huì)變灰,如下所示:

goto
用于跳轉(zhuǎn)到另外的界面:
goto PAGE_FORM_ID_2,
prompt = STRING_TOKEN(STR_GOTO_PROMPT),
help = STRING_TOKEN(STR_GOTO_HELPER);
endform;
form
formid = PAGE_FORM_ID_2,
title = STRING_TOKEN(STR_PAGE_TITLE_FORM_2);
subtitle text = STRING_TOKEN(STR_PAGE_NETX_PAGE);
endform;
顯示的結(jié)果:


label
label相當(dāng)于一個(gè)VFR中的一個(gè)占位符,本身不會(huì)產(chǎn)生可顯示的內(nèi)容,而是需要通過(guò)代碼動(dòng)態(tài)的增加顯示內(nèi)容,具體如何增加,就是使用之前介紹的HiiCreateXXX()函數(shù)在增加form組件。下面是label的示例:
#define LABEL_START 0x1004
#define LABEL_END 0x1005
form
formid = PAGE_FORM_ID_2,
title = STRING_TOKEN(STR_PAGE_TITLE_FORM_2);
subtitle text = STRING_TOKEN(STR_PAGE_NETX_PAGE);
subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
label LABEL_START;
label LABEL_END;
endform;
可以看到這里只是增加了兩個(gè)label而已,真正的操作還是在代碼中:
/**
Customize menus in the page.
@param[in] HiiHandle The HII Handle of the form to update.
@param[in] StartOpCodeHandle The context used to insert opcode.
@retval NA
**/
VOID
CustomizePage (
IN EFI_HII_HANDLE HiiHandle,
IN VOID *StartOpCodeHandle
)
{
//
// Add OpCode here.
//
HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_TEXT_IN_CODE), 0, 0, 0);
}
/**
Update components.
@param NA
@retval NA
**/
VOID
UpdatePageForm (
VOID
)
{
VOID *StartOpCodeHandle;
VOID *EndOpCodeHandle;
EFI_IFR_GUID_LABEL *StartGuidLabel;
EFI_IFR_GUID_LABEL *EndGuidLabel;
//
// Allocate space for creation of UpdateData Buffer
//
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (StartOpCodeHandle != NULL);
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (EndOpCodeHandle != NULL);
//
// Create Hii Extend Label OpCode as the start opcode
//
StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
StartGuidLabel->Number = LABEL_START;
//
// Create Hii Extend Label OpCode as the end opcode
//
EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
EndGuidLabel->Number = LABEL_END;
CustomizePage (
mPrivateData->SetupHiiHandle,
StartOpCodeHandle
);
HiiUpdateForm (
mPrivateData->SetupHiiHandle,
&gBeniSetupFormSetGuid,
PAGE_FORM_ID_2,
StartOpCodeHandle,
EndOpCodeHandle
);
return;
}
得到的結(jié)果如下,紅色部分就是通過(guò)代碼生成的:

以上就是UEFI開(kāi)發(fā)基礎(chǔ)HII代碼示例的詳細(xì)內(nèi)容,更多關(guān)于UEFI開(kāi)發(fā)HII代碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
匯編語(yǔ)言 跳轉(zhuǎn)指令與C語(yǔ)言的條件分支
這篇文章主要介紹了匯編語(yǔ)言 跳轉(zhuǎn)指令與C語(yǔ)言的條件分支,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼
這篇文章主要介紹了純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
Windows10下利用DOSBOX和MASM32搭建匯編語(yǔ)言開(kāi)發(fā)環(huán)境
這篇文章主要介紹了Windows10下利用DOSBOX和MASM32搭建匯編語(yǔ)言開(kāi)發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
一位數(shù)乘法的匯編語(yǔ)言實(shí)現(xiàn)方法
這篇文章主要介紹了一位數(shù)乘法的匯編語(yǔ)言實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02

