Home | History | Annotate | Download | only in EfiIfrSupportLib
      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