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 条评论