UEFI HII本地化:EDK II中多语言支持实现方法

UEFI HII本地化:EDK II中多语言支持实现方法

【免费下载链接】edk2 EDK II 【免费下载链接】edk2 项目地址: https://gitcode.com/gh_mirrors/ed/edk2

引言

你是否在开发UEFI(Unified Extensible Firmware Interface,统一可扩展固件接口)应用时,为多语言支持而烦恼?是否希望你的BIOS设置界面能够无缝切换中英文、法语等多种语言?本文将深入解析EDK II(EFI Development Kit II)中HII(Human Interface Infrastructure,人机交互基础设施)本地化技术,通过实例演示如何实现UEFI应用的多语言支持。读完本文,你将掌握从配置文件编写到代码集成的完整流程,轻松构建支持全球用户的UEFI应用。

HII本地化核心概念

HII概述

HII是UEFI规范定义的人机交互框架,提供了表单(Form)、字符串(String)、字体(Font)等用户界面元素的标准化管理方式。其核心优势在于将界面逻辑与具体实现分离,支持通过配置文件而非硬编码实现多语言切换。

本地化关键组件

EDK II中实现HII本地化需要三个关键文件类型:

  1. .uni文件:存储多语言字符串资源,采用键值对结构,支持按语言标签区分不同翻译版本
  2. .vfr文件:定义表单布局和用户界面元素,通过字符串令牌(Token)引用.uni文件中的多语言文本
  3. C源代码文件:实现HII配置协议(EFI_HII_CONFIG_ACCESS_PROTOCOL),处理用户交互和配置数据存储

三者关系如下:

mermaid

多语言支持实现步骤

步骤1:创建.uni字符串文件

.uni文件采用特殊格式定义多语言字符串,基本语法如下:

#string <字符串ID>  #language <语言代码> "<翻译文本>"

VfrStrings.uni为例,定义支持英文和法语的字符串:

#langdef en-US  "English"
#langdef fr-FR  "Francais"

#string STR_FORM_SET_TITLE             #language en-US "Browser Testcase Engine"
                                       #language fr-FR "Browser Testcase Engine"
#string STR_ONE_OF_PROMPT_X_UEFI       #language en-US "x-UEFI HII Option"
                                       #language fr-FR "x-UEFI HII Option"
#string STR_ONE_OF_PROMPT_NON_X_UEFI   #language en-US "Non x-UEFI HII Option"
                                       #language fr-FR "Non x-UEFI HII Option"

最佳实践:为每个功能模块创建独立的.uni文件(如DriverSample.uniNetworkConfig.uni),避免单个文件过大难以维护

步骤2:编写.vfr表单定义文件

.vfr文件通过字符串令牌引用.uni文件中的多语言文本,关键语法如下:

formset
  guid      = DRIVER_SAMPLE_FORMSET_GUID,
  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
  
  varstore DRIVER_SAMPLE_CONFIGURATION,
    varid = CONFIGURATION_VARSTORE_ID,
    name  = MyIfrNVData,
    guid  = DRIVER_SAMPLE_FORMSET_GUID;
  
  form formid = 1, title = STRING_TOKEN(STR_FORM1_TITLE);
    oneof varid  = MyIfrNVData.QuestionXUefiKeywordRestStyle,
      prompt      = STRING_TOKEN(STR_ONE_OF_PROMPT_X_UEFI),
      help        = STRING_TOKEN(STR_ONE_OF_PROMPT_X_UEFI_HELP),
      flags       = RESET_REQUIRED | REST_STYLE,
      option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = 0;
      option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = DEFAULT;
    endoneof;
  endform;
endformset;

注意:所有字符串引用必须使用STRING_TOKEN()宏包装,EDK II构建系统会自动处理令牌解析和字符串表生成

步骤3:实现HII配置协议

在C源代码中,需要实现HII配置协议以连接表单定义和实际功能:

EFI_STATUS
EFIAPI
DriverSampleConfigAccessCallback (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
  IN  EFI_HII_CONFIGURATION_ACTION          Action,
  IN  EFI_STRING                            ConfigRequest,
  IN  EFI_STRING                            ConfigResponse,
  IN  UINTN                                 Progress,
  OUT EFI_STRING                            Results
  )
{
  // 处理配置数据加载和保存
  switch (Action) {
    case EFI_HII_CONFIGURATION_ACTION_EXTRACT:
      // 从NVRAM加载配置数据
      break;
    case EFI_HII_CONFIGURATION_ACTION_APPLY:
      // 将配置数据保存到NVRAM
      break;
  }
  return EFI_SUCCESS;
}

// 协议实例
EFI_HII_CONFIG_ACCESS_PROTOCOL mDriverSampleConfigAccess = {
  DriverSampleExtractConfig,
  DriverSampleRouteConfig,
  DriverSampleConfigAccessCallback
};

步骤4:注册HII数据包

在驱动入口函数中,需要将表单和字符串资源注册到HII数据库:

EFI_STATUS
EFIAPI
DriverSampleEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS status;
  EFI_HII_HANDLE hiiHandle;
  
  // 加载VFR表单和UNI字符串
  hiiHandle = HiiAddPackages (
                &gDriverSampleFormSetGuid,
                ImageHandle,
                DriverSampleVfrBin,    // 编译后的VFR二进制数据
                DriverSampleStrings,   // 编译后的UNI字符串数据
                NULL
                );
  if (hiiHandle == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  
  // 安装HII配置访问协议
  status = gBS->InstallProtocolInterface (
                  &ImageHandle,
                  &gEfiHiiConfigAccessProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &mDriverSampleConfigAccess
                  );
  
  return status;
}

高级应用:动态语言切换

运行时语言检测

EDK II提供HiiGetSupportedLanguages()函数获取系统支持的语言列表,示例代码:

EFI_STATUS
GetSupportedLanguages (
  OUT CHAR8  **LanguagesBuffer,
  OUT UINTN  *LanguagesSize
  )
{
  EFI_HII_PROTOCOL *HiiProtocol;
  EFI_STATUS status;
  
  // 获取HII协议
  status = gBS->LocateProtocol (
                  &gEfiHiiProtocolGuid,
                  NULL,
                  (VOID **)&HiiProtocol
                  );
  if (EFI_ERROR(status)) return status;
  
  // 获取支持的语言列表
  return HiiProtocol->GetSupportedLanguages (
                        HiiProtocol,
                        LanguagesBuffer,
                        LanguagesSize
                        );
}

字符串动态加载

通过HiiGetString()函数可根据语言代码动态获取对应翻译:

EFI_STATUS
GetLocalizedString (
  IN  EFI_HII_HANDLE  HiiHandle,
  IN  EFI_STRING_ID   StringId,
  IN  CHAR8           *Language,
  OUT EFI_STRING      *String
  )
{
  EFI_HII_STRING_PROTOCOL *HiiString;
  EFI_STATUS status;
  
  status = gBS->LocateProtocol (
                  &gEfiHiiStringProtocolGuid,
                  NULL,
                  (VOID **)&HiiString
                  );
  if (EFI_ERROR(status)) return status;
  
  return HiiString->GetString (
                      HiiString,
                      Language,
                      StringId,
                      HiiHandle,
                      String,
                      NULL
                      );
}

语言切换流程

mermaid

常见问题与解决方案

问题1:字符串令牌解析失败

症状:编译时提示STRING_TOKEN(XXX) not found

原因:.vfr文件中引用的字符串ID在.uni文件中未定义或拼写错误

解决方案

  • 检查.uni文件确保包含对应的#string定义
  • 验证字符串ID大小写是否一致(区分大小写)
  • 清理编译产物后重新构建(build clean

问题2:部分语言显示乱码

症状:中文、日文等非ASCII语言显示为乱码

原因:.uni文件编码不是UTF-8或未包含BOM头

解决方案

  • 使用支持UTF-8的编辑器(如VS Code)保存.uni文件
  • 添加UTF-8 BOM头(Windows环境)
  • 确保EDK II工具链支持宽字符(设置INTEL_ASM_ENABLE_WIDE_CHARACTER_SUPPORT=TRUE

问题3:HII数据库注册失败

症状HiiAddPackages()返回NULL

原因

  • 资源文件路径错误
  • 内存不足
  • GUID冲突

解决方案

  • 使用DEBUG宏输出详细日志
  • 验证VFR和UNI文件是否正确编译为二进制资源
  • 使用guidgen工具生成新的唯一GUID

性能优化策略

字符串压缩

对于包含大量字符串的应用,可启用EDK II的字符串压缩功能:

在.dsc文件中添加:

[Defines]
  SUPPORT_STRING_COMPRESSION = TRUE

按需加载

实现语言包的按需加载,减少内存占用:

// 只加载当前语言所需的字符串
EFI_STATUS
LoadLanguagePack (
  IN CHAR8 *LanguageCode
  )
{
  EFI_STATUS status;
  EFI_HANDLE packageHandle;
  
  // 加载指定语言的HII包
  status = gBS->LoadImage (
                  FALSE,
                  gImageHandle,
                  LanguageCode,  // 语言包路径
                  NULL,
                  0,
                  &packageHandle,
                  NULL
                  );
  if (!EFI_ERROR(status)) {
    status = gBS->StartImage (packageHandle, NULL, NULL);
  }
  
  return status;
}

总结与展望

HII本地化技术是构建全球化UEFI应用的关键,通过.uni和.vfr文件的配合,能够以最小的开发成本实现多语言支持。随着UEFI 2.10及后续版本的发布,HII将支持更多富文本格式和动态界面元素,进一步提升用户体验。

本文介绍的方法已在EDK II的DriverSampleDxe等示例中得到验证,读者可参考以下路径的源代码深入学习:

  • MdeModulePkg/Universal/DriverSampleDxe:HII示例驱动
  • MdeModulePkg/Include/Protocol/HiiConfigAccess.h:HII配置协议定义
  • MdeModulePkg/Library/UefiHiiLib:HII操作工具函数库

掌握HII本地化技术,将使你的UEFI应用能够轻松走向国际市场,满足不同地区用户的语言需求。立即动手改造你的第一个多语言UEFI应用吧!

扩展学习资源

  1. EDK II官方文档:《UEFI HII Specification》
  2. EDK II示例代码:MdeModulePkg/Universal/HiiResourcesSampleDxe
  3. UEFI论坛:HII Working Group
  4. 书籍:《Beyond BIOS: Developing with the Unified Extensible Firmware Interface》

如果你觉得本文有帮助,请点赞、收藏并关注作者,获取更多UEFI开发技术分享! 下期预告:UEFI表单动态验证与错误处理

【免费下载链接】edk2 EDK II 【免费下载链接】edk2 项目地址: https://gitcode.com/gh_mirrors/ed/edk2

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值