UEFI開發(fā)基礎(chǔ)HII代碼示例
代碼示例
代碼 https://gitee.com/jiangwei0512/edk2-beni
模塊
BeniPkg\DynamicCommand\SetupDynamicCommand\SetupDynamicCommand.inf。
這里通過一個(gè)命令setup來打開圖形界面。圖形界面的form在Page.vfr中,還有若干的uni文件存放字符串,并通過如下的代碼來初始化:
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)制中的方式。然后通過如下的代碼來顯示圖形:
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
一開始使用的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ì)顯示出來,還需要在里面加內(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)題來自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)楹蠖藳]有代碼實(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)出來。然后就是安裝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í)際情況來實(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
沒什么好說的,就是數(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類似,只不過只能輸入數(shù)字,通過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)容,而是需要通過代碼動(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é)果如下,紅色部分就是通過代碼生成的:
以上就是UEFI開發(fā)基礎(chǔ)HII代碼示例的詳細(xì)內(nèi)容,更多關(guān)于UEFI開發(fā)HII代碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
匯編語(yǔ)言:比較指令、跳轉(zhuǎn)指令、JCC的使用
這篇文章主要介紹了匯編語(yǔ)言:比較指令、跳轉(zhuǎn)指令、JCC的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Windows10下利用DOSBOX和MASM32搭建匯編語(yǔ)言開發(fā)環(huán)境
這篇文章主要介紹了Windows10下利用DOSBOX和MASM32搭建匯編語(yǔ)言開發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01iOS匯編入門教程之在Xcode工程中嵌入?yún)R編代碼的方法
在Xcode中嵌入?yún)R編代碼主要依賴了C語(yǔ)言支持通過 __asm__ 引入?yún)R編代碼的功能。這篇文章主要介紹了iOS匯編入門教程之在Xcode工程中嵌入?yún)R編代碼的方法,需要的朋友可以參考下2020-02-02UEFI開發(fā)實(shí)戰(zhàn)SlimBootloader中調(diào)用FSP
這篇文章主要為大家介紹了UEFI開發(fā)實(shí)戰(zhàn)SlimBootloader中調(diào)用FSP基礎(chǔ)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06匯編語(yǔ)言 and和or邏輯運(yùn)算指令的實(shí)現(xiàn)
這篇文章主要介紹了匯編語(yǔ)言 and,or邏輯運(yùn)算指令的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01匯編語(yǔ)言MUL指令無符號(hào)數(shù)乘法的使用
這篇文章主要介紹了匯編語(yǔ)言MUL指令無符號(hào)數(shù)乘法的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02