1 /*++ 2 Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.<BR> 3 This program and the accompanying materials 4 are licensed and made available under the terms and conditions of the BSD License 5 which accompanies this distribution. The full text of the license may be found at 6 http://opensource.org/licenses/bsd-license.php 7 8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 11 Module Name: 12 IfrCommon.c 13 14 Abstract: 15 16 Common Library Routines to assist in IFR creation on-the-fly 17 18 --*/ 19 20 #include "IfrLibrary.h" 21 22 EFI_STATUS 23 GetCurrentLanguage ( 24 OUT CHAR16 *Lang 25 ) 26 /*++ 27 28 Routine Description: 29 30 Determine what is the current language setting 31 32 Arguments: 33 34 Lang - Pointer of system language 35 36 Returns: 37 38 Status code 39 40 --*/ 41 { 42 EFI_STATUS Status; 43 UINTN Size; 44 UINTN Index; 45 CHAR8 Language[4]; 46 47 // 48 // Getting the system language and placing it into our Global Data 49 // 50 Size = sizeof (Language); 51 52 Status = gRT->GetVariable ( 53 L"Lang", 54 &gEfiGlobalVariableGuid, 55 NULL, 56 &Size, 57 Language 58 ); 59 60 if (EFI_ERROR (Status)) { 61 EfiAsciiStrCpy (Language, (CHAR8 *) "eng"); 62 } 63 64 for (Index = 0; Index < 3; Index++) { 65 // 66 // Bitwise AND ascii value with 0xDF yields an uppercase value. 67 // Sign extend into a unicode value 68 // 69 Lang[Index] = (CHAR16) (Language[Index] & 0xDF); 70 } 71 72 // 73 // Null-terminate the value 74 // 75 Lang[3] = (CHAR16) 0; 76 77 return Status; 78 } 79 80 81 #ifdef SUPPORT_DEPRECATED_IFRSUPPORTLIB_API 82 EFI_STATUS 83 AddString ( 84 IN VOID *StringBuffer, 85 IN CHAR16 *Language, 86 IN CHAR16 *String, 87 IN OUT STRING_REF *StringToken 88 ) 89 /*++ 90 91 Routine Description: 92 93 Add a string to the incoming buffer and return the token and offset data 94 95 Arguments: 96 97 StringBuffer - The incoming buffer 98 99 Language - Currrent language 100 101 String - The string to be added 102 103 StringToken - The index where the string placed 104 105 Returns: 106 107 EFI_OUT_OF_RESOURCES - No enough buffer to allocate 108 109 EFI_SUCCESS - String successfully added to the incoming buffer 110 111 --*/ 112 { 113 EFI_HII_STRING_PACK *StringPack; 114 EFI_HII_STRING_PACK *StringPackBuffer; 115 VOID *NewBuffer; 116 RELOFST *PackSource; 117 RELOFST *PackDestination; 118 UINT8 *Source; 119 UINT8 *Destination; 120 UINTN Index; 121 BOOLEAN Finished; 122 UINTN SizeofLanguage; 123 UINTN SizeofString; 124 125 StringPack = (EFI_HII_STRING_PACK *) StringBuffer; 126 Finished = FALSE; 127 128 // 129 // Pre-allocate a buffer sufficient for us to work on. 130 // We will use it as a destination scratch pad to build data on 131 // and when complete shift the data back to the original buffer 132 // 133 NewBuffer = EfiLibAllocateZeroPool (DEFAULT_STRING_BUFFER_SIZE); 134 if (NewBuffer == NULL) { 135 return EFI_OUT_OF_RESOURCES; 136 } 137 138 StringPackBuffer = (EFI_HII_STRING_PACK *) NewBuffer; 139 140 // 141 // StringPack is terminated with a length 0 entry 142 // 143 for (; StringPack->Header.Length != 0;) { 144 // 145 // If this stringpack's language is same as CurrentLanguage, use it 146 // 147 if (EfiCompareMem ((VOID *) ((CHAR8 *) (StringPack) + StringPack->LanguageNameString), Language, 3) == 0) { 148 // 149 // We have some data in this string pack, copy the string package up to the string data 150 // 151 EfiCopyMem (&StringPackBuffer->Header, &StringPack->Header, sizeof (StringPack)); 152 153 // 154 // These are references in the structure to tokens, need to increase them by the space occupied by an additional StringPointer 155 // 156 StringPackBuffer->LanguageNameString = (UINT16) (StringPackBuffer->LanguageNameString + (UINT16) sizeof (RELOFST)); 157 StringPackBuffer->PrintableLanguageName = (UINT16) (StringPackBuffer->PrintableLanguageName + (UINT16) sizeof (RELOFST)); 158 159 PackSource = (RELOFST *) (StringPack + 1); 160 PackDestination = (RELOFST *) (StringPackBuffer + 1); 161 for (Index = 0; PackSource[Index] != 0x0000; Index++) { 162 // 163 // Copy the stringpointers from old to new buffer 164 // remember that we are adding a string, so the string offsets will all go up by sizeof (RELOFST) 165 // 166 PackDestination[Index] = (UINT16) (PackDestination[Index] + sizeof (RELOFST)); 167 } 168 169 // 170 // Add a new stringpointer in the new buffer since we are adding a string. Null terminate it 171 // 172 PackDestination[Index] = (UINT16)(PackDestination[Index-1] + 173 EfiStrSize((CHAR16 *)((CHAR8 *)(StringPack) + PackSource[Index-1]))); 174 PackDestination[Index + 1] = (UINT16) 0; 175 176 // 177 // Index is the token value for the new string 178 // 179 *StringToken = (UINT16) Index; 180 181 // 182 // Source now points to the beginning of the old buffer strings 183 // Destination now points to the beginning of the new buffer strings 184 // 185 Source = (UINT8 *) &PackSource[Index + 1]; 186 Destination = (UINT8 *) &PackDestination[Index + 2]; 187 188 // 189 // This should copy all the strings from the old buffer to the new buffer 190 // 191 for (; Index != 0; Index--) { 192 // 193 // Copy Source string to destination buffer 194 // 195 EfiStrCpy ((CHAR16 *) Destination, (CHAR16 *) Source); 196 197 // 198 // Adjust the source/destination to the next string location 199 // 200 Destination = Destination + EfiStrSize ((CHAR16 *) Source); 201 Source = Source + EfiStrSize ((CHAR16 *) Source); 202 } 203 204 // 205 // This copies the new string to the destination buffer 206 // 207 EfiStrCpy ((CHAR16 *) Destination, (CHAR16 *) String); 208 209 // 210 // Adjust the size of the changed string pack by adding the size of the new string 211 // along with the size of the additional offset entry for the new string 212 // 213 StringPackBuffer->Header.Length = (UINT32) ((UINTN) StringPackBuffer->Header.Length + EfiStrSize (String) + sizeof (RELOFST)); 214 215 // 216 // Advance the buffers to point to the next spots. 217 // 218 StringPackBuffer = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPackBuffer->Header.Length); 219 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length); 220 Finished = TRUE; 221 continue; 222 } 223 // 224 // This isn't the language of the stringpack we were asked to add a string to 225 // so we need to copy it to the new buffer. 226 // 227 EfiCopyMem (&StringPackBuffer->Header, &StringPack->Header, StringPack->Header.Length); 228 229 // 230 // Advance the buffers to point to the next spots. 231 // 232 StringPackBuffer = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPack->Header.Length); 233 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length); 234 } 235 236 // 237 // If we didn't copy the new data to a stringpack yet 238 // 239 if (!Finished) { 240 PackDestination = (RELOFST *) (StringPackBuffer + 1); 241 // 242 // Pointing to a new string pack location 243 // 244 SizeofLanguage = EfiStrSize (Language); 245 SizeofString = EfiStrSize (String); 246 StringPackBuffer->Header.Length = (UINT32) 247 ( 248 sizeof (EFI_HII_STRING_PACK) - 249 sizeof (EFI_STRING) + 250 sizeof (RELOFST) + 251 sizeof (RELOFST) + 252 SizeofLanguage + 253 SizeofString 254 ); 255 StringPackBuffer->Header.Type = EFI_HII_STRING; 256 StringPackBuffer->LanguageNameString = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer); 257 StringPackBuffer->PrintableLanguageName = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer); 258 StringPackBuffer->Attributes = 0; 259 PackDestination[0] = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer); 260 PackDestination[1] = (UINT16) (PackDestination[0] + EfiStrSize (Language)); 261 PackDestination[2] = (UINT16) 0; 262 263 // 264 // The first string location will be set to destination. The minimum number of strings 265 // associated with a stringpack will always be token 0 stored as the languagename (e.g. ENG, SPA, etc) 266 // and token 1 as the new string being added and and null entry for the stringpointers 267 // 268 Destination = (CHAR8 *) &PackDestination[3]; 269 270 // 271 // Copy the language name string to the new buffer 272 // 273 EfiStrCpy ((CHAR16 *) Destination, Language); 274 275 // 276 // Advance the destination to the new empty spot 277 // 278 Destination = Destination + EfiStrSize (Language); 279 280 // 281 // Copy the string to the new buffer 282 // 283 EfiStrCpy ((CHAR16 *) Destination, String); 284 285 // 286 // Since we are starting with a new string pack - we know the new string is token 1 287 // 288 *StringToken = (UINT16) 1; 289 } 290 291 // 292 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer 293 // 294 EfiZeroMem (StringBuffer, DEFAULT_STRING_BUFFER_SIZE); 295 EfiCopyMem (StringBuffer, NewBuffer, DEFAULT_STRING_BUFFER_SIZE); 296 297 // 298 // Free the newly created buffer since we don't need it anymore 299 // 300 gBS->FreePool (NewBuffer); 301 return EFI_SUCCESS; 302 } 303 304 305 EFI_STATUS 306 AddOpCode ( 307 IN VOID *FormBuffer, 308 IN OUT VOID *OpCodeData 309 ) 310 /*++ 311 312 Routine Description: 313 314 Add op-code data to the FormBuffer 315 316 Arguments: 317 318 FormBuffer - Form buffer to be inserted to 319 320 OpCodeData - Op-code data to be inserted 321 322 Returns: 323 324 EFI_OUT_OF_RESOURCES - No enough buffer to allocate 325 326 EFI_SUCCESS - Op-code data successfully inserted 327 328 --*/ 329 { 330 EFI_HII_PACK_HEADER *NewBuffer; 331 UINT8 *Source; 332 UINT8 *Destination; 333 334 // 335 // Pre-allocate a buffer sufficient for us to work on. 336 // We will use it as a destination scratch pad to build data on 337 // and when complete shift the data back to the original buffer 338 // 339 NewBuffer = EfiLibAllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE); 340 if (NewBuffer == NULL) { 341 return EFI_OUT_OF_RESOURCES; 342 } 343 344 Source = (UINT8 *) FormBuffer; 345 Destination = (UINT8 *) NewBuffer; 346 347 // 348 // Copy the IFR Package header to the new buffer 349 // 350 EfiCopyMem (Destination, Source, sizeof (EFI_HII_PACK_HEADER)); 351 352 // 353 // Advance Source and Destination to next op-code 354 // 355 Source = Source + sizeof (EFI_HII_PACK_HEADER); 356 Destination = Destination + sizeof (EFI_HII_PACK_HEADER); 357 358 // 359 // Copy data to the new buffer until we run into the end_form 360 // 361 for (; ((EFI_IFR_OP_HEADER *) Source)->OpCode != EFI_IFR_END_FORM_OP;) { 362 // 363 // If the this opcode is an end_form_set we better be creating and endform 364 // Nonetheless, we will add data before the end_form_set. This also provides 365 // for interesting behavior in the code we will run, but has no bad side-effects 366 // since we will possibly do a 0 byte copy in this particular end-case. 367 // 368 if (((EFI_IFR_OP_HEADER *) Source)->OpCode == EFI_IFR_END_FORM_SET_OP) { 369 break; 370 } 371 372 // 373 // Copy data to new buffer 374 // 375 EfiCopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length); 376 377 // 378 // Adjust Source/Destination to next op-code location 379 // 380 Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; 381 Source = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; 382 } 383 384 // 385 // Prior to the end_form is where we insert the new op-code data 386 // 387 EfiCopyMem (Destination, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length); 388 Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; 389 390 NewBuffer->Length = (UINT32) (NewBuffer->Length + (UINT32) (((EFI_IFR_OP_HEADER *) OpCodeData)->Length)); 391 392 // 393 // Copy end-form data to new buffer 394 // 395 EfiCopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length); 396 397 // 398 // Adjust Source/Destination to next op-code location 399 // 400 Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; 401 Source = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length; 402 403 // 404 // Copy end-formset data to new buffer 405 // 406 EfiCopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length); 407 408 // 409 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer 410 // 411 EfiZeroMem (FormBuffer, DEFAULT_FORM_BUFFER_SIZE); 412 EfiCopyMem (FormBuffer, NewBuffer, DEFAULT_FORM_BUFFER_SIZE); 413 414 // 415 // Free the newly created buffer since we don't need it anymore 416 // 417 gBS->FreePool (NewBuffer); 418 return EFI_SUCCESS; 419 } 420 #endif 421 422 423 EFI_STATUS 424 GetHiiInterface ( 425 OUT EFI_HII_PROTOCOL **Hii 426 ) 427 /*++ 428 429 Routine Description: 430 431 Get the HII protocol interface 432 433 Arguments: 434 435 Hii - HII protocol interface 436 437 Returns: 438 439 Status code 440 441 --*/ 442 { 443 EFI_STATUS Status; 444 445 // 446 // There should only be one HII protocol 447 // 448 Status = gBS->LocateProtocol ( 449 &gEfiHiiProtocolGuid, 450 NULL, 451 (VOID **) Hii 452 ); 453 454 return Status;; 455 } 456 457 458 EFI_STATUS 459 ExtractDataFromHiiHandle ( 460 IN EFI_HII_HANDLE HiiHandle, 461 IN OUT UINT16 *ImageLength, 462 OUT UINT8 *DefaultImage, 463 OUT EFI_GUID *Guid 464 ) 465 /*++ 466 467 Routine Description: 468 469 Extract information pertaining to the HiiHandle 470 471 Arguments: 472 473 HiiHandle - Hii handle 474 475 ImageLength - For input, length of DefaultImage; 476 For output, length of actually required 477 478 DefaultImage - Image buffer prepared by caller 479 480 Guid - Guid information about the form 481 482 Returns: 483 484 EFI_OUT_OF_RESOURCES - No enough buffer to allocate 485 486 EFI_BUFFER_TOO_SMALL - DefualtImage has no enough ImageLength 487 488 EFI_SUCCESS - Successfully extract data from Hii database. 489 490 491 --*/ 492 { 493 EFI_STATUS Status; 494 EFI_HII_PROTOCOL *Hii; 495 UINTN DataLength; 496 UINT8 *RawData; 497 UINT8 *OldData; 498 UINTN Index; 499 UINTN Temp; 500 UINTN SizeOfNvStore; 501 UINTN CachedStart; 502 503 DataLength = DEFAULT_FORM_BUFFER_SIZE; 504 SizeOfNvStore = 0; 505 CachedStart = 0; 506 507 Status = GetHiiInterface (&Hii); 508 509 if (EFI_ERROR (Status)) { 510 return Status; 511 } 512 513 // 514 // Allocate space for retrieval of IFR data 515 // 516 RawData = EfiLibAllocateZeroPool ((UINTN) DataLength); 517 if (RawData == NULL) { 518 return EFI_OUT_OF_RESOURCES; 519 } 520 521 // 522 // Get all the forms associated with this HiiHandle 523 // 524 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData); 525 526 if (EFI_ERROR (Status)) { 527 gBS->FreePool (RawData); 528 529 // 530 // Allocate space for retrieval of IFR data 531 // 532 RawData = EfiLibAllocateZeroPool ((UINTN) DataLength); 533 if (RawData == NULL) { 534 return EFI_OUT_OF_RESOURCES; 535 } 536 537 // 538 // Get all the forms associated with this HiiHandle 539 // 540 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData); 541 } 542 543 OldData = RawData; 544 545 // 546 // Point RawData to the beginning of the form data 547 // 548 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER)); 549 550 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { 551 switch (RawData[Index]) { 552 case EFI_IFR_FORM_SET_OP: 553 // 554 // Copy the GUID information from this handle 555 // 556 EfiCopyMem (Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID)); 557 break; 558 559 case EFI_IFR_ONE_OF_OP: 560 case EFI_IFR_CHECKBOX_OP: 561 case EFI_IFR_NUMERIC_OP: 562 case EFI_IFR_DATE_OP: 563 case EFI_IFR_TIME_OP: 564 case EFI_IFR_PASSWORD_OP: 565 case EFI_IFR_STRING_OP: 566 // 567 // Remember, multiple op-codes may reference the same item, so let's keep a running 568 // marker of what the highest QuestionId that wasn't zero length. This will accurately 569 // maintain the Size of the NvStore 570 // 571 if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) { 572 Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; 573 if (SizeOfNvStore < Temp) { 574 SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; 575 } 576 } 577 } 578 579 Index = RawData[Index + 1] + Index; 580 } 581 582 // 583 // Return an error if buffer is too small 584 // 585 if (SizeOfNvStore > *ImageLength || DefaultImage == NULL) { 586 gBS->FreePool (OldData); 587 *ImageLength = (UINT16) SizeOfNvStore; 588 return EFI_BUFFER_TOO_SMALL; 589 } 590 591 EfiZeroMem (DefaultImage, SizeOfNvStore); 592 593 // 594 // Copy the default image information to the user's buffer 595 // 596 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { 597 switch (RawData[Index]) { 598 case EFI_IFR_ONE_OF_OP: 599 CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId; 600 break; 601 602 case EFI_IFR_ONE_OF_OPTION_OP: 603 if (((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Flags & EFI_IFR_FLAG_DEFAULT) { 604 EfiCopyMem (&DefaultImage[CachedStart], &((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value, 2); 605 } 606 break; 607 608 case EFI_IFR_CHECKBOX_OP: 609 DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId] = ((EFI_IFR_CHECK_BOX *) &RawData[Index])->Flags; 610 break; 611 612 case EFI_IFR_NUMERIC_OP: 613 EfiCopyMem ( 614 &DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId], 615 &((EFI_IFR_NUMERIC *) &RawData[Index])->Default, 616 2 617 ); 618 break; 619 620 } 621 622 Index = RawData[Index + 1] + Index; 623 } 624 625 *ImageLength = (UINT16) SizeOfNvStore; 626 627 // 628 // Free our temporary repository of form data 629 // 630 gBS->FreePool (OldData); 631 632 return EFI_SUCCESS; 633 } 634 635 636 EFI_HII_HANDLE 637 FindHiiHandle ( 638 IN OUT EFI_HII_PROTOCOL **HiiProtocol, OPTIONAL 639 IN EFI_GUID *Guid 640 ) 641 /*++ 642 643 Routine Description: 644 Finds HII handle for given pack GUID previously registered with the HII. 645 646 Arguments: 647 HiiProtocol - pointer to pointer to HII protocol interface. 648 If NULL, the interface will be found but not returned. 649 If it points to NULL, the interface will be found and 650 written back to the pointer that is pointed to. 651 Guid - The GUID of the pack that registered with the HII. 652 653 Returns: 654 Handle to the HII pack previously registered by the memory driver. 655 656 --*/ 657 { 658 EFI_STATUS Status; 659 660 EFI_HII_HANDLE *HiiHandleBuffer; 661 EFI_HII_HANDLE HiiHandle; 662 UINT16 HiiHandleBufferLength; 663 UINT32 NumberOfHiiHandles; 664 EFI_GUID HiiGuid; 665 EFI_HII_PROTOCOL *HiiProt; 666 UINT32 Index; 667 UINT16 Length; 668 669 HiiHandle = 0; 670 if ((HiiProtocol != NULL) && (*HiiProtocol != NULL)) { 671 // 672 // The protocol has been passed in 673 // 674 HiiProt = *HiiProtocol; 675 } else { 676 gBS->LocateProtocol ( 677 &gEfiHiiProtocolGuid, 678 NULL, 679 (VOID **) &HiiProt 680 ); 681 if (HiiProt == NULL) { 682 return HiiHandle; 683 } 684 685 if (HiiProtocol != NULL) { 686 // 687 // Return back the HII protocol for the caller as promissed 688 // 689 *HiiProtocol = HiiProt; 690 } 691 } 692 // 693 // Allocate buffer 694 // 695 HiiHandleBufferLength = 10; 696 HiiHandleBuffer = EfiLibAllocatePool (HiiHandleBufferLength); 697 ASSERT (HiiHandleBuffer != NULL); 698 699 // 700 // Get the Handles of the packages that were registered with Hii 701 // 702 Status = HiiProt->FindHandles ( 703 HiiProt, 704 &HiiHandleBufferLength, 705 HiiHandleBuffer 706 ); 707 708 // 709 // Get a bigger bugffer if this one is to small, and try again 710 // 711 if (Status == EFI_BUFFER_TOO_SMALL) { 712 713 gBS->FreePool (HiiHandleBuffer); 714 715 HiiHandleBuffer = EfiLibAllocatePool (HiiHandleBufferLength); 716 ASSERT (HiiHandleBuffer != NULL); 717 718 Status = HiiProt->FindHandles ( 719 HiiProt, 720 &HiiHandleBufferLength, 721 HiiHandleBuffer 722 ); 723 } 724 725 if (EFI_ERROR (Status)) { 726 goto lbl_exit; 727 } 728 729 NumberOfHiiHandles = HiiHandleBufferLength / sizeof (EFI_HII_HANDLE); 730 731 // 732 // Iterate Hii handles and look for the one that matches our Guid 733 // 734 for (Index = 0; Index < NumberOfHiiHandles; Index++) { 735 736 Length = 0; 737 ExtractDataFromHiiHandle (HiiHandleBuffer[Index], &Length, NULL, &HiiGuid); 738 739 if (EfiCompareGuid (&HiiGuid, Guid)) { 740 741 HiiHandle = HiiHandleBuffer[Index]; 742 break; 743 } 744 } 745 746 lbl_exit: 747 gBS->FreePool (HiiHandleBuffer); 748 return HiiHandle; 749 } 750 751 #ifdef SUPPORT_DEPRECATED_IFRSUPPORTLIB_API 752 EFI_STATUS 753 ValidateDataFromHiiHandle ( 754 IN EFI_HII_HANDLE HiiHandle, 755 OUT BOOLEAN *Results 756 ) 757 /*++ 758 759 Routine Description: 760 761 Validate that the data associated with the HiiHandle in NVRAM is within 762 the reasonable parameters for that FormSet. Values for strings and passwords 763 are not verified due to their not having the equivalent of valid range settings. 764 765 Arguments: 766 767 HiiHandle - Handle of the HII database entry to query 768 769 Results - If return Status is EFI_SUCCESS, Results provides valid data 770 TRUE = NVRAM Data is within parameters 771 FALSE = NVRAM Data is NOT within parameters 772 773 Returns: 774 775 EFI_OUT_OF_RESOURCES - No enough buffer to allocate 776 777 EFI_SUCCESS - Data successfully validated 778 --*/ 779 { 780 EFI_STATUS Status; 781 EFI_HII_PROTOCOL *Hii; 782 EFI_GUID Guid; 783 UINT8 *RawData; 784 UINT8 *OldData; 785 UINTN RawDataLength; 786 UINT8 *VariableData; 787 UINTN Index; 788 UINTN Temp; 789 UINTN SizeOfNvStore; 790 UINTN CachedStart; 791 BOOLEAN GotMatch; 792 793 RawDataLength = DEFAULT_FORM_BUFFER_SIZE; 794 SizeOfNvStore = 0; 795 CachedStart = 0; 796 GotMatch = FALSE; 797 *Results = TRUE; 798 799 Status = GetHiiInterface (&Hii); 800 801 if (EFI_ERROR (Status)) { 802 return Status; 803 } 804 805 // 806 // Allocate space for retrieval of IFR data 807 // 808 RawData = EfiLibAllocateZeroPool (RawDataLength); 809 if (RawData == NULL) { 810 return EFI_OUT_OF_RESOURCES; 811 } 812 813 // 814 // Get all the forms associated with this HiiHandle 815 // 816 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData); 817 818 if (EFI_ERROR (Status)) { 819 gBS->FreePool (RawData); 820 821 // 822 // Allocate space for retrieval of IFR data 823 // 824 RawData = EfiLibAllocateZeroPool (RawDataLength); 825 if (RawData == NULL) { 826 return EFI_OUT_OF_RESOURCES; 827 } 828 829 // 830 // Get all the forms associated with this HiiHandle 831 // 832 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData); 833 } 834 835 OldData = RawData; 836 837 // 838 // Point RawData to the beginning of the form data 839 // 840 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER)); 841 842 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { 843 if (RawData[Index] == EFI_IFR_FORM_SET_OP) { 844 EfiCopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID)); 845 break; 846 } 847 848 Index = RawData[Index + 1] + Index; 849 } 850 851 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { 852 switch (RawData[Index]) { 853 case EFI_IFR_FORM_SET_OP: 854 break; 855 856 case EFI_IFR_ONE_OF_OP: 857 case EFI_IFR_CHECKBOX_OP: 858 case EFI_IFR_NUMERIC_OP: 859 case EFI_IFR_DATE_OP: 860 case EFI_IFR_TIME_OP: 861 case EFI_IFR_PASSWORD_OP: 862 case EFI_IFR_STRING_OP: 863 // 864 // Remember, multiple op-codes may reference the same item, so let's keep a running 865 // marker of what the highest QuestionId that wasn't zero length. This will accurately 866 // maintain the Size of the NvStore 867 // 868 if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) { 869 Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; 870 if (SizeOfNvStore < Temp) { 871 SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width; 872 } 873 } 874 } 875 876 Index = RawData[Index + 1] + Index; 877 } 878 879 // 880 // Allocate memory for our File Form Tags 881 // 882 VariableData = EfiLibAllocateZeroPool (SizeOfNvStore); 883 if (VariableData == NULL) { 884 return EFI_OUT_OF_RESOURCES; 885 } 886 887 Status = gRT->GetVariable ( 888 L"Setup", 889 &Guid, 890 NULL, 891 &SizeOfNvStore, 892 (VOID *) VariableData 893 ); 894 895 if (EFI_ERROR (Status)) { 896 897 // 898 // If there is a variable that exists already and it is larger than what we calculated the 899 // storage needs to be, we must assume the variable size from GetVariable is correct and not 900 // allow the truncation of the variable. It is very possible that the user who created the IFR 901 // we are cracking is not referring to a variable that was in a previous map, however we cannot 902 // allow it's truncation. 903 // 904 if (Status == EFI_BUFFER_TOO_SMALL) { 905 // 906 // Free the buffer that was allocated that was too small 907 // 908 gBS->FreePool (VariableData); 909 910 VariableData = EfiLibAllocatePool (SizeOfNvStore); 911 if (VariableData == NULL) { 912 return EFI_OUT_OF_RESOURCES; 913 } 914 915 Status = gRT->GetVariable ( 916 L"Setup", 917 &Guid, 918 NULL, 919 &SizeOfNvStore, 920 (VOID *) VariableData 921 ); 922 } 923 } 924 925 // 926 // Walk through the form and see that the variable data it refers to is ok. 927 // This allows for the possibility of stale (obsoleted) data in the variable 928 // can be overlooked without causing an error 929 // 930 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) { 931 switch (RawData[Index]) { 932 case EFI_IFR_ONE_OF_OP: 933 // 934 // A one_of has no data, its the option that does - cache the storage Id 935 // 936 CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId; 937 break; 938 939 case EFI_IFR_ONE_OF_OPTION_OP: 940 // 941 // A one_of_option can be any value 942 // 943 if (VariableData[CachedStart] == ((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value) { 944 GotMatch = TRUE; 945 } 946 break; 947 948 case EFI_IFR_END_ONE_OF_OP: 949 // 950 // At this point lets make sure that the data value in the NVRAM matches one of the options 951 // 952 if (!GotMatch) { 953 *Results = FALSE; 954 return EFI_SUCCESS; 955 } 956 break; 957 958 case EFI_IFR_CHECKBOX_OP: 959 // 960 // A checkbox is a boolean, so 0 and 1 are valid 961 // Remember, QuestionId corresponds to the offset location of the data in the variable 962 // 963 if (VariableData[((EFI_IFR_CHECK_BOX *) &RawData[Index])->QuestionId] > 1) { 964 *Results = FALSE; 965 return EFI_SUCCESS; 966 } 967 break; 968 969 case EFI_IFR_NUMERIC_OP: 970 if ((VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] < ((EFI_IFR_NUMERIC *)&RawData[Index])->Minimum) || 971 (VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] > ((EFI_IFR_NUMERIC *)&RawData[Index])->Maximum)) { 972 *Results = FALSE; 973 return EFI_SUCCESS; 974 } 975 break; 976 977 } 978 979 Index = RawData[Index + 1] + Index; 980 } 981 982 // 983 // Free our temporary repository of form data 984 // 985 gBS->FreePool (OldData); 986 gBS->FreePool (VariableData); 987 988 return EFI_SUCCESS; 989 } 990 #endif 991 992 EFI_HII_PACKAGES * 993 PreparePackages ( 994 IN UINTN NumberOfPackages, 995 IN EFI_GUID *GuidId, 996 ... 997 ) 998 /*++ 999 1000 Routine Description: 1001 1002 Assemble EFI_HII_PACKAGES according to the passed in packages. 1003 1004 Arguments: 1005 1006 NumberOfPackages - Number of packages. 1007 GuidId - Package GUID. 1008 1009 Returns: 1010 1011 Pointer of EFI_HII_PACKAGES. 1012 1013 --*/ 1014 { 1015 VA_LIST args; 1016 EFI_HII_PACKAGES *HiiPackages; 1017 VOID **Package; 1018 UINTN Index; 1019 1020 ASSERT (NumberOfPackages > 0); 1021 1022 HiiPackages = EfiLibAllocateZeroPool (sizeof (EFI_HII_PACKAGES) + NumberOfPackages * sizeof (VOID *)); 1023 1024 HiiPackages->GuidId = GuidId; 1025 HiiPackages->NumberOfPackages = NumberOfPackages; 1026 Package = (VOID **) (((UINT8 *) HiiPackages) + sizeof (EFI_HII_PACKAGES)); 1027 1028 VA_START (args, GuidId); 1029 1030 for (Index = 0; Index < NumberOfPackages; Index++) { 1031 *Package = VA_ARG (args, VOID *); 1032 Package++; 1033 } 1034 1035 VA_END (args); 1036 1037 return HiiPackages; 1038 } 1039