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

 更新时间:2022年06月06日 11:56:19   作者:jiangwei0512  
这篇文章主要为大家介绍了UEFI开发实战用户交互界面的基础说明,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

本文以vUDK2017: https://github.com/tianocore/edk2.git Tag vUDK2017.中的代码为例说明UEFI用户交互界面的实现。

这里UEFI用户交互界面的实现载体是OVMF(使用QEMU启动),其形式如下:

它一般被叫做Front Page(后面将以该名称来称呼上述的界面),其下还包括Setup,Boot Manager,Device Manager等选项。

相比Legacy BIOS,UEFI的交互界面要丰富得多,比如支持多语言,支持图片等,不过EDK默认带的还是最原始的,跟Legacy BIOS类似的界面。

本文讨论的就是该界面的实现。

启动

在EDK2017的OVMF代码中,Front Page被做成一个独立的APP(跟Shell一样),然后注册,可以通过在启动过程中按F2来进入,具体的注册代码如下:

VOID
PlatformRegisterOptionsAndKeys (
  VOID
  )
{
  EFI_STATUS                   Status;
  EFI_INPUT_KEY                Enter;
  EFI_INPUT_KEY                F2;
  EFI_INPUT_KEY                Esc;
  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
  //
  // Register ENTER as CONTINUE key
  //
  Enter.ScanCode    = SCAN_NULL;
  Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
  Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
  ASSERT_EFI_ERROR (Status);
  //
  // Map F2 to Boot Manager Menu
  //
  F2.ScanCode     = SCAN_F2;
  F2.UnicodeChar  = CHAR_NULL;
  Esc.ScanCode    = SCAN_ESC;
  Esc.UnicodeChar = CHAR_NULL;
  Status = EfiBootManagerGetBootManagerMenu (&BootOption);
  ASSERT_EFI_ERROR (Status);
  Status = EfiBootManagerAddKeyOptionVariable (
             NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
             );
  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
  Status = EfiBootManagerAddKeyOptionVariable (
             NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
             );
  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
}

而Front Page对应APP的驱动是UiApp.inf,它对应的GUID是:

  # Point to the MdeModulePkg/Application/UiApp/UiApp.inf
  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }

在EfiBootManagerGetBootManagerMenu()函数中会根据上述的GUID寻找UiApp模块,并生成对应的启动项。

最终的结果就是启动过程中按F2就可以进入UiApp模块,其入口是InitializeUserInterface(),将在后续的内容中介绍。

UiApp模块

InitializeUserInterface()模块的大致流程如下:

其中绿色部分涉及到交互相关的操作,后续会重点说明。

字体

字体使用一种称为Glyph的元素表示,它其实就是一个二进制的文件,里面包含了描述字体的元素,但是具体是怎么样表示的,目前还不是很清楚,这个也不是我们需要关注的重点。

这个二进制在代码中有下述的数组表示:

typedef struct {
  ///
  /// This 4-bytes total array length is required by HiiAddPackages()
  ///
  UINT32                 Length;
  //
  // This is the Font package definition
  //
  EFI_HII_PACKAGE_HEADER Header;
  UINT16                 NumberOfNarrowGlyphs;
  UINT16                 NumberOfWideGlyphs;
  EFI_NARROW_GLYPH       NarrowArray[NARROW_GLYPH_NUMBER];
  EFI_WIDE_GLYPH         WideArray[WIDE_GLYPH_NUMBER];
} FONT_PACK_BIN;
FONT_PACK_BIN mFontBin = {
  sizeof (FONT_PACK_BIN),
  {
    sizeof (FONT_PACK_BIN) - sizeof (UINT32),
    EFI_HII_PACKAGE_SIMPLE_FONTS,
  },
  NARROW_GLYPH_NUMBER,
  0,
  {     // Narrow Glyphs
    {
      0x05d0,
      0x00,
      {
        0x00,  // 后面的省略

这个数组通过一个通过HiiAddPackages()导入,如下所示:

/**
  Routine to export glyphs to the HII database.  
  This is in addition to whatever is defined in the Graphics Console driver.
**/
EFI_HII_HANDLE
ExportFonts (
  VOID
  )
{
  return HiiAddPackages (
           &mFontPackageGuid,
           gImageHandle,
           &mFontBin,
           NULL
           );
}

字符串

字符串通过UNI文件转换成,编译时在AutoGen.c中生成对应的数组,然后通过下面的函数来注册到HII数据库中:

/**
  Initialize HII global accessor for string support.
**/
VOID
InitializeStringSupport (
  VOID
  )
{
  gStringPackHandle = HiiAddPackages (
                         &mUiStringPackGuid,
                         gImageHandle,
                         UiAppStrings,
                         NULL
                         );
  ASSERT (gStringPackHandle != NULL);
}

这里的UiAppStrings就是通过.uni文件生成的字符串表示。

可以看到,导入字体和字符串使用的是相同的函数。

UI Entry

进入UI界面是通过UiEntry()来实现的,其大致流程如下:

这里的重点也主要在绿色部分,它包含了Front Page的初始化和调用。

上述的绿色部分大致流程如下所示:

这里最重要的是两个部分,一个是更新Front Page的部分,另一个是SendForm()的部分。

更新Front Page部分主要由UpdateFrontPageBannerStrings()、UpdateFrontPageForm()等函数组成,它们使用了各类HII操作来更新界面,比如说UiCustomizeFrontPageBanner()构成了Front Page界面中的一条条的字符串显示(就是开头图片中的蓝字部分),另外还有UiCustomizeFrontPage()、HiiUpdateForm()等函数,都更新了界面。

SendForm()部分,它其实是整个UEFI界面显示的引擎,这部分实现在显示界面(比如图形输出界面,或者串口)上显示前面更新的内容,后续会详细介绍。

本文只是简单的介绍,以上就是UEFI开发实战用户交互界面基础说明的详细内容,更多关于UEFI用户交互界面的资料请关注脚本之家其它相关文章!

相关文章

  • 汇编语言 and和or逻辑运算指令的实现

    汇编语言 and和or逻辑运算指令的实现

    这篇文章主要介绍了汇编语言 and,or逻辑运算指令的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • 汇编程序设计之DOSBox模拟环境配置

    汇编程序设计之DOSBox模拟环境配置

    最近在学习汇编语言设计,然后上网找关于汇编程序的编译软件,不负有心人,终于找到了我需要的软件,值得庆幸
    2023-08-08
  • 汇编语言中test和cmp有什么区别

    汇编语言中test和cmp有什么区别

    汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。这篇文章主要介绍了汇编语言中test和cmp有什么区别,需要的朋友可以参考下
    2020-01-01
  • 使用汇编实现字符串的大小写转换

    使用汇编实现字符串的大小写转换

    这篇文章主要介绍了使用汇编实现字符串的大小写转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • UEFI开发实战用户交互界面基础说明

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

    这篇文章主要为大家介绍了UEFI开发实战用户交互界面的基础说明,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • 汇编语言指令大全 X86和X87汇编指令大全(带注释)

    汇编语言指令大全 X86和X87汇编指令大全(带注释)

    汇编指令集太多,如果不用就会忘记,所以将i处理器官方的指令集大全写到博客上,有需要的人可以参考一下
    2021-10-10
  • 汇编语言学习assume的作用详解

    汇编语言学习assume的作用详解

    这篇文章主要为大家介绍了汇编语言学习assume的作用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2021-11-11
  • 汇编语言中mov和lea指令的区别详解

    汇编语言中mov和lea指令的区别详解

    指令(instruction)是一种语句,它在程序汇编编译时变得可执行。本文给大家总结一下汇编语言中mov和lea指令的区别详解,感兴趣的朋友跟随小编一起看看吧
    2020-01-01
  • 汇编语言中的segment

    汇编语言中的segment

    segment是段的意思,是段定义伪指令,一个正常的应用程序被由若干个 segment组成,接下来通过本文给大家介绍汇编语言中的segment,需要的朋友可以参考下
    2020-01-01
  • 汇编:Debug的常用命令

    汇编:Debug的常用命令

    DEBUG是专门为汇编语言设计的一种调试工具,它通过步进,设置断点等方式为汇编语言程序员提供了非常有效的调试手段
    2023-08-08

最新评论