1 /** @file 2 3 This library class defines a set of interfaces to customize Ui module 4 5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 8 The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php. 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 #include <Uefi.h> 16 17 #include <Guid/MdeModuleHii.h> 18 #include <Guid/GlobalVariable.h> 19 20 #include <Protocol/HiiConfigAccess.h> 21 #include <Protocol/HiiString.h> 22 23 #include <Library/HiiLib.h> 24 #include <Library/DebugLib.h> 25 #include <Library/UefiLib.h> 26 #include <Library/BaseMemoryLib.h> 27 #include <Library/PcdLib.h> 28 #include <Library/MemoryAllocationLib.h> 29 #include <Library/UefiRuntimeServicesTableLib.h> 30 #include <Library/UefiHiiServicesLib.h> 31 #include <Library/DevicePathLib.h> 32 #include <Library/UefiBootServicesTableLib.h> 33 #include "FrontPageCustomizedUiSupport.h" 34 35 // 36 // This is the VFR compiler generated header file which defines the 37 // string identifiers. 38 // 39 #define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001 40 41 #define UI_HII_DRIVER_LIST_SIZE 0x8 42 43 #define FRONT_PAGE_KEY_CONTINUE 0x1000 44 #define FRONT_PAGE_KEY_RESET 0x1001 45 #define FRONT_PAGE_KEY_LANGUAGE 0x1002 46 #define FRONT_PAGE_KEY_DRIVER 0x2000 47 48 typedef struct { 49 EFI_STRING_ID PromptId; 50 EFI_STRING_ID HelpId; 51 EFI_STRING_ID DevicePathId; 52 EFI_GUID FormSetGuid; 53 BOOLEAN EmptyLineAfter; 54 } UI_HII_DRIVER_INSTANCE; 55 56 CHAR8 *gLanguageString; 57 EFI_STRING_ID *gLanguageToken; 58 UI_HII_DRIVER_INSTANCE *gHiiDriverList; 59 extern EFI_HII_HANDLE gStringPackHandle; 60 UINT8 gCurrentLanguageIndex; 61 62 63 /** 64 Get next language from language code list (with separator ';'). 65 66 If LangCode is NULL, then ASSERT. 67 If Lang is NULL, then ASSERT. 68 69 @param LangCode On input: point to first language in the list. On 70 output: point to next language in the list, or 71 NULL if no more language in the list. 72 @param Lang The first language in the list. 73 74 **/ 75 VOID 76 GetNextLanguage ( 77 IN OUT CHAR8 **LangCode, 78 OUT CHAR8 *Lang 79 ) 80 { 81 UINTN Index; 82 CHAR8 *StringPtr; 83 84 ASSERT (LangCode != NULL); 85 ASSERT (*LangCode != NULL); 86 ASSERT (Lang != NULL); 87 88 Index = 0; 89 StringPtr = *LangCode; 90 while (StringPtr[Index] != 0 && StringPtr[Index] != ';') { 91 Index++; 92 } 93 94 CopyMem (Lang, StringPtr, Index); 95 Lang[Index] = 0; 96 97 if (StringPtr[Index] == ';') { 98 Index++; 99 } 100 *LangCode = StringPtr + Index; 101 } 102 103 /** 104 This function processes the language changes in configuration. 105 106 @param Value A pointer to the data being sent to the original exporting driver. 107 108 109 @retval TRUE The callback successfully handled the action. 110 @retval FALSE The callback not supported in this handler. 111 112 **/ 113 EFI_STATUS 114 LanguageChangeHandler ( 115 IN EFI_IFR_TYPE_VALUE *Value 116 ) 117 { 118 CHAR8 *LangCode; 119 CHAR8 *Lang; 120 UINTN Index; 121 EFI_STATUS Status; 122 123 // 124 // Allocate working buffer for RFC 4646 language in supported LanguageString. 125 // 126 Lang = AllocatePool (AsciiStrSize (gLanguageString)); 127 ASSERT (Lang != NULL); 128 129 Index = 0; 130 LangCode = gLanguageString; 131 while (*LangCode != 0) { 132 GetNextLanguage (&LangCode, Lang); 133 134 if (Index == Value->u8) { 135 gCurrentLanguageIndex = Value->u8; 136 break; 137 } 138 139 Index++; 140 } 141 142 if (Index == Value->u8) { 143 Status = gRT->SetVariable ( 144 L"PlatformLang", 145 &gEfiGlobalVariableGuid, 146 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 147 AsciiStrSize (Lang), 148 Lang 149 ); 150 if (EFI_ERROR (Status)) { 151 FreePool (Lang); 152 return EFI_DEVICE_ERROR; 153 } 154 } else { 155 ASSERT (FALSE); 156 } 157 FreePool (Lang); 158 159 return EFI_SUCCESS; 160 } 161 162 /** 163 This function processes the results of changes in configuration. 164 165 166 @param HiiHandle Points to the hii handle for this formset. 167 @param Action Specifies the type of action taken by the browser. 168 @param QuestionId A unique value which is sent to the original exporting driver 169 so that it can identify the type of data to expect. 170 @param Type The type of value for the question. 171 @param Value A pointer to the data being sent to the original exporting driver. 172 @param ActionRequest On return, points to the action requested by the callback function. 173 @param Status Return the handle status. 174 175 @retval TRUE The callback successfully handled the action. 176 @retval FALSE The callback not supported in this handler. 177 178 **/ 179 BOOLEAN 180 UiSupportLibCallbackHandler ( 181 IN EFI_HII_HANDLE HiiHandle, 182 IN EFI_BROWSER_ACTION Action, 183 IN EFI_QUESTION_ID QuestionId, 184 IN UINT8 Type, 185 IN EFI_IFR_TYPE_VALUE *Value, 186 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest, 187 OUT EFI_STATUS *Status 188 ) 189 { 190 if (QuestionId != FRONT_PAGE_KEY_CONTINUE && 191 QuestionId != FRONT_PAGE_KEY_RESET && 192 QuestionId != FRONT_PAGE_KEY_LANGUAGE) { 193 return FALSE; 194 } 195 196 if (Action == EFI_BROWSER_ACTION_RETRIEVE) { 197 if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) { 198 Value->u8 = gCurrentLanguageIndex; 199 *Status = EFI_SUCCESS; 200 } else { 201 *Status = EFI_UNSUPPORTED; 202 } 203 return TRUE; 204 } 205 206 if (Action != EFI_BROWSER_ACTION_CHANGED) { 207 // 208 // Do nothing for other UEFI Action. Only do call back when data is changed. 209 // 210 *Status = EFI_UNSUPPORTED; 211 return TRUE; 212 } 213 214 if (Action == EFI_BROWSER_ACTION_CHANGED) { 215 if ((Value == NULL) || (ActionRequest == NULL)) { 216 *Status = EFI_INVALID_PARAMETER; 217 return TRUE; 218 } 219 220 *Status = EFI_SUCCESS; 221 switch (QuestionId) { 222 case FRONT_PAGE_KEY_CONTINUE: 223 // 224 // This is the continue - clear the screen and return an error to get out of FrontPage loop 225 // 226 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; 227 break; 228 229 case FRONT_PAGE_KEY_LANGUAGE: 230 *Status = LanguageChangeHandler(Value); 231 break; 232 233 case FRONT_PAGE_KEY_RESET: 234 // 235 // Reset 236 // 237 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); 238 *Status = EFI_UNSUPPORTED; 239 240 default: 241 break; 242 } 243 } 244 245 return TRUE; 246 } 247 248 /** 249 Create Select language menu in the front page with oneof opcode. 250 251 @param[in] HiiHandle The hii handle for the Uiapp driver. 252 @param[in] StartOpCodeHandle The opcode handle to save the new opcode. 253 254 **/ 255 VOID 256 UiCreateLanguageMenu ( 257 IN EFI_HII_HANDLE HiiHandle, 258 IN VOID *StartOpCodeHandle 259 ) 260 { 261 CHAR8 *LangCode; 262 CHAR8 *Lang; 263 UINTN LangSize; 264 CHAR8 *CurrentLang; 265 UINTN OptionCount; 266 CHAR16 *StringBuffer; 267 VOID *OptionsOpCodeHandle; 268 UINTN StringSize; 269 EFI_STATUS Status; 270 EFI_HII_STRING_PROTOCOL *HiiString; 271 272 Lang = NULL; 273 StringBuffer = NULL; 274 275 // 276 // Init OpCode Handle and Allocate space for creation of UpdateData Buffer 277 // 278 OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); 279 ASSERT (OptionsOpCodeHandle != NULL); 280 281 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL); 282 283 // 284 // Get Support language list from variable. 285 // 286 GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL); 287 if (gLanguageString == NULL) { 288 gLanguageString = AllocateCopyPool ( 289 AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)), 290 (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes) 291 ); 292 ASSERT (gLanguageString != NULL); 293 } 294 295 if (gLanguageToken == NULL) { 296 // 297 // Count the language list number. 298 // 299 LangCode = gLanguageString; 300 Lang = AllocatePool (AsciiStrSize (gLanguageString)); 301 ASSERT (Lang != NULL); 302 303 OptionCount = 0; 304 while (*LangCode != 0) { 305 GetNextLanguage (&LangCode, Lang); 306 OptionCount ++; 307 } 308 309 // 310 // Allocate extra 1 as the end tag. 311 // 312 gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID)); 313 ASSERT (gLanguageToken != NULL); 314 315 Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString); 316 ASSERT_EFI_ERROR (Status); 317 318 LangCode = gLanguageString; 319 OptionCount = 0; 320 while (*LangCode != 0) { 321 GetNextLanguage (&LangCode, Lang); 322 323 StringSize = 0; 324 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL); 325 if (Status == EFI_BUFFER_TOO_SMALL) { 326 StringBuffer = AllocateZeroPool (StringSize); 327 ASSERT (StringBuffer != NULL); 328 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL); 329 ASSERT_EFI_ERROR (Status); 330 } 331 332 if (EFI_ERROR (Status)) { 333 LangSize = AsciiStrSize (Lang); 334 StringBuffer = AllocatePool (LangSize * sizeof (CHAR16)); 335 ASSERT (StringBuffer != NULL); 336 AsciiStrToUnicodeStrS (Lang, StringBuffer, LangSize); 337 } 338 339 ASSERT (StringBuffer != NULL); 340 gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL); 341 FreePool (StringBuffer); 342 343 OptionCount++; 344 } 345 } 346 347 ASSERT (gLanguageToken != NULL); 348 LangCode = gLanguageString; 349 OptionCount = 0; 350 if (Lang == NULL) { 351 Lang = AllocatePool (AsciiStrSize (gLanguageString)); 352 ASSERT (Lang != NULL); 353 } 354 while (*LangCode != 0) { 355 GetNextLanguage (&LangCode, Lang); 356 357 if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) { 358 HiiCreateOneOfOptionOpCode ( 359 OptionsOpCodeHandle, 360 gLanguageToken[OptionCount], 361 EFI_IFR_OPTION_DEFAULT, 362 EFI_IFR_NUMERIC_SIZE_1, 363 (UINT8) OptionCount 364 ); 365 gCurrentLanguageIndex = (UINT8) OptionCount; 366 } else { 367 HiiCreateOneOfOptionOpCode ( 368 OptionsOpCodeHandle, 369 gLanguageToken[OptionCount], 370 0, 371 EFI_IFR_NUMERIC_SIZE_1, 372 (UINT8) OptionCount 373 ); 374 } 375 376 OptionCount++; 377 } 378 379 if (CurrentLang != NULL) { 380 FreePool (CurrentLang); 381 } 382 FreePool (Lang); 383 384 HiiCreateOneOfOpCode ( 385 StartOpCodeHandle, 386 FRONT_PAGE_KEY_LANGUAGE, 387 0, 388 0, 389 STRING_TOKEN (STR_LANGUAGE_SELECT), 390 STRING_TOKEN (STR_LANGUAGE_SELECT_HELP), 391 EFI_IFR_FLAG_CALLBACK, 392 EFI_IFR_NUMERIC_SIZE_1, 393 OptionsOpCodeHandle, 394 NULL 395 ); 396 } 397 398 /** 399 Create continue menu in the front page. 400 401 @param[in] HiiHandle The hii handle for the Uiapp driver. 402 @param[in] StartOpCodeHandle The opcode handle to save the new opcode. 403 404 **/ 405 VOID 406 UiCreateContinueMenu ( 407 IN EFI_HII_HANDLE HiiHandle, 408 IN VOID *StartOpCodeHandle 409 ) 410 { 411 HiiCreateActionOpCode ( 412 StartOpCodeHandle, 413 FRONT_PAGE_KEY_CONTINUE, 414 STRING_TOKEN (STR_CONTINUE_PROMPT), 415 STRING_TOKEN (STR_CONTINUE_PROMPT), 416 EFI_IFR_FLAG_CALLBACK, 417 0 418 ); 419 } 420 421 /** 422 Create empty line menu in the front page. 423 424 @param HiiHandle The hii handle for the Uiapp driver. 425 @param StartOpCodeHandle The opcode handle to save the new opcode. 426 427 **/ 428 VOID 429 UiCreateEmptyLine ( 430 IN EFI_HII_HANDLE HiiHandle, 431 IN VOID *StartOpCodeHandle 432 ) 433 { 434 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0); 435 } 436 437 /** 438 Create Reset menu in the front page. 439 440 @param[in] HiiHandle The hii handle for the Uiapp driver. 441 @param[in] StartOpCodeHandle The opcode handle to save the new opcode. 442 443 **/ 444 VOID 445 UiCreateResetMenu ( 446 IN EFI_HII_HANDLE HiiHandle, 447 IN VOID *StartOpCodeHandle 448 ) 449 { 450 HiiCreateActionOpCode ( 451 StartOpCodeHandle, 452 FRONT_PAGE_KEY_RESET, 453 STRING_TOKEN (STR_RESET_STRING), 454 STRING_TOKEN (STR_RESET_STRING), 455 EFI_IFR_FLAG_CALLBACK, 456 0 457 ); 458 } 459 460 /** 461 Extract device path for given HII handle and class guid. 462 463 @param Handle The HII handle. 464 465 @retval NULL Fail to get the device path string. 466 @return PathString Get the device path string. 467 468 **/ 469 CHAR16 * 470 ExtractDevicePathFromHiiHandle ( 471 IN EFI_HII_HANDLE Handle 472 ) 473 { 474 EFI_STATUS Status; 475 EFI_HANDLE DriverHandle; 476 477 ASSERT (Handle != NULL); 478 479 if (Handle == NULL) { 480 return NULL; 481 } 482 483 Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle); 484 if (EFI_ERROR (Status)) { 485 return NULL; 486 } 487 488 return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE); 489 } 490 491 /** 492 Check whether this driver need to be shown in the front page. 493 494 @param HiiHandle The hii handle for the driver. 495 @param Guid The special guid for the driver which is the target. 496 @param PromptId Return the prompt string id. 497 @param HelpId Return the help string id. 498 @param FormsetGuid Return the formset guid info. 499 500 @retval EFI_SUCCESS Search the driver success 501 502 **/ 503 BOOLEAN 504 RequiredDriver ( 505 IN EFI_HII_HANDLE HiiHandle, 506 IN EFI_GUID *Guid, 507 OUT EFI_STRING_ID *PromptId, 508 OUT EFI_STRING_ID *HelpId, 509 OUT VOID *FormsetGuid 510 ) 511 { 512 EFI_STATUS Status; 513 UINT8 ClassGuidNum; 514 EFI_GUID *ClassGuid; 515 EFI_IFR_FORM_SET *Buffer; 516 UINTN BufferSize; 517 UINT8 *Ptr; 518 UINTN TempSize; 519 BOOLEAN RetVal; 520 521 Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize); 522 if (EFI_ERROR (Status)) { 523 return FALSE; 524 } 525 526 RetVal = FALSE; 527 TempSize = 0; 528 Ptr = (UINT8 *) Buffer; 529 while(TempSize < BufferSize) { 530 TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length; 531 532 if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){ 533 Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length; 534 continue; 535 } 536 537 ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3); 538 ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET)); 539 while (ClassGuidNum-- > 0) { 540 if (!CompareGuid (Guid, ClassGuid)){ 541 ClassGuid ++; 542 continue; 543 } 544 545 *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle; 546 *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help; 547 CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID)); 548 RetVal = TRUE; 549 } 550 } 551 552 FreePool (Buffer); 553 554 return RetVal; 555 } 556 557 /** 558 Search the drivers in the system which need to show in the front page 559 and insert the menu to the front page. 560 561 @param HiiHandle The hii handle for the Uiapp driver. 562 @param ClassGuid The class guid for the driver which is the target. 563 @param SpecialHandlerFn The pointer to the specail handler function, if any. 564 @param StartOpCodeHandle The opcode handle to save the new opcode. 565 566 @retval EFI_SUCCESS Search the driver success 567 568 **/ 569 EFI_STATUS 570 UiListThirdPartyDrivers ( 571 IN EFI_HII_HANDLE HiiHandle, 572 IN EFI_GUID *ClassGuid, 573 IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn, 574 IN VOID *StartOpCodeHandle 575 ) 576 { 577 UINTN Index; 578 EFI_STRING String; 579 EFI_STRING_ID Token; 580 EFI_STRING_ID TokenHelp; 581 EFI_HII_HANDLE *HiiHandles; 582 CHAR16 *DevicePathStr; 583 UINTN Count; 584 UINTN CurrentSize; 585 UI_HII_DRIVER_INSTANCE *DriverListPtr; 586 EFI_STRING NewName; 587 BOOLEAN EmptyLineAfter; 588 589 if (gHiiDriverList != NULL) { 590 FreePool (gHiiDriverList); 591 } 592 593 HiiHandles = HiiGetHiiHandles (NULL); 594 ASSERT (HiiHandles != NULL); 595 596 gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE)); 597 ASSERT (gHiiDriverList != NULL); 598 DriverListPtr = gHiiDriverList; 599 CurrentSize = UI_HII_DRIVER_LIST_SIZE; 600 601 for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) { 602 if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) { 603 continue; 604 } 605 606 String = HiiGetString (HiiHandles[Index], Token, NULL); 607 if (String == NULL) { 608 String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL); 609 ASSERT (String != NULL); 610 } else if (SpecialHandlerFn != NULL) { 611 // 612 // Check whether need to rename the driver name. 613 // 614 EmptyLineAfter = FALSE; 615 if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) { 616 FreePool (String); 617 String = NewName; 618 DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter; 619 } 620 } 621 DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL); 622 FreePool (String); 623 624 String = HiiGetString (HiiHandles[Index], TokenHelp, NULL); 625 if (String == NULL) { 626 String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL); 627 ASSERT (String != NULL); 628 } 629 DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL); 630 FreePool (String); 631 632 DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]); 633 if (DevicePathStr != NULL){ 634 DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL); 635 FreePool (DevicePathStr); 636 } else { 637 DriverListPtr[Count].DevicePathId = 0; 638 } 639 640 Count++; 641 if (Count >= CurrentSize) { 642 DriverListPtr = AllocateCopyPool ((Count + UI_HII_DRIVER_LIST_SIZE) * sizeof (UI_HII_DRIVER_INSTANCE), gHiiDriverList); 643 ASSERT (DriverListPtr != NULL); 644 FreePool (gHiiDriverList); 645 gHiiDriverList = DriverListPtr; 646 CurrentSize += UI_HII_DRIVER_LIST_SIZE; 647 } 648 } 649 650 FreePool (HiiHandles); 651 652 Index = 0; 653 while (gHiiDriverList[Index].PromptId != 0) { 654 HiiCreateGotoExOpCode ( 655 StartOpCodeHandle, 656 0, 657 gHiiDriverList[Index].PromptId, 658 gHiiDriverList[Index].HelpId, 659 0, 660 (EFI_QUESTION_ID) (Index + FRONT_PAGE_KEY_DRIVER), 661 0, 662 &gHiiDriverList[Index].FormSetGuid, 663 gHiiDriverList[Index].DevicePathId 664 ); 665 666 if (gHiiDriverList[Index].EmptyLineAfter) { 667 UiCreateEmptyLine (HiiHandle, StartOpCodeHandle); 668 } 669 670 Index ++; 671 } 672 673 return EFI_SUCCESS; 674 } 675