UEFI开发学习20 – Setup 互动控制
概述
软件开发是有层次之分的,如网站程序中的前端和后端,前者注重于UI设计,后者则注重功能和逻辑的实现。网站前端语言有HTML、CSS、JS等,后端语言如PHP,Java等。此外,除了前后端,还有底层与上层之分。底层多为跟硬件打交道的固件开发,上层则是运行于OS中的APP开发,UEFI属于底层,底层中也分前后端,如UEFI中的Setup界面便是前端,读写寄存器,枚举设备等由C语言实现的则是后端。
setup 简介
Setup是UEFI为了方便对一些功能进行配置而设计的一个界面。同大多数的软件设计架构一样,UEFI也采用了前后端分离的架构,界面布局只需通过编辑VFR文件即可。
在UEFI的开发过程中,可能会需要在Setup界面做一些动态控制,如弹框,开关联动等,而VFR只是一种界面描述语言,无法直接动态控制,需要借助C语言来实现,那C语言如何得到VFR文件的相关信息呢?这一篇就来探究探究前端与后端的互动是如何实现的。
INTERACTIVE & questionid / key
INTERACTIVE 是Setup Item中的一个标志位,用于表示某Item支持互动功能;questionid / key 则是一个全局的Item id,setup中有很多的item,假如有多个item做互动功能,那就需要一个id来标识,每个id表示一个item。questionid和key的用途是一样的,区别是一个用于oneof的item,一个是用于text。
实例分析
SETUP首页有个Continue的Item,按下该Item将执行可引导程序,如下:
如何实现的呢?
在IntelFrameworkModulePkg\Universal\BdsDxe\FrontPageVfr.Vfr文件中,可找到相应的代码,如下:
text help = STRING_TOKEN(STR_CONTINUE_HELP), text = STRING_TOKEN(STR_CONTINUE_PROMPT), flags = INTERACTIVE, key = FRONT_PAGE_KEY_CONTINUE;
可看到,在flags处使用了INTERACTIVE来表示这是一个互动Item,之下还有一个key,它是一个全局id。通过搜索这个FRONT_PAGE_KEY_CONTINUE可定位到处理该Item的C文件IntelFrameworkModulePkg\Universal\BdsDxe\FrontPage.c:
EFI_STATUS
EFIAPI
FrontPageCallback (
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
)
{
CHAR8 *LangCode;
CHAR8 *Lang;
UINTN Index;
if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
//
// All other action return unsupported.
//
return EFI_UNSUPPORTED;
}
gCallbackKey = QuestionId;
if (Action == EFI_BROWSER_ACTION_CHANGED) {
if ((Value == NULL) || (ActionRequest == NULL)) {
return EFI_INVALID_PARAMETER;
}
switch (QuestionId) {
case FRONT_PAGE_KEY_CONTINUE:
//
// This is the continue - clear the screen and return an error to get out of FrontPage loop
//
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
break;
......
}
}
这个函数是如何跟continue这个item联系起来的呢?追踪这个函数FrontPageCallback ,最后可看到:
//
// Install Device Path Protocol and Config Access protocol to driver handle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&gFrontPagePrivate.DriverHandle,
&gEfiDevicePathProtocolGuid,
&mFrontPageHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&gFrontPagePrivate.ConfigAccess,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Publish our HII data
//
gFrontPagePrivate.HiiHandle = HiiAddPackages (
&gFrontPageFormSetGuid,
gFrontPagePrivate.DriverHandle,
FrontPageVfrBin,
BdsDxeStrings,
NULL
);
if (gFrontPagePrivate.HiiHandle == NULL) {
return EFI_OUT_OF_RESOURCES;
}
FrontPageCallback 被放入 gFrontPagePrivate.ConfigAccess 中,然后安装到 gFrontPagePrivate.DriverHandle,接着通过 HiiAddPackages 把continue所在form与 DriverHandle 绑定起来,这便是VFR与C交互的整个实现过程了。
实例
实现一个联动控制Item,即当Item1的值变化时,Item2也跟着变化。
MdeModulePkg\Universal\DriverSampleDxe\Vfr.vfr文件添加:
oneof varid = MyIfrNVData.Ay123_T1, questionid = 0x9876, prompt = STRING_TOKEN(STR_AY123_TEST1), help = STRING_TOKEN(STR_AY123_HELP), flags = INTERACTIVE, option text = STRING_TOKEN(STR_ENABLE), value = 0x0, flags = DEFAULT; option text = STRING_TOKEN(STR_DISABLE), value = 0x1, flags = 0; endoneof; oneof varid = MyIfrNVData.Ay123_T2, questionid = 0x9875, prompt = STRING_TOKEN(STR_AY123_TEST2), help = STRING_TOKEN(STR_AY123_HELP), flags = INTERACTIVE, option text = STRING_TOKEN(STR_ENABLE), value = 0x0, flags = DEFAULT; option text = STRING_TOKEN(STR_DISABLE), value = 0x1, flags = 0; endoneof; subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
MdeModulePkg\Universal\DriverSampleDxe\NVDataStruc.h 中的 DRIVER_SAMPLE_CONFIGURATION 添加:
UINT8 Ay123_T1; UINT8 Ay123_T2;
MdeModulePkg\Universal\DriverSampleDxe\VfrStrings.uni 添加:
#string STR_AY123_TEST1 #language en-US "Ay123 Test 1" #string STR_AY123_TEST2 #language en-US "Ay123 Test 2" #string STR_AY123_HELP #language en-US "Ay123 Test help" #string STR_ENABLE #language en-US "Enable" #string STR_DISABLE #language en-US "Disable"
MdeModulePkg\Universal\DriverSampleDxe\DriverSample.c 中case 0x1330下添加
case 0x9876:
Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_CONFIGURATION));
ASSERT (Configuration != NULL);
HiiGetBrowserData (&gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration);
Configuration->Ay123_T2 = Value->u8;
//
// Update uncommitted data of Browser
//
HiiSetBrowserData (
&gDriverSampleFormSetGuid,
VariableName,
sizeof (DRIVER_SAMPLE_CONFIGURATION),
(UINT8 *) Configuration,
NULL
);
break;
最终效果如下:
版权声明:
作者:bin
链接:https://ay123.net/mystudy/1293/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。



共有 0 条评论