/** @file This library class defines a set of interfaces to customize Ui module Copyright (c) 2016, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FrontPageCustomizedUiSupport.h" // // This is the VFR compiler generated header file which defines the // string identifiers. // #define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001 #define UI_HII_DRIVER_LIST_SIZE 0x8 #define FRONT_PAGE_KEY_CONTINUE 0x1000 #define FRONT_PAGE_KEY_RESET 0x1001 #define FRONT_PAGE_KEY_LANGUAGE 0x1002 #define FRONT_PAGE_KEY_DRIVER 0x2000 typedef struct { EFI_STRING_ID PromptId; EFI_STRING_ID HelpId; EFI_STRING_ID DevicePathId; EFI_GUID FormSetGuid; BOOLEAN EmptyLineAfter; } UI_HII_DRIVER_INSTANCE; CHAR8 *gLanguageString; EFI_STRING_ID *gLanguageToken; UI_HII_DRIVER_INSTANCE *gHiiDriverList; extern EFI_HII_HANDLE gStringPackHandle; UINT8 gCurrentLanguageIndex; /** Get next language from language code list (with separator ';'). If LangCode is NULL, then ASSERT. If Lang is NULL, then ASSERT. @param LangCode On input: point to first language in the list. On output: point to next language in the list, or NULL if no more language in the list. @param Lang The first language in the list. **/ VOID GetNextLanguage ( IN OUT CHAR8 **LangCode, OUT CHAR8 *Lang ) { UINTN Index; CHAR8 *StringPtr; ASSERT (LangCode != NULL); ASSERT (*LangCode != NULL); ASSERT (Lang != NULL); Index = 0; StringPtr = *LangCode; while (StringPtr[Index] != 0 && StringPtr[Index] != ';') { Index++; } CopyMem (Lang, StringPtr, Index); Lang[Index] = 0; if (StringPtr[Index] == ';') { Index++; } *LangCode = StringPtr + Index; } /** This function processes the language changes in configuration. @param Value A pointer to the data being sent to the original exporting driver. @retval TRUE The callback successfully handled the action. @retval FALSE The callback not supported in this handler. **/ EFI_STATUS LanguageChangeHandler ( IN EFI_IFR_TYPE_VALUE *Value ) { CHAR8 *LangCode; CHAR8 *Lang; UINTN Index; EFI_STATUS Status; // // Allocate working buffer for RFC 4646 language in supported LanguageString. // Lang = AllocatePool (AsciiStrSize (gLanguageString)); ASSERT (Lang != NULL); Index = 0; LangCode = gLanguageString; while (*LangCode != 0) { GetNextLanguage (&LangCode, Lang); if (Index == Value->u8) { gCurrentLanguageIndex = Value->u8; break; } Index++; } if (Index == Value->u8) { Status = gRT->SetVariable ( L"PlatformLang", &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, AsciiStrSize (Lang), Lang ); if (EFI_ERROR (Status)) { FreePool (Lang); return EFI_DEVICE_ERROR; } } else { ASSERT (FALSE); } FreePool (Lang); return EFI_SUCCESS; } /** This function processes the results of changes in configuration. @param HiiHandle Points to the hii handle for this formset. @param Action Specifies the type of action taken by the browser. @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. @param Type The type of value for the question. @param Value A pointer to the data being sent to the original exporting driver. @param ActionRequest On return, points to the action requested by the callback function. @param Status Return the handle status. @retval TRUE The callback successfully handled the action. @retval FALSE The callback not supported in this handler. **/ BOOLEAN UiSupportLibCallbackHandler ( IN EFI_HII_HANDLE HiiHandle, 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, OUT EFI_STATUS *Status ) { if (QuestionId != FRONT_PAGE_KEY_CONTINUE && QuestionId != FRONT_PAGE_KEY_RESET && QuestionId != FRONT_PAGE_KEY_LANGUAGE) { return FALSE; } if (Action == EFI_BROWSER_ACTION_RETRIEVE) { if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) { Value->u8 = gCurrentLanguageIndex; *Status = EFI_SUCCESS; } else { *Status = EFI_UNSUPPORTED; } return TRUE; } if (Action != EFI_BROWSER_ACTION_CHANGED) { // // Do nothing for other UEFI Action. Only do call back when data is changed. // *Status = EFI_UNSUPPORTED; return TRUE; } if (Action == EFI_BROWSER_ACTION_CHANGED) { if ((Value == NULL) || (ActionRequest == NULL)) { *Status = EFI_INVALID_PARAMETER; return TRUE; } *Status = EFI_SUCCESS; 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; case FRONT_PAGE_KEY_LANGUAGE: *Status = LanguageChangeHandler(Value); break; case FRONT_PAGE_KEY_RESET: // // Reset // gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); *Status = EFI_UNSUPPORTED; default: break; } } return TRUE; } /** Create Select language menu in the front page with oneof opcode. @param[in] HiiHandle The hii handle for the Uiapp driver. @param[in] StartOpCodeHandle The opcode handle to save the new opcode. **/ VOID UiCreateLanguageMenu ( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { CHAR8 *LangCode; CHAR8 *Lang; UINTN LangSize; CHAR8 *CurrentLang; UINTN OptionCount; CHAR16 *StringBuffer; VOID *OptionsOpCodeHandle; UINTN StringSize; EFI_STATUS Status; EFI_HII_STRING_PROTOCOL *HiiString; Lang = NULL; StringBuffer = NULL; // // Init OpCode Handle and Allocate space for creation of UpdateData Buffer // OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (OptionsOpCodeHandle != NULL); GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL); // // Get Support language list from variable. // GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL); if (gLanguageString == NULL) { gLanguageString = AllocateCopyPool ( AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)), (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes) ); ASSERT (gLanguageString != NULL); } if (gLanguageToken == NULL) { // // Count the language list number. // LangCode = gLanguageString; Lang = AllocatePool (AsciiStrSize (gLanguageString)); ASSERT (Lang != NULL); OptionCount = 0; while (*LangCode != 0) { GetNextLanguage (&LangCode, Lang); OptionCount ++; } // // Allocate extra 1 as the end tag. // gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID)); ASSERT (gLanguageToken != NULL); Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString); ASSERT_EFI_ERROR (Status); LangCode = gLanguageString; OptionCount = 0; while (*LangCode != 0) { GetNextLanguage (&LangCode, Lang); StringSize = 0; Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL); if (Status == EFI_BUFFER_TOO_SMALL) { StringBuffer = AllocateZeroPool (StringSize); ASSERT (StringBuffer != NULL); Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL); ASSERT_EFI_ERROR (Status); } if (EFI_ERROR (Status)) { LangSize = AsciiStrSize (Lang); StringBuffer = AllocatePool (LangSize * sizeof (CHAR16)); ASSERT (StringBuffer != NULL); AsciiStrToUnicodeStrS (Lang, StringBuffer, LangSize); } ASSERT (StringBuffer != NULL); gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL); FreePool (StringBuffer); OptionCount++; } } ASSERT (gLanguageToken != NULL); LangCode = gLanguageString; OptionCount = 0; if (Lang == NULL) { Lang = AllocatePool (AsciiStrSize (gLanguageString)); ASSERT (Lang != NULL); } while (*LangCode != 0) { GetNextLanguage (&LangCode, Lang); if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) { HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, gLanguageToken[OptionCount], EFI_IFR_OPTION_DEFAULT, EFI_IFR_NUMERIC_SIZE_1, (UINT8) OptionCount ); gCurrentLanguageIndex = (UINT8) OptionCount; } else { HiiCreateOneOfOptionOpCode ( OptionsOpCodeHandle, gLanguageToken[OptionCount], 0, EFI_IFR_NUMERIC_SIZE_1, (UINT8) OptionCount ); } OptionCount++; } if (CurrentLang != NULL) { FreePool (CurrentLang); } FreePool (Lang); HiiCreateOneOfOpCode ( StartOpCodeHandle, FRONT_PAGE_KEY_LANGUAGE, 0, 0, STRING_TOKEN (STR_LANGUAGE_SELECT), STRING_TOKEN (STR_LANGUAGE_SELECT_HELP), EFI_IFR_FLAG_CALLBACK, EFI_IFR_NUMERIC_SIZE_1, OptionsOpCodeHandle, NULL ); } /** Create continue menu in the front page. @param[in] HiiHandle The hii handle for the Uiapp driver. @param[in] StartOpCodeHandle The opcode handle to save the new opcode. **/ VOID UiCreateContinueMenu ( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { HiiCreateActionOpCode ( StartOpCodeHandle, FRONT_PAGE_KEY_CONTINUE, STRING_TOKEN (STR_CONTINUE_PROMPT), STRING_TOKEN (STR_CONTINUE_PROMPT), EFI_IFR_FLAG_CALLBACK, 0 ); } /** Create empty line menu in the front page. @param HiiHandle The hii handle for the Uiapp driver. @param StartOpCodeHandle The opcode handle to save the new opcode. **/ VOID UiCreateEmptyLine ( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0); } /** Create Reset menu in the front page. @param[in] HiiHandle The hii handle for the Uiapp driver. @param[in] StartOpCodeHandle The opcode handle to save the new opcode. **/ VOID UiCreateResetMenu ( IN EFI_HII_HANDLE HiiHandle, IN VOID *StartOpCodeHandle ) { HiiCreateActionOpCode ( StartOpCodeHandle, FRONT_PAGE_KEY_RESET, STRING_TOKEN (STR_RESET_STRING), STRING_TOKEN (STR_RESET_STRING), EFI_IFR_FLAG_CALLBACK, 0 ); } /** Extract device path for given HII handle and class guid. @param Handle The HII handle. @retval NULL Fail to get the device path string. @return PathString Get the device path string. **/ CHAR16 * ExtractDevicePathFromHiiHandle ( IN EFI_HII_HANDLE Handle ) { EFI_STATUS Status; EFI_HANDLE DriverHandle; ASSERT (Handle != NULL); if (Handle == NULL) { return NULL; } Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle); if (EFI_ERROR (Status)) { return NULL; } return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE); } /** Check whether this driver need to be shown in the front page. @param HiiHandle The hii handle for the driver. @param Guid The special guid for the driver which is the target. @param PromptId Return the prompt string id. @param HelpId Return the help string id. @param FormsetGuid Return the formset guid info. @retval EFI_SUCCESS Search the driver success **/ BOOLEAN RequiredDriver ( IN EFI_HII_HANDLE HiiHandle, IN EFI_GUID *Guid, OUT EFI_STRING_ID *PromptId, OUT EFI_STRING_ID *HelpId, OUT VOID *FormsetGuid ) { EFI_STATUS Status; UINT8 ClassGuidNum; EFI_GUID *ClassGuid; EFI_IFR_FORM_SET *Buffer; UINTN BufferSize; UINT8 *Ptr; UINTN TempSize; BOOLEAN RetVal; Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize); if (EFI_ERROR (Status)) { return FALSE; } RetVal = FALSE; TempSize = 0; Ptr = (UINT8 *) Buffer; while(TempSize < BufferSize) { TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length; if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){ Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length; continue; } ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3); ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET)); while (ClassGuidNum-- > 0) { if (!CompareGuid (Guid, ClassGuid)){ ClassGuid ++; continue; } *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle; *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help; CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID)); RetVal = TRUE; } } FreePool (Buffer); return RetVal; } /** Search the drivers in the system which need to show in the front page and insert the menu to the front page. @param HiiHandle The hii handle for the Uiapp driver. @param ClassGuid The class guid for the driver which is the target. @param SpecialHandlerFn The pointer to the special handler function, if any. @param StartOpCodeHandle The opcode handle to save the new opcode. @retval EFI_SUCCESS Search the driver success **/ EFI_STATUS UiListThirdPartyDrivers ( IN EFI_HII_HANDLE HiiHandle, IN EFI_GUID *ClassGuid, IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn, IN VOID *StartOpCodeHandle ) { UINTN Index; EFI_STRING String; EFI_STRING_ID Token; EFI_STRING_ID TokenHelp; EFI_HII_HANDLE *HiiHandles; CHAR16 *DevicePathStr; UINTN Count; UINTN CurrentSize; UI_HII_DRIVER_INSTANCE *DriverListPtr; EFI_STRING NewName; BOOLEAN EmptyLineAfter; if (gHiiDriverList != NULL) { FreePool (gHiiDriverList); } HiiHandles = HiiGetHiiHandles (NULL); ASSERT (HiiHandles != NULL); gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE)); ASSERT (gHiiDriverList != NULL); DriverListPtr = gHiiDriverList; CurrentSize = UI_HII_DRIVER_LIST_SIZE; for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) { if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) { continue; } String = HiiGetString (HiiHandles[Index], Token, NULL); if (String == NULL) { String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL); ASSERT (String != NULL); } else if (SpecialHandlerFn != NULL) { // // Check whether need to rename the driver name. // EmptyLineAfter = FALSE; if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) { FreePool (String); String = NewName; DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter; } } DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL); FreePool (String); String = HiiGetString (HiiHandles[Index], TokenHelp, NULL); if (String == NULL) { String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL); ASSERT (String != NULL); } DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL); FreePool (String); DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]); if (DevicePathStr != NULL){ DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL); FreePool (DevicePathStr); } else { DriverListPtr[Count].DevicePathId = 0; } Count++; if (Count >= CurrentSize) { DriverListPtr = ReallocatePool ( CurrentSize * sizeof (UI_HII_DRIVER_INSTANCE), (Count + UI_HII_DRIVER_LIST_SIZE) * sizeof (UI_HII_DRIVER_INSTANCE), gHiiDriverList ); ASSERT (DriverListPtr != NULL); gHiiDriverList = DriverListPtr; CurrentSize += UI_HII_DRIVER_LIST_SIZE; } } FreePool (HiiHandles); Index = 0; while (gHiiDriverList[Index].PromptId != 0) { HiiCreateGotoExOpCode ( StartOpCodeHandle, 0, gHiiDriverList[Index].PromptId, gHiiDriverList[Index].HelpId, 0, (EFI_QUESTION_ID) (Index + FRONT_PAGE_KEY_DRIVER), 0, &gHiiDriverList[Index].FormSetGuid, gHiiDriverList[Index].DevicePathId ); if (gHiiDriverList[Index].EmptyLineAfter) { UiCreateEmptyLine (HiiHandle, StartOpCodeHandle); } Index ++; } return EFI_SUCCESS; }