溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

發(fā)布時間:2022-06-06 13:52:20 來源:億速云 閱讀:579 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“UEFI開發(fā)基礎(chǔ)HII代碼實例分析”,在日常操作中,相信很多人在UEFI開發(fā)基礎(chǔ)HII代碼實例分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”UEFI開發(fā)基礎(chǔ)HII代碼實例分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

模塊

BeniPkg\DynamicCommand\SetupDynamicCommand\SetupDynamicCommand.inf。

這里通過一個命令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;
}

這里使用了將資源放到二進制中的方式。然后通過如下的代碼來顯示圖形:

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

只有一個formset,此時什么也不會顯示出來,還需要在里面加內(nèi)容,首先是一個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;

此時得到的結(jié)果:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

標題來自STR_PAGE_TITLE_FORM,而Esc=ExitSendForm()自己生成的。

subtitle

之后就可以往form中添加內(nèi)容。首先增加一個靜態(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é)果:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

可以看到SendForm()自己還生成了一個↑↓=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;

對應(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é)果如下:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

這里可以修改值,并且保存,但是因為后端沒有代碼實現(xiàn),所以會報錯:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

因此還需要增加后端的代碼,這主要包含幾個部分:變量的初始化,EFI_HII_CONFIG_ACCESS_PROTOCOL的實現(xiàn)和安裝。

這里首先初始化vfr中對應(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;
}

這個本身意義不大,就是初始化和設(shè)置了一個變量而已,變量的值是1(所以顯示的不再是Zero,而是One),這在界面中也會體現(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ù)實際情況來實現(xiàn),目前只是增加了打印信息而已,在操作上述的選擇框時會被調(diào)用并輸出信息。

string

string是一個可編輯的字符串,編輯之后可以保存到變量,下面是一個示例:

    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的成員,它也可以預先初始化(本例中初始化成“Hello World”),PAGE_DESCRIPTION_ID可以在EFI_HII_CONFIG_ACCESS_PROTOCOLCallback()中定位,此外還有一些幫助信息、大小和操作限制等等配置。

下面是顯示結(jié)果:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

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é)果:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

跟string類似,只不過只能輸入數(shù)字,通過flag的配置,可以選擇使用十進制還是十六進制。

text

跟subtitle不同的是,text可以被選中,下面是一個例子:

    text
      help   = STRING_TOKEN(STR_TEXT_PROMPT),
      text   = STRING_TOKEN(STR_TEXT_HELPER),
      flags  = INTERACTIVE,
      key    = PAGE_TEXT_ID;

PAGE_TEXT_IDEFI_HII_CONFIG_ACCESS_PROTOCOLCallback()中使用:

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;
}

顯示如下:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

可以看到text那一行可以被選中,點擊之后可以看到打印信息:

[BENI]DriverCallback start...
DriverCallback 138 PAGE_TEXT_ID
[BENI]DriverCallback end...
[BENI]DriverCallback start...
DriverCallback 146 PAGE_TEXT_ID
[BENI]DriverCallback end...

之所以能夠操作這一行,原始主要在于flags = INTERACTIVE,,這樣就會創(chuàng)建一個EFI_IFR_ACTION的操作碼,相當于植入了一個可操作的動作。

checkbox

勾選框,只有TRUE和FALSE,或者0和1兩個值。下面是一個示例:

    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,選中之后之前測試用的text會變灰,如下所示:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

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é)果:

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

UEFI開發(fā)基礎(chǔ)HII代碼實例分析

label

label相當于一個VFR中的一個占位符,本身不會產(chǎn)生可顯示的內(nèi)容,而是需要通過代碼動態(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;

可以看到這里只是增加了兩個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代碼實例分析

到此,關(guān)于“UEFI開發(fā)基礎(chǔ)HII代碼實例分析”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI