UEFI开发基础HII代码示例

目录
  • 代码示例
    • 模块
    • formset
    • form
    • subtitle
    • oneof
    • string
    • numeric
    • text
    • checkbox
    • goto
    • label

代码示例

代码 https://gitee.com/jiangwei0512/edk2-beni

模块

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文件内容:

// {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,此时什么也不会显示出来,还需要在里面加内容,首先是一个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;

此时得到的结果:

标题来自STR_PAGE_TITLE_FORM,而Esc=ExitSendForm()自己生成的。

subtitle

之后就可以往form中添加内容。首先增加一个静态的字符串:

  form
    formid  = FRONT_PAGE_FORM_ID,
    title   = STRING_TOKEN(STR_PAGE_TITLE_FORM);

    subtitle text = STRING_TOKEN(STR_PAGE_STATIC_TEXT);

  endform;

得到的结果:

可以看到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;

对应的变量结构体:

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

显示结果如下:

这里可以修改值,并且保存,但是因为后端没有代码实现,所以会报错:

因此还需要增加后端的代码,这主要包含几个部分:变量的初始化,EFI_HII_CONFIG_ACCESS_PROTOCOL的实现和安装。

这里首先初始化vfr中对应的变量:

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

这个本身意义不大,就是初始化和设置了一个变量而已,变量的值是1(所以显示的不再是Zero,而是One),这在界面中也会体现出来。然后就是安装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()等函数可以根据实际情况来实现,目前只是增加了打印信息而已,在操作上述的选择框时会被调用并输出信息。

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()中定位,此外还有一些帮助信息、大小和操作限制等等配置。

下面是显示结果:

numeric

没什么好说的,就是数字:

    numeric varid   = BeniSetupData.Id,
            prompt  = STRING_TOKEN(STR_NUMERIC_ID_PROMPT),
            help    = STRING_TOKEN(STR_NUMERIC_ID_HELPER),
            minimum = 0,
            maximum = 1024,
    endnumeric;

下面是显示的结果:

跟string类似,只不过只能输入数字,通过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;
}

显示如下:

可以看到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,,这样就会创建一个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会变灰,如下所示:

goto

用于跳转到另外的界面:

    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;

显示的结果:

label

label相当于一个VFR中的一个占位符,本身不会产生可显示的内容,而是需要通过代码动态的增加显示内容,具体如何增加,就是使用之前介绍的HiiCreateXXX()函数在增加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;
}

得到的结果如下,红色部分就是通过代码生成的:

以上就是UEFI开发基础HII代码示例的详细内容,更多关于UEFI开发HII代码的资料请关注我们其它相关文章!

(0)

相关推荐

  • UEFI开发基础汇编代码的使用

    UEFI中使用汇编代码 EDK代码中包含一部分汇编代码,目前支持的有.S..asm和.nasm格式的汇编(第一个是AT&T汇编,后两个是Intel汇编,只是使用的汇编样式稍有不同,.nasm是开源和免费的,更加的通用),如果是在Windows下编译,一般使用的是NASM编译器,所以会使用.nasm格式的汇编文件,而编译工具也是免费的,可以在https://www.nasm.us/下载,并放到C:\Nasm目录,之后就可以在EDK代码中使用. 下面是一个示例,它是一个库模块: 首先创建inf文件:

  • UEFI开发基础HII代码示例

    目录 代码示例 模块 formset form subtitle oneof string numeric text checkbox goto label 代码示例 代码 https://gitee.com/jiangwei0512/edk2-beni 模块 BeniPkg\DynamicCommand\SetupDynamicCommand\SetupDynamicCommand.inf. 这里通过一个命令setup来打开图形界面.图形界面的form在Page.vfr中,还有若干的uni文件

  • UEFI开发实战用户交互界面基础说明

    目录 前言 启动 UiApp模块 字体 字符串 UI Entry 前言 本文以vUDK2017: https://github.com/tianocore/edk2.git Tag vUDK2017.中的代码为例说明UEFI用户交互界面的实现. 这里UEFI用户交互界面的实现载体是OVMF(使用QEMU启动),其形式如下: 它一般被叫做Front Page(后面将以该名称来称呼上述的界面),其下还包括Setup,Boot Manager,Device Manager等选项. 相比Legacy B

  • 鸿蒙开发之Button按钮类型及如何通过代码设置(HarmonyOS鸿蒙开发基础知识)

    AbilitySlice 是什么 (HarmonyOS鸿蒙开发基础知识) AbilitySlice 是什么 AbilitySlice主要用于承载Ability的具体逻辑实现和界面UI,是应用显示.运行和跳转的最小单元.AbilitySlice通过setUIContent()为界面设置布局 本文重点给大家介绍鸿蒙开发之Button按钮类型及如何通过代码设置(HarmonyOS鸿蒙开发基础知识),具体内容如下所示: Button类型分类 按照按钮的形状,按钮可以分为: 普通按钮 椭圆按钮 胶囊按钮

  • Scala基础简介及代码示例

    一.主要内容 Scala中变量的声明与函数定义 Scala中的控制结构 Scala中的数据类型 1:变量声明与函数定义 变量声明:val 和 var ,两者的区别是val声明的变量是不可变的,而var声明的变量可变 带返回值 scala> def max(x:Int,y:Int):Int = { | if(x>y) x | else y | } max: (x: Int, y: Int)Int scala> max(1,2) res5: Int = 2 不带返回值 scala> d

  • 快速了解Python开发中的cookie及简单代码示例

    cookie :是用户保存在用户浏览器端的一对键值对,是为了解决http的无状态连接.服务端是可以把 cookie写到用户浏览器上,用户每次发请求会携带cookie. 存放位置: 每次发请求cookie是放在请求头里面的. 应用场景: ·登陆用户和密码的记住密码 ·显示每页显示的数据,以后都是按照设定的数目显示 ·投票机制 案例用户登录 创建用户登录的url url(r'^login/', views.login), 创建登录页面 代码为: <!DOCTYPE html> <html l

  • Sublime开发python程序的示例代码

    本文介绍了Sublime开发python程序的示例代码,分享给大家,具体如下: 下载.安装Python程序 https://www.python.org/downloads/ 下载.安装 sublime http://www.sublimetext.com/ 关联python Preferences->Browers Packages ->Python ->Python.sublime-build 修改Python.sublime-build文件,增加python安装路径 { "

  • Java开发基础日期类代码详解

    由于工作关系,很久没更新博客了,今天就给大家带来一篇Java实现获取指定月份的星期与日期对应关系的文章,好了,不多说,我们直接上代码: 一.日期工具类 package com.lyz.date; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.u

  • UEFI开发实战用户交互界面使用说明VFR文件

    目录 1. 综述 2. 作用 3. 语法 3.1 注释 3.2 预定义 3.3 数据结构 3.4 Forms相关表达式总览 3.4.1 formset 3.4.2 formset list 3.5 Form Set List 3.5.1 变量定义 3.5.2 控制语句 3.5.3 Question语句 3.5.4 form语句 3.6 Forms表达式 3.6.1 vfrStatementImage 3.6.2 vfrStatementLocked 3.6.3 vfrStatementRules

  • UEFI开发实战用户交互界面使用说明UNI文件

    综述 UEFI用户交互界面的实现涉及到多种不同类型的文件,这里要讲的是UNI文件,它也是其中最简单的一种.本文主要参考自<edk-ii-uni-specification.pdf>(以下简称参考文档).它可以在EDK II Specifications · tianocore/tianocore.github.io Wiki · GitHub下载到.文本的代码示例来自EDK2017,由于版本更新等原因,示例中的代码可能跟实际GIT库中的代码有一定的差异. 作用 关于UNI文件的作用,在参考文档

随机推荐