🎯 目标
在 UEFI Setup 的 Advanced 菜单下添加一个自定义子菜单,包含配置选项。
第一步:创建驱动程序目录结构
1.1 创建驱动程序目录
# 在 Drivers 目录下创建新的驱动程序目录
mkdir -p LsFwSdk/LsRefCodePkg/Drivers/YourMenuDxe
1.2 创建必需的文件
YourMenuDxe/
├── YourMenu.c # 主驱动程序文件
├── YourMenu.h # 头文件
├── YourMenuNv.h # 配置定义文件
├── YourMenuVfr.vfr # 表单定义文件
├── YourMenuStrings.uni # 字符串资源文件
└── YourMenuDxe.inf # 构建配置文件
第二步:配置文件创建(照着模板修改)
2.1 INF 文件模板 (YourMenuDxe.inf)
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = YourMenuDxe # 重要:影响符号命名
MODULE_UNI_FILE = YourMenuStrings.uni
FILE_GUID = XXXX-XXXX-XXXX-XXXX-XXXX # 生成新GUID
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = YourMenuInit
UNLOAD_IMAGE = YourMenuUnload
[Sources]
YourMenu.c
YourMenu.h
YourMenuNv.h
YourMenuStrings.uni # 必须包含此项
YourMenuVfr.vfr
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
LsRefCodePkg/Loongson.dec
[LibraryClasses]
BaseLib
MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
BaseMemoryLib
DebugLib
HiiLib
PrintLib
UefiLib
[Guids]
gEfiIfrTianoGuid
gEfiIfrFrontPageGuid
gEfiIfrAdvancedManagerGuid # 重要:使菜单显示在Advanced下
gYourMenuFormSetGuid # 在Loongson.dec中定义
[Protocols]
gEfiHiiConfigRoutingProtocolGuid
gEfiHiiConfigAccessProtocolGuid
gEfiFormBrowser2ProtocolGuid
gEdkiiFormBrowserExProtocolGuid
[Depex]
gEfiSimpleTextOutProtocolGuid AND gEfiHiiDatabaseProtocolGuid AND gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
2.2 配置定义文件 (YourMenuNv.h)
#ifndef _YOUR_MENU_NV_H_
#define _YOUR_MENU_NV_H_
#include <Guid/HiiPlatformSetupFormset.h>
#include <Guid/HiiFormMapMethodGuid.h>
#include <Guid/DriverSampleHii.h>
#include <Guid/ZeroGuid.h>
#include <SetupStru.h>
#define YOUR_MENU_SETTINGS_VARSTORE_ID 0x12XX # 使用唯一ID
#define YOUR_MENU_FORMSET_GUID { \
0xXXXXXXXX, 0xXXXX, 0xXXXX, { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX } \
}
#endif
2.3 在平台配置文件中注册GUID (Loongson.dec)
gYourMenuFormSetGuid = { 0xXXXXXXXX, 0xXXXX, 0xXXXX, { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX } }
第三步:配置数据结构定义
3.1 在 SetupStru.h 中添加配置结构体
/*************************************
* YOUR_MENU_SETTING
************************************/
typedef struct {
UINT8 YourOption; # OneOf控件必须使用UINT8/16/32/64
// 可以添加更多配置字段
} YOUR_MENU_SETTING;
第四步:字符串资源文件 (YourMenuStrings.uni)
4.1 字符串文件模板
#langdef en-US "English"
#langdef fr-FR "Francais"
#langdef x-UEFI-ns "UefiNameSpace"
#langdef zh-Hans "简体中文"
#string STR_YOUR_MENU_FORM_SET_TITLE #language en-US "Your Menu Title"
#language zh-Hans "您的菜单标题"
#string STR_YOUR_MENU_FORM_SET_TITLE_HELP #language en-US "Your menu help text"
#language zh-Hans "菜单帮助文本"
#string STR_YOUR_OPTION #language en-US "Your Option"
#language zh-Hans "您的选项"
#string STR_YOUR_OPTION_HELP #language en-US "Option help text"
#language zh-Hans "选项帮助文本"
#string STR_OPTION_VALUE_1 #language en-US "Option 1"
#language zh-Hans "选项1"
#string STR_OPTION_VALUE_2 #language en-US "Option 2"
#language zh-Hans "选项2"
#string STR_EMPTY_STRING #language en-US ""
#language zh-Hans ""
#string STR_DEVICE_PATH #language en-US ""
#language zh-Hans ""
⚠️ 重要注意事项:
- 字符串标识符不能包含特殊字符(如 ‘x’ 要改为 ‘_’)
- 必须包含
STR_EMPTY_STRING和STR_DEVICE_PATH
第五步:表单定义文件 (YourMenuVfr.vfr)
5.1 VFR 文件模板
#include "YourMenuNv.h"
formset
guid = YOUR_MENU_FORMSET_GUID,
title = STRING_TOKEN(STR_YOUR_MENU_FORM_SET_TITLE),
help = STRING_TOKEN(STR_YOUR_MENU_FORM_SET_TITLE_HELP),
classguid = gEfiIfrAdvancedManagerGuid, # 重要:显示在Advanced菜单下
# 配置存储定义 - 必须与SetupStru.h中的结构体名称一致
varstore YOUR_MENU_SETTING,
varid = YOUR_MENU_SETTINGS_VARSTORE_ID,
name = YourCfg,
guid = YOUR_MENU_FORMSET_GUID;
form formid = 0x1,
title = STRING_TOKEN(STR_YOUR_MENU_FORM_SET_TITLE);
subtitle text = STRING_TOKEN(STR_YOUR_MENU_FORM_SET_TITLE);
subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
# OneOf控件 - 只支持UINT8/16/32/64数据类型
oneof name = YourCfg,
varid = YourCfg.YourOption, # 格式:变量名.字段名
prompt = STRING_TOKEN(STR_YOUR_OPTION),
help = STRING_TOKEN(STR_YOUR_OPTION_HELP),
option text = STRING_TOKEN(STR_OPTION_VALUE_1), value=0x0, flags=DEFAULT;
option text = STRING_TOKEN(STR_OPTION_VALUE_2), value=0x1, flags=0;
endoneof;
endform;
endformset;
⚠️ 重要注意事项:
varstore后的结构体名称必须与SetupStru.h中定义的一致- OneOf 控件只支持 UINT8/16/32/64 数据类型
- 变量引用格式:
变量名.字段名
第六步:驱动程序实现 (YourMenu.c)
6.1 驱动程序模板
#include "YourMenu.h"
// 全局变量
CHAR16 VariableName[] = L"YourMenuConfig";
YOUR_MENU_PRIVATE_DATA *mPrivateData = NULL;
HII_VENDOR_DEVICE_PATH mYourMenuHiiVendorDevicePath;
// 配置访问协议实现
EFI_STATUS EFIAPI ExtractConfig(...) {
// 实现配置提取逻辑
}
EFI_STATUS EFIAPI RouteConfig(...) {
// 实现配置路由逻辑
}
EFI_STATUS EFIAPI Callback(...) {
// 实现回调逻辑
}
// 驱动程序入口点
EFI_STATUS EFIAPI YourMenuInit(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
EFI_STATUS Status;
EFI_HANDLE DriverHandle = NULL;
EFI_HII_HANDLE HiiHandle;
// 1. 分配私有数据结构
mPrivateData = AllocateZeroPool(sizeof(YOUR_MENU_PRIVATE_DATA));
// 2. 初始化设备路径结构体(运行时初始化,避免编译时常量问题)
mYourMenuHiiVendorDevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH;
mYourMenuHiiVendorDevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP;
mYourMenuHiiVendorDevicePath.VendorDevicePath.Header.Length[0] = (UINT8)(sizeof(VENDOR_DEVICE_PATH));
mYourMenuHiiVendorDevicePath.VendorDevicePath.Header.Length[1] = (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8);
CopyMem(&mYourMenuHiiVendorDevicePath.VendorDevicePath.Guid, &gYourMenuFormSetGuid, sizeof(EFI_GUID));
// 3. 安装协议接口
Status = gBS->InstallMultipleProtocolInterfaces(
&DriverHandle,
&gEfiDevicePathProtocolGuid, &mYourMenuHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid, &mPrivateData->ConfigAccess,
NULL
);
// 4. 添加HII包 - 重要:字符串包符号命名规则
HiiHandle = HiiAddPackages(
&gYourMenuFormSetGuid,
DriverHandle,
YourMenuDxeStrings, # BASE_NAME + "Strings"
YourMenuVfrBin,
NULL
);
return Status;
}
// 驱动程序卸载函数
EFI_STATUS EFIAPI YourMenuUnload(IN EFI_HANDLE ImageHandle) {
// 清理资源
}
⚠️ 重要注意事项:
- 字符串包符号:
BASE_NAME+ “Strings”(如:YourMenuDxeStrings) - 设备路径结构体必须在运行时初始化
- 必须实现配置访问协议的三个函数
第七步:平台集成配置
7.1 修改平台 DSC 文件
在每个平台的 DSC 文件中添加:
LsRefCodePkg/Drivers/YourMenuDxe/YourMenuDxe.inf
7.2 修改平台 FDF 文件
在每个平台的 FDF 文件中添加:
INF LsRefCodePkg/Drivers/YourMenuDxe/YourMenuDxe.inf
第八步:构建和调试
8.1 构建命令
# 清理构建缓存(遇到奇怪错误时使用)
rm -rf Build/Ls2k3000/
# 重新构建
python build.py -p LsFwSdk/LsRefCodePkg/LsRefCodePkg.dsc -a LOONGARCH64 -t GCC5 -b DEBUG
8.2 常见错误及解决方案
| 错误类型 | 错误信息 | 解决方案 |
|---|---|---|
| VFR编译错误 | undefined | 检查结构体名称是否一致 |
| 字符串错误 | No such file or directory | 确认UNI文件在[Sources]中 |
| 链接错误 | undefined reference | 检查字符串包符号命名 |
| 类型错误 | not constant | 改为运行时结构体初始化 |
✅ 成功验证标准
- 编译通过:无错误信息
- 链接成功:生成 EFI 驱动程序文件
- 菜单显示:在 UEFI Setup → Advanced 下看到自定义菜单
- 功能正常:选项可以选择和保存
📋 快速检查清单
- INF 文件中 UNI 文件在 [Sources] 中
- 字符串包符号命名正确(BASE_NAME + “Strings”)
- VFR 文件中结构体名称与 SetupStru.h 一致
- 平台 DSC/FDF 文件中添加了驱动程序引用
- GUID 在 Loongson.dec 中注册
- 设备路径结构体运行时初始化
393

被折叠的 条评论
为什么被折叠?



