UEFI 界面实例解析

这篇文章主要记录一些setup界面的实例,这些实例都是EDK上的,我们可以看到如下图:

 上面三个为banner,下面的都是通过LABLE动态加载的,代码如下:

 我们可以看到 UiListThirdPartyDrivers (HiiHandle, &gEfiIfrFrontPageGuid, NULL, StartOpCodeHandle);这个函数,就是发现第三方的HII驱动然后给它放到FrontPage也就是主页当中,怎么发现,就是通过VFR中的classguid是不是gEfiIfrFrontPageGuid,这是重要依据,自己创建一个第三方驱动AnthonyPage,其中VFR:

, C文件中保留重要的函数就行,仿照其他第三方驱动,这些驱动以Library形式在DSC文件中被包入,这样就新增了一个页面,在DeviceManager页面,还有一种驱动,这种是独立的驱动

 在Devices List下有六个子项,这六个子项就是六个独立的驱动,以Browser Testcase Engine为例子,查看vfr:

 可以看到重点是EFI_HII_PLATFORM_SETUP_FORMSET_GUID,这个classguid和device manager这个页面是绑定的,在仿照这种驱动的时候,这个classguid必须是EFI_HII_PLATFORM_SETUP_FORMSET_GUID。

打开Browser Testcase Engine页面,一个一个分析:

 第一个:My subtitle text:

 title就是My First Setup Page,下面的就是My subtitle text和它的help,一个vfr只有一个formset,其他的就是formid,formid和LABLE同级。

第二个My CPU Speed is :

 第一个text就是左边的文字,第二个就是它的值,这种形式可以看到,它是可以选中但是不能改动的,因为没有key,不能执行action

Exit now!

 text
      help   = STRING_TOKEN(STR_EXIT_TEXT),
      text   = STRING_TOKEN(STR_EXIT_TEXT),
      flags  = INTERACTIVE,   // VfrCompiler will generate opcode EFI_IFR_ACTION for Text marked as INTERACTIVE
      key    = 0x1237;

INTERACTIVE,意味人机交互,也就是可以动作的,通过这个key去进行操作,这种形式选中后按Enter就是执行操作,先理解三个函数,ExtractConfig,导出配置,RouteConfig,存储配置,CallBack,操作Hii数据。执行操作在callback中:

case EFI_BROWSER_ACTION_CHANGED:
    switch (QuestionId) {
      case 0x1237:
        //
        // User press "Exit now", request Browser to exit
        //
        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
        break;

      case 0x1238:
        //
        // User press "Save now", request Browser to save the uncommitted data.
        //
        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
        break;

直接跳过到My one-of prompt #1,前面几个类似,不介绍了:

 //
    // Define oneof (EFI_IFR_ONE_OF)
    //
    oneof name = MyOneOf,                                // Define reference name for Question
      varid   = MyIfrNVData.SuppressGrayOutSomething,    // Use "DataStructure.Member" to reference Buffer Storage
      prompt  = STRING_TOKEN(STR_ONE_OF_PROMPT),
      help    = STRING_TOKEN(STR_ONE_OF_HELP),
      //
      // Define an option (EFI_IFR_ONE_OF_OPTION)
      //
      option text = STRING_TOKEN(STR_ONE_OF_TEXT4), value = 0x0, flags = 0;
      option text = STRING_TOKEN(STR_ONE_OF_TEXT5), value = 0x1, flags = 0;
      //
      // DEFAULT indicate this option will be marked with EFI_IFR_OPTION_DEFAULT
      //
      option text = STRING_TOKEN(STR_ONE_OF_TEXT6), value = 0x2, flags = DEFAULT;
    endoneof;

看代码,one-of也就是其中之一,这里有三个选项,分别是0:让checkbox隐藏,1:让checkbox不可选,2:让checkbox可选,我们尝试更改为Suppress the Checkbox,可以看到:

 下方的checkbox没有了,反而出现了一个Pick 1。这里主要说明不可选和隐藏的使用,

 grayoutif  ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1;
      suppressif questionref(MyOneOf) == 0x0;

        checkbox varid   = MyIfrNVData.ChooseToActivateNuclearWeaponry,
                 prompt   = STRING_TOKEN(STR_CHECK_BOX_PROMPT),
                 help     = STRING_TOKEN(STR_CHECK_BOX_HELP),
                 //
                 // CHECKBOX_DEFAULT indicate this checkbox is marked with EFI_IFR_CHECKBOX_DEFAULT
                 // CHECKBOX_DEFAULT_MFG indicate EFI_IFR_CHECKBOX_DEFAULT_MFG.
                 //
                 flags    = CHECKBOX_DEFAULT | CHECKBOX_DEFAULT_MFG,
                 default  = TRUE,
        endcheckbox;
      endif;
    endif;

第一句就是可选与不可选,ideqval只是判断,这句话可以这样理解,grayout  if true,如果是true就不可选,什么条件,也就是SuppressGrayOutSomething 的值为0x1;如果不加判断,直接不可选,那么可以这么写 grayoutif   TRUE;,别 grayoutif  ideqval TRUE,不然会报错。隐藏也是一样,MyOneof只是引用,给该变量取个别名一样,使用是一样的,只是需要加一个questionref。

标准的checkbox如上,简化的如下,需要先初始化变量:

 checkbox varid = MyIfrNVData.SerialPortStatus,
        prompt   = STRING_TOKEN(STR_SERIAL_PORT_STATUS),
        help     = STRING_TOKEN(STR_CHECK_BOX_HELP),
      endcheckbox;

 上图选项更改成LargeBootList,Boot Order会多显示USB选项,这个就是在最后一个USB选项加了个隐藏选项,也就是说隐藏和不可选也可以放在一个选项的内部。

然后再看一下Boot Order,它能显示多个选项,是因为使用了orderedlist,这里可以看到suppressif嵌入在中间:

 orderedlist
                varid       = MyIfrNVData.BootOrder,
                prompt      = STRING_TOKEN(STR_BOOT_OPTIONS),
                help        = STRING_TOKEN(STR_NULL_STRING),
                flags       = RESET_REQUIRED,
                option text = STRING_TOKEN(STR_BOOT_OPTION2), value = 2, flags = 0;
                option text = STRING_TOKEN(STR_BOOT_OPTION1), value = 1, flags = 0;
                option text = STRING_TOKEN(STR_BOOT_OPTION3), value = 3, flags = 0;
              suppressif ideqval MyIfrNVData.BootOrderLarge == 0;
                option text = STRING_TOKEN(STR_BOOT_OPTION4), value = 4, flags = 0;
              endif;
      endlist;

Goto Dynamic Page+:

 

说明这个页面是动态创建的,首先Goto Dynamic Page+这个选项需要显示:

 goto 0x1234,                                  // Destination Form ID
      prompt  = STRING_TOKEN(STR_GOTO_DYNAMIC),   // Prompt string
      help    = STRING_TOKEN(STR_GOTO_HELP),      // Help string
      flags   = INTERACTIVE,                      // INTERACTIVE indicate it's marked with EFI_IFR_FLAG_CALLBACK
      key     = 0x1234;                           // Question ID which will be passed-in in COnfigAccess.Callback()

进入这个goto,就到了另一个页面:

form formid = 0x1234,            // Dynamically created page,
       title = STRING_TOKEN(STR_DYNAMIC_TITLE);  // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code

    label LABEL_UPDATE1;
    //
    // This is where we will insert dynamic created opcodes
    //
    label LABEL_END;

  endform;
case EFI_BROWSER_ACTION_CHANGING:
  {
    switch (QuestionId) {
    case 0x1249:
      {
        if (Type != EFI_IFR_TYPE_REF) {
          return EFI_INVALID_PARAMETER;
        }

        Value->ref.FormId = 0x1234;
      }
    break;
    case 0x1234:
      //
      // Initialize the container for dynamic opcodes
      //
      StartOpCodeHandle = HiiAllocateOpCodeHandle ();
      ASSERT (StartOpCodeHandle != NULL);

      EndOpCodeHandle = HiiAllocateOpCodeHandle ();
      ASSERT (EndOpCodeHandle != NULL);

      //
      // Create Hii Extend Label OpCode as the start opcode
      //
      StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
      StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
      StartLabel->Number       = LABEL_UPDATE1;

      //
      // Create Hii Extend Label OpCode as the end opcode
      //
      EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
      EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
      EndLabel->Number       = LABEL_END;

      HiiCreateActionOpCode (
        StartOpCodeHandle,                // Container for dynamic created opcodes
        0x1237,                           // Question ID
        STRING_TOKEN(STR_EXIT_TEXT),      // Prompt text
        STRING_TOKEN(STR_EXIT_TEXT),      // Help text
        EFI_IFR_FLAG_CALLBACK,            // Question flag
        0                                 // Action String ID
      );

      //
      // Create Option OpCode
      //
      OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
      ASSERT (OptionsOpCodeHandle != NULL);

      HiiCreateOneOfOptionOpCode (
        OptionsOpCodeHandle,
        STRING_TOKEN (STR_BOOT_OPTION1),
        0,
        EFI_IFR_NUMERIC_SIZE_1,
        1
        );

      HiiCreateOneOfOptionOpCode (
        OptionsOpCodeHandle,
        STRING_TOKEN (STR_BOOT_OPTION2),
        0,
        EFI_IFR_NUMERIC_SIZE_1,
        2
        );

      //
      // Prepare initial value for the dynamic created oneof Question
      //
      PrivateData->Configuration.DynamicOneof = 2;
      Status = gRT->SetVariable(
                      VariableName,
                      &gDriverSampleFormSetGuid,
                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
                      sizeof (DRIVER_SAMPLE_CONFIGURATION),
                      &PrivateData->Configuration
                      );

      //
      // Set initial vlaue of dynamic created oneof Question in Form Browser
      //
      Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_CONFIGURATION));
      ASSERT (Configuration != NULL);
      if (HiiGetBrowserData (&gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration)) {
        Configuration->DynamicOneof = 2;

        //
        // Update uncommitted data of Browser
        //
        HiiSetBrowserData (
          &gDriverSampleFormSetGuid,
          VariableName,
          sizeof (DRIVER_SAMPLE_CONFIGURATION),
          (UINT8 *) Configuration,
          NULL
          );
      }
      FreePool (Configuration);

      HiiCreateOneOfOpCode (
        StartOpCodeHandle,                         // Container for dynamic created opcodes
        0x8001,                                    // Question ID (or call it "key")
        CONFIGURATION_VARSTORE_ID,                 // VarStore ID
        (UINT16) DYNAMIC_ONE_OF_VAR_OFFSET,        // Offset in Buffer Storage
        STRING_TOKEN (STR_ONE_OF_PROMPT),          // Question prompt text
        STRING_TOKEN (STR_ONE_OF_HELP),            // Question help text
        EFI_IFR_FLAG_CALLBACK,                     // Question flag
        EFI_IFR_NUMERIC_SIZE_1,                    // Data type of Question Value
        OptionsOpCodeHandle,                       // Option Opcode list
        NULL                                       // Default Opcode is NULl
        );

这里只简单贴下代码,主要说下几个重要函数:

HiiCreateOneOfOptionOpCode用于创建一种选项(Option)。它用于定义在系统配置界面中的单选或多选菜单中的一个选项。

HiiCreateActionOpCode该操作码用于创建一个与用户界面交互的动作。动作可以是按下按钮、选择复选框、拖动滑块等用户交互事件。

HiiCreateDateOpCode该操作码用于创建一个与日期相关的控件或选项。

HiiCreateTimeOpCode操作码用于创建一个与时间相关的控件或选项。

HiiCreateGotoOpCode用于创建跳转操作。

 numeric varid  = MyIfrNVData.QuestionNonXUefiKeywordRestStyle,
      prompt       = STRING_TOKEN(STR_ONE_OF_PROMPT_NON_X_UEFI),
      help         = STRING_TOKEN(STR_ONE_OF_PROMPT_NON_X_UEFI_HELP),
      flags        = RESET_REQUIRED | REST_STYLE,
      minimum      = 0,
      maximum      = 0xf0,
      step         = 0,          // Stepping of 0 equates to a manual entering
                                 // of a value, otherwise it will be adjusted by "+"/"-"
      default      = 0,          // defaultstore could be used to specify the default type
                                 // If no defaultstore is specified, it implies Standard Default
    endnumeric;

 这里flags也可以是flags   = READ_ONLY, 如果是这种表明可见但不可选。

 //
    // Define a string (EFI_IFR_STRING)
    //
    string    varid    = MyIfrNVData.MyStringData,
              prompt   = STRING_TOKEN(STR_MY_STRING_PROMPT2),
              help     = STRING_TOKEN(STR_MY_STRING_HELP2),
              flags    = INTERACTIVE,
              key      = 0x1236,
              minsize  = 6,
              maxsize  = 40,
              inconsistentif prompt = STRING_TOKEN(STR_STRING_CHECK_ERROR_POPUP),
                pushthis != stringref(STRING_TOKEN(STR_STRING_CHECK))
              endif;
    endstring;

 作用不明,在vfr中maxsize下有两句,第一句的意思是没输入对会弹窗报错,第二行也就是右侧的值是否等于STR_STRING_CHECK。

最后分析一下,怎么跳转到另一个页面:

 这个页面在DeviceManager中,是和该同级页面在同一个驱动中生成的,因此可以直接通过GUID去指向:

goto
      formsetguid = DRIVER_SAMPLE_INVENTORY_GUID,
      formid  = 0x1,
      question = 0x1,
      prompt  = STRING_TOKEN(STR_GOTO_ANOTHER_FORMSET),
      help    = STRING_TOKEN(STR_GOTO_ANOTHER_FORMSET_HELP);

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值