Home | History | Annotate | Download | only in UefiEfiIfrSupportLib
      1 /*++
      2 
      3 Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   UefiIfrForm.c
     15 
     16 Abstract:
     17 
     18   Common Library Routines to assist handle HII elements.
     19 
     20 --*/
     21 
     22 #include "UefiIfrLibrary.h"
     23 
     24 //
     25 // Fake <ConfigHdr>
     26 //
     27 UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0";
     28 
     29 EFI_STATUS
     30 GetPackageDataFromPackageList (
     31   IN  EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
     32   IN  UINT32                      PackageIndex,
     33   OUT UINT32                      *BufferLen,
     34   OUT EFI_HII_PACKAGE_HEADER      **Buffer
     35   )
     36 {
     37   UINT32                        Index;
     38   EFI_HII_PACKAGE_HEADER        *Package;
     39   UINT32                        Offset;
     40   UINT32                        PackageListLength;
     41   EFI_HII_PACKAGE_HEADER        PackageHeader = {0, 0};
     42 
     43   ASSERT(HiiPackageList != NULL);
     44 
     45   if ((BufferLen == NULL) || (Buffer == NULL)) {
     46     return EFI_INVALID_PARAMETER;
     47   }
     48 
     49   Package = NULL;
     50   Index   = 0;
     51   Offset  = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
     52   EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
     53   while (Offset < PackageListLength) {
     54     Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
     55     EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
     56     if (Index == PackageIndex) {
     57       break;
     58     }
     59     Offset += PackageHeader.Length;
     60     Index++;
     61   }
     62   if (Offset >= PackageListLength) {
     63     //
     64     // no package found in this Package List
     65     //
     66     return EFI_NOT_FOUND;
     67   }
     68 
     69   *BufferLen = PackageHeader.Length;
     70   *Buffer    = Package;
     71   return EFI_SUCCESS;
     72 }
     73 
     74 EFI_STATUS
     75 UpdateFormPackageData (
     76   IN  EFI_GUID               *FormSetGuid,
     77   IN  EFI_FORM_ID            FormId,
     78   IN  EFI_HII_PACKAGE_HEADER *Package,
     79   IN  UINT32                 PackageLength,
     80   IN  UINT16                 Label,
     81   IN  BOOLEAN                Insert,
     82   IN  EFI_HII_UPDATE_DATA    *Data,
     83   OUT UINT8                  **TempBuffer,
     84   OUT UINT32                 *TempBufferSize
     85   )
     86 {
     87   UINT8                     *BufferPos;
     88   EFI_HII_PACKAGE_HEADER    PackageHeader;
     89   UINT32                    Offset;
     90   EFI_IFR_OP_HEADER         *IfrOpHdr;
     91   BOOLEAN                   GetFormSet;
     92   BOOLEAN                   GetForm;
     93   UINT8                     ExtendOpCode;
     94   UINT16                    LabelNumber;
     95   BOOLEAN                   Updated;
     96 
     97   if ((TempBuffer == NULL) || (TempBufferSize == NULL)) {
     98     return EFI_INVALID_PARAMETER;
     99   }
    100 
    101   *TempBufferSize = PackageLength;
    102   if (Data != NULL) {
    103     *TempBufferSize += Data->Offset;
    104   }
    105   *TempBuffer = EfiLibAllocateZeroPool (*TempBufferSize);
    106   if (*TempBuffer == NULL) {
    107     return EFI_OUT_OF_RESOURCES;
    108   }
    109 
    110   EfiCopyMem (*TempBuffer, Package, sizeof (EFI_HII_PACKAGE_HEADER));
    111   *TempBufferSize = sizeof (EFI_HII_PACKAGE_HEADER);
    112   BufferPos = *TempBuffer + sizeof (EFI_HII_PACKAGE_HEADER);
    113 
    114   EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
    115   IfrOpHdr   = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
    116   Offset     = sizeof (EFI_HII_PACKAGE_HEADER);
    117   GetFormSet = (BOOLEAN)((FormSetGuid == NULL) ? TRUE : FALSE);
    118   GetForm    = FALSE;
    119   Updated    = FALSE;
    120 
    121   while (!Updated && Offset < PackageHeader.Length) {
    122     EfiCopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
    123     BufferPos += IfrOpHdr->Length;
    124     *TempBufferSize += IfrOpHdr->Length;
    125 
    126     switch (IfrOpHdr->OpCode) {
    127     case EFI_IFR_FORM_SET_OP :
    128       if (FormSetGuid != NULL) {
    129         if (EfiCompareMem (&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid, sizeof (EFI_GUID)) == 0) {
    130           GetFormSet = TRUE;
    131         } else {
    132           GetFormSet = FALSE;
    133         }
    134       }
    135       break;
    136 
    137     case EFI_IFR_FORM_OP:
    138       if (EfiCompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
    139         GetForm = TRUE;
    140       } else {
    141         GetForm = FALSE;
    142       }
    143       break;
    144 
    145     case EFI_IFR_GUID_OP :
    146       if (!GetFormSet || !GetForm) {
    147         //
    148         // Go to the next Op-Code
    149         //
    150         break;
    151       }
    152 
    153       if (!EfiCompareGuid (&((EFI_IFR_GUID *) IfrOpHdr)->Guid, &mIfrVendorGuid)) {
    154         //
    155         // GUID mismatch, skip this op-code
    156         //
    157         break;
    158       }
    159 
    160       ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;
    161       EfiCopyMem (&LabelNumber, &((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Number, sizeof (UINT16));
    162       if ((ExtendOpCode != EFI_IFR_EXTEND_OP_LABEL) || (LabelNumber != Label)) {
    163         //
    164         // Go to the next Op-Code
    165         //
    166         break;
    167       }
    168 
    169       if (Insert) {
    170         //
    171         // Insert data after current Label, skip myself
    172         //
    173         Offset   += IfrOpHdr->Length;
    174         IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
    175       } else {
    176         //
    177         // Replace data between two paired Label, try to find the next Label.
    178         //
    179         while (TRUE) {
    180           Offset   += IfrOpHdr->Length;
    181           //
    182           // Search the next label and Fail if not label found.
    183           //
    184           if (Offset >= PackageHeader.Length) {
    185             goto Fail;
    186           }
    187           IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
    188           if (IfrOpHdr->OpCode == EFI_IFR_GUID_OP) {
    189             ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;
    190             if (EfiCompareGuid (&((EFI_IFR_GUID *) IfrOpHdr)->Guid, &mIfrVendorGuid) && ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) {
    191               break;
    192             }
    193           }
    194         }
    195       }
    196 
    197       //
    198       // Fill in the update data
    199       //
    200       if (Data != NULL) {
    201         EfiCopyMem (BufferPos, Data->Data, Data->Offset);
    202         BufferPos += Data->Offset;
    203         *TempBufferSize += Data->Offset;
    204       }
    205 
    206       //
    207       // Copy the reset data
    208       //
    209       EfiCopyMem (BufferPos, IfrOpHdr, PackageHeader.Length - Offset);
    210       *TempBufferSize += PackageHeader.Length - Offset;
    211 
    212       Updated = TRUE;
    213       break;
    214     default :
    215       break;
    216     }
    217 
    218     //
    219     // Go to the next Op-Code
    220     //
    221     Offset   += IfrOpHdr->Length;
    222     IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
    223   }
    224 
    225   //
    226   // Update the package length.
    227   //
    228   PackageHeader.Length = *TempBufferSize;
    229   EfiCopyMem (*TempBuffer, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
    230 
    231 Fail:
    232   if (!Updated) {
    233     gBS->FreePool (*TempBuffer);
    234     *TempBufferSize = 0;
    235     return EFI_NOT_FOUND;
    236   }
    237 
    238   return EFI_SUCCESS;
    239 }
    240 
    241 EFI_STATUS
    242 IfrLibInitUpdateData (
    243   IN OUT EFI_HII_UPDATE_DATA   *UpdateData,
    244   IN UINT32                    BufferSize
    245   )
    246 /*++
    247 
    248 Routine Description:
    249   This function initialize the data structure for dynamic opcode.
    250 
    251 Arguments:
    252   UpdateData     - The adding data;
    253   BufferSize     - Length of the buffer to fill dynamic opcodes.
    254 
    255 Returns:
    256   EFI_SUCCESS           - Update data is initialized.
    257   EFI_INVALID_PARAMETER - UpdateData is NULL.
    258   EFI_OUT_OF_RESOURCES  - No enough memory to allocate.
    259 
    260 --*/
    261 {
    262   if (UpdateData == NULL) {
    263     return EFI_INVALID_PARAMETER;
    264   }
    265 
    266   UpdateData->BufferSize = BufferSize;
    267   UpdateData->Offset = 0;
    268   UpdateData->Data = EfiLibAllocatePool (BufferSize);
    269 
    270   return (UpdateData->Data != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
    271 }
    272 
    273 EFI_STATUS
    274 IfrLibFreeUpdateData (
    275   IN EFI_HII_UPDATE_DATA       *UpdateData
    276   )
    277 /*++
    278 
    279 Routine Description:
    280   This function free the resource of update data.
    281 
    282 Arguments:
    283   UpdateData     - The adding data;
    284 
    285 Returns:
    286   EFI_SUCCESS           - Resource in UpdateData is released.
    287   EFI_INVALID_PARAMETER - UpdateData is NULL.
    288 
    289 --*/
    290 {
    291   EFI_STATUS  Status;
    292 
    293   if (UpdateData == NULL) {
    294     return EFI_INVALID_PARAMETER;
    295   }
    296 
    297   Status = gBS->FreePool (UpdateData->Data);
    298   UpdateData->Data = NULL;
    299 
    300   return Status;
    301 }
    302 
    303 EFI_STATUS
    304 IfrLibUpdateForm (
    305   IN EFI_HII_HANDLE            Handle,
    306   IN EFI_GUID                  *FormSetGuid, OPTIONAL
    307   IN EFI_FORM_ID               FormId,
    308   IN UINT16                    Label,
    309   IN BOOLEAN                   Insert,
    310   IN EFI_HII_UPDATE_DATA       *Data
    311   )
    312 /*++
    313 
    314 Routine Description:
    315   This function allows the caller to update a form that has
    316   previously been registered with the EFI HII database.
    317 
    318 Arguments:
    319   Handle       - Hii Handle
    320   FormSetGuid  - The formset should be updated.
    321   FormId       - The form should be updated.
    322   Label        - Update information starting immediately after this label in the IFR
    323   Insert       - If TRUE and Data is not NULL, insert data after Label.
    324                  If FALSE, replace opcodes between two labels with Data
    325   Data         - The adding data; If NULL, remove opcodes between two Label.
    326 
    327 Returns:
    328   EFI_SUCCESS  - Update success.
    329   Other        - Update fail.
    330 
    331 --*/
    332 {
    333   EFI_STATUS                   Status;
    334   EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
    335   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
    336   UINT32                       Index;
    337   EFI_HII_PACKAGE_LIST_HEADER  *UpdateBuffer;
    338   UINTN                        BufferSize;
    339   UINT8                        *UpdateBufferPos;
    340   EFI_HII_PACKAGE_HEADER       PackageHeader;
    341   EFI_HII_PACKAGE_HEADER       *Package;
    342   UINT32                       PackageLength;
    343   EFI_HII_PACKAGE_HEADER       *TempBuffer;
    344   UINT32                       TempBufferSize;
    345   BOOLEAN                      Updated;
    346 
    347   if (Data == NULL) {
    348     return EFI_INVALID_PARAMETER;
    349   }
    350 
    351   LocateHiiProtocols ();
    352   HiiDatabase = gIfrLibHiiDatabase;
    353 
    354   //
    355   // Get the orginal package list
    356   //
    357   BufferSize = 0;
    358   HiiPackageList   = NULL;
    359   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
    360   if (Status == EFI_BUFFER_TOO_SMALL) {
    361     HiiPackageList = EfiLibAllocatePool (BufferSize);
    362     ASSERT (HiiPackageList != NULL);
    363 
    364     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
    365     if (EFI_ERROR (Status)) {
    366       gBS->FreePool (HiiPackageList);
    367       return Status;
    368     }
    369   }
    370 
    371   //
    372   // Calculate and allocate space for retrieval of IFR data
    373   //
    374   BufferSize += Data->Offset;
    375   UpdateBuffer = EfiLibAllocateZeroPool (BufferSize);
    376   if (UpdateBuffer == NULL) {
    377     return EFI_OUT_OF_RESOURCES;
    378   }
    379 
    380   UpdateBufferPos = (UINT8 *) UpdateBuffer;
    381 
    382   //
    383   // copy the package list header
    384   //
    385   EfiCopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
    386   UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
    387 
    388   Updated = FALSE;
    389   for (Index = 0; ; Index++) {
    390     Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);
    391     if (Status == EFI_SUCCESS) {
    392       EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
    393       if ((PackageHeader.Type == EFI_HII_PACKAGE_FORMS) && !Updated) {
    394         Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);
    395         if (!EFI_ERROR(Status)) {
    396           if (FormSetGuid == NULL) {
    397             Updated = TRUE;
    398           }
    399           EfiCopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);
    400           UpdateBufferPos += TempBufferSize;
    401           gBS->FreePool (TempBuffer);
    402           continue;
    403         }
    404       }
    405 
    406       EfiCopyMem (UpdateBufferPos, Package, PackageLength);
    407       UpdateBufferPos += PackageLength;
    408     } else if (Status == EFI_NOT_FOUND) {
    409       break;
    410     } else {
    411       gBS->FreePool (HiiPackageList);
    412       return Status;
    413     }
    414   }
    415 
    416   //
    417   // Update package list length
    418   //
    419   BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;
    420   EfiCopyMem (&UpdateBuffer->PackageLength, &BufferSize, sizeof (UINT32));
    421 
    422   gBS->FreePool (HiiPackageList);
    423 
    424   return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);
    425 }
    426 
    427 EFI_STATUS
    428 IfrLibCreatePopUp (
    429   IN  UINTN                       NumberOfLines,
    430   OUT EFI_INPUT_KEY               *KeyValue,
    431   IN  CHAR16                      *String,
    432   ...
    433   )
    434 /*++
    435 
    436 Routine Description:
    437   Draw a dialog and return the selected key.
    438 
    439 Arguments:
    440   NumberOfLines     - The number of lines for the dialog box
    441   KeyValue          - The EFI_KEY value returned if HotKey is TRUE..
    442   String            - Pointer to the first string in the list
    443   ...               - A series of (quantity == NumberOfLines) text strings which
    444                       will be used to construct the dialog box
    445 
    446 Returns:
    447   EFI_SUCCESS           - Displayed dialog and received user interaction
    448   EFI_INVALID_PARAMETER - One of the parameters was invalid.
    449 
    450 --*/
    451 {
    452   UINTN                         Index;
    453   UINTN                         Count;
    454   UINTN                         Start;
    455   UINTN                         Top;
    456   CHAR16                        *StringPtr;
    457   UINTN                         LeftColumn;
    458   UINTN                         RightColumn;
    459   UINTN                         TopRow;
    460   UINTN                         BottomRow;
    461   UINTN                         DimensionsWidth;
    462   UINTN                         DimensionsHeight;
    463   VA_LIST                       Marker;
    464   EFI_INPUT_KEY                 Key;
    465   UINTN                         LargestString;
    466   CHAR16                        *StackString;
    467   EFI_STATUS                    Status;
    468   UINTN                         StringLen;
    469   CHAR16                        *LineBuffer;
    470   CHAR16                        **StringArray;
    471   EFI_EVENT                     TimerEvent;
    472   EFI_EVENT                     WaitList[2];
    473   UINTN                         CurrentAttribute;
    474   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *ConOut;
    475 
    476   if ((KeyValue == NULL) || (String == NULL)) {
    477     return EFI_INVALID_PARAMETER;
    478   }
    479 
    480   TopRow      = 0;
    481   BottomRow   = 0;
    482   LeftColumn  = 0;
    483   RightColumn = 0;
    484 
    485   ConOut = gST->ConOut;
    486   ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
    487 
    488   DimensionsWidth  = RightColumn - LeftColumn;
    489   DimensionsHeight = BottomRow - TopRow;
    490 
    491   CurrentAttribute = ConOut->Mode->Attribute;
    492 
    493   LineBuffer = EfiLibAllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
    494   ASSERT (LineBuffer != NULL);
    495 
    496   //
    497   // Determine the largest string in the dialog box
    498   // Notice we are starting with 1 since String is the first string
    499   //
    500   StringArray = EfiLibAllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
    501   LargestString = EfiStrLen (String);
    502   StringArray[0] = String;
    503 
    504   VA_START (Marker, String);
    505   for (Index = 1; Index < NumberOfLines; Index++) {
    506     StackString = VA_ARG (Marker, CHAR16 *);
    507 
    508     if (StackString == NULL) {
    509       VA_END (Marker);
    510       return EFI_INVALID_PARAMETER;
    511     }
    512 
    513     StringArray[Index] = StackString;
    514     StringLen = EfiStrLen (StackString);
    515     if (StringLen > LargestString) {
    516       LargestString = StringLen;
    517     }
    518   }
    519   VA_END (Marker);
    520 
    521   if ((LargestString + 2) > DimensionsWidth) {
    522     LargestString = DimensionsWidth - 2;
    523   }
    524 
    525   //
    526   // Subtract the PopUp width from total Columns, allow for one space extra on
    527   // each end plus a border.
    528   //
    529   Start     = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
    530 
    531   Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
    532 
    533   //
    534   // Disable cursor
    535   //
    536   ConOut->EnableCursor (ConOut, FALSE);
    537   ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
    538 
    539   StringPtr = &LineBuffer[0];
    540   *StringPtr++ = BOXDRAW_DOWN_RIGHT;
    541   for (Index = 0; Index < LargestString; Index++) {
    542     *StringPtr++ = BOXDRAW_HORIZONTAL;
    543   }
    544   *StringPtr++ = BOXDRAW_DOWN_LEFT;
    545   *StringPtr = L'\0';
    546 
    547   ConOut->SetCursorPosition (ConOut, Start, Top);
    548   ConOut->OutputString (ConOut, LineBuffer);
    549 
    550   for (Index = 0; Index < NumberOfLines; Index++) {
    551     StringPtr = &LineBuffer[0];
    552     *StringPtr++ = BOXDRAW_VERTICAL;
    553 
    554     for (Count = 0; Count < LargestString; Count++) {
    555       StringPtr[Count] = L' ';
    556     }
    557 
    558     StringLen = EfiStrLen (StringArray[Index]);
    559     if (StringLen > LargestString) {
    560       StringLen = LargestString;
    561     }
    562     EfiCopyMem (
    563       StringPtr + ((LargestString - StringLen) / 2),
    564       StringArray[Index],
    565       StringLen * sizeof (CHAR16)
    566       );
    567     StringPtr += LargestString;
    568 
    569     *StringPtr++ = BOXDRAW_VERTICAL;
    570     *StringPtr = L'\0';
    571 
    572     ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
    573     ConOut->OutputString (ConOut, LineBuffer);
    574   }
    575 
    576   StringPtr = &LineBuffer[0];
    577   *StringPtr++ = BOXDRAW_UP_RIGHT;
    578   for (Index = 0; Index < LargestString; Index++) {
    579     *StringPtr++ = BOXDRAW_HORIZONTAL;
    580   }
    581   *StringPtr++ = BOXDRAW_UP_LEFT;
    582   *StringPtr = L'\0';
    583 
    584   ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
    585   ConOut->OutputString (ConOut, LineBuffer);
    586 
    587   do {
    588     Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);
    589 
    590     //
    591     // Set a timer event of 1 second expiration
    592     //
    593     gBS->SetTimer (
    594           TimerEvent,
    595           TimerRelative,
    596           10000000
    597           );
    598 
    599     //
    600     // Wait for the keystroke event or the timer
    601     //
    602     WaitList[0] = gST->ConIn->WaitForKey;
    603     WaitList[1] = TimerEvent;
    604     Status      = gBS->WaitForEvent (2, WaitList, &Index);
    605 
    606     //
    607     // Check for the timer expiration
    608     //
    609     if (!EFI_ERROR (Status) && Index == 1) {
    610       Status = EFI_TIMEOUT;
    611     }
    612 
    613     gBS->CloseEvent (TimerEvent);
    614   } while (Status == EFI_TIMEOUT);
    615 
    616   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    617   EfiCopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
    618 
    619   ConOut->SetAttribute (ConOut, CurrentAttribute);
    620   ConOut->EnableCursor (ConOut, TRUE);
    621 
    622   return Status;
    623 }
    624 
    625 EFI_STATUS
    626 ExtractDefault(
    627   IN VOID                         *Buffer,
    628   IN UINTN                        *BufferSize,
    629   UINTN                           Number,
    630   ...
    631   )
    632 /*++
    633 
    634   Routine Description:
    635 
    636     Configure the buffer accrording to ConfigBody strings.
    637 
    638   Arguments:
    639     DefaultId             - the ID of default.
    640     Buffer                - the start address of buffer.
    641     BufferSize            - the size of buffer.
    642     Number                - the number of the strings.
    643 
    644   Returns:
    645     EFI_BUFFER_TOO_SMALL  - the BufferSize is too small to operate.
    646     EFI_INVALID_PARAMETER - Buffer is NULL or BufferSize is 0.
    647     EFI_SUCCESS           - Operation successful.
    648 
    649 --*/
    650 {
    651   VA_LIST                         Args;
    652   UINTN                           Index;
    653   UINT32                          TotalLen;
    654   UINT8                           *BufCfgArray;
    655   UINT8                           *BufferPos;
    656   UINT16                          Offset;
    657   UINT16                          Width;
    658   UINT8                           *Value;
    659 
    660   if ((Buffer == NULL) || (BufferSize == NULL)) {
    661     return EFI_INVALID_PARAMETER;
    662   }
    663 
    664   Offset = 0;
    665   Width  = 0;
    666   Value  = NULL;
    667 
    668   VA_START (Args, Number);
    669   for (Index = 0; Index < Number; Index++) {
    670     BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
    671     EfiCopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
    672     BufferPos = BufCfgArray + sizeof (UINT32);
    673 
    674     while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
    675       EfiCopyMem (&Offset, BufferPos, sizeof (UINT16));
    676       BufferPos += sizeof (UINT16);
    677       EfiCopyMem (&Width, BufferPos, sizeof (UINT16));
    678       BufferPos += sizeof (UINT16);
    679       Value = BufferPos;
    680       BufferPos += Width;
    681 
    682       if ((UINTN)(Offset + Width) > *BufferSize) {
    683         VA_END (Args);
    684         return EFI_BUFFER_TOO_SMALL;
    685       }
    686 
    687       EfiCopyMem ((UINT8 *)Buffer + Offset, Value, Width);
    688     }
    689   }
    690   VA_END (Args);
    691 
    692   *BufferSize = (UINTN)Offset;
    693 
    694   return EFI_SUCCESS;
    695 }
    696 
    697 EFI_STATUS
    698 ExtractBlockName (
    699   IN UINT8                        *Buffer,
    700   OUT CHAR16                      **BlockName
    701   )
    702 /*++
    703 
    704   Routine Description:
    705 
    706     Extract block name from the array generated by VFR compiler. The name of
    707   this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".
    708   Format of this array is:
    709      Array length | 4-bytes
    710        Offset     | 2-bytes
    711        Width      | 2-bytes
    712        Offset     | 2-bytes
    713        Width      | 2-bytes
    714        ... ...
    715 
    716   Arguments:
    717     Buffer                - Array generated by VFR compiler.
    718     BlockName             - The returned <BlockName>
    719 
    720   Returns:
    721     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
    722     EFI_INVALID_PARAMETER - Buffer is NULL or BlockName is NULL.
    723     EFI_SUCCESS           - Operation successful.
    724 
    725 --*/
    726 {
    727   UINTN       Index;
    728   UINT32      Length;
    729   UINT32      BlockNameNumber;
    730   UINTN       HexStringBufferLen;
    731   CHAR16      *StringPtr;
    732 
    733   if ((Buffer == NULL) || (BlockName == NULL)) {
    734     return EFI_INVALID_PARAMETER;
    735   }
    736 
    737   //
    738   // Calculate number of Offset/Width pair
    739   //
    740   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
    741   BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);
    742 
    743   //
    744   // <BlockName> ::= &OFFSET=1234&WIDTH=1234
    745   //                 |   8  | 4 |  7   | 4 |
    746   //
    747   StringPtr = EfiLibAllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));
    748   *BlockName = StringPtr;
    749   if (StringPtr == NULL) {
    750     return EFI_OUT_OF_RESOURCES;
    751   }
    752 
    753   Buffer += sizeof (UINT32);
    754   for (Index = 0; Index < BlockNameNumber; Index++) {
    755     EfiStrCpy (StringPtr, L"&OFFSET=");
    756     StringPtr += 8;
    757 
    758     HexStringBufferLen = 5;
    759     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    760     Buffer += sizeof (UINT16);
    761     StringPtr += 4;
    762 
    763     EfiStrCpy (StringPtr, L"&WIDTH=");
    764     StringPtr += 7;
    765 
    766     HexStringBufferLen = 5;
    767     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    768     Buffer += sizeof (UINT16);
    769     StringPtr += 4;
    770   }
    771 
    772   return EFI_SUCCESS;
    773 }
    774 
    775 EFI_STATUS
    776 ExtractBlockConfig (
    777   IN UINT8                        *Buffer,
    778   OUT CHAR16                      **BlockConfig
    779   )
    780 /*++
    781 
    782   Routine Description:
    783 
    784     Extract block config from the array generated by VFR compiler. The name of
    785   this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".
    786 
    787   Arguments:
    788     Buffer                - Array generated by VFR compiler.
    789     BlockConfig           - The returned <BlockConfig>
    790 
    791   Returns:
    792     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
    793     EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.
    794     EFI_SUCCESS           - Operation successful.
    795 
    796 --*/
    797 {
    798   UINT32      Length;
    799   UINT16      Width;
    800   UINTN       HexStringBufferLen;
    801   CHAR16      *StringPtr;
    802   UINT8       *BufferEnd;
    803   CHAR16      *StringEnd;
    804   EFI_STATUS  Status;
    805 
    806   if ((Buffer == NULL) || (BlockConfig == NULL)) {
    807     return EFI_INVALID_PARAMETER;
    808   }
    809 
    810   //
    811   // Calculate length of AltResp string
    812   // Format of Default value array is:
    813   //  Array length | 4-bytes
    814   //        Offset | 2-bytes
    815   //        Width  | 2-bytes
    816   //        Value  | Variable length
    817   //        Offset | 2-bytes
    818   //        Width  | 2-bytes
    819   //        Value  | Variable length
    820   //        ... ...
    821   // When value is 1 byte in length, overhead of AltResp string will be maximum,
    822   //  BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+
    823   //                   |   8   | 4  |  7   | 4 |  7  |2|
    824   // so the maximum length of BlockConfig could be calculated as:
    825   // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7
    826   //
    827   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
    828   BufferEnd = Buffer + Length;
    829   StringPtr = EfiLibAllocatePool (Length * 7 * sizeof (CHAR16));
    830   *BlockConfig = StringPtr;
    831   if (StringPtr == NULL) {
    832       return EFI_OUT_OF_RESOURCES;
    833   }
    834   StringEnd = StringPtr + (Length * 7);
    835 
    836   Buffer += sizeof (UINT32);
    837   while (Buffer < BufferEnd) {
    838     EfiStrCpy (StringPtr, L"&OFFSET=");
    839     StringPtr += 8;
    840 
    841     HexStringBufferLen = 5;
    842     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    843     Buffer += sizeof (UINT16);
    844     StringPtr += 4;
    845 
    846     EfiStrCpy (StringPtr, L"&WIDTH=");
    847     StringPtr += 7;
    848 
    849     HexStringBufferLen = 5;
    850     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    851     EfiCopyMem (&Width, Buffer, sizeof (UINT16));
    852     Buffer += sizeof (UINT16);
    853     StringPtr += 4;
    854 
    855     EfiStrCpy (StringPtr, L"&VALUE=");
    856     StringPtr += 7;
    857 
    858     HexStringBufferLen = StringEnd - StringPtr;
    859     Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);
    860     if (EFI_ERROR (Status)) {
    861       return Status;
    862     }
    863     Buffer += Width;
    864     StringPtr += (Width * 2);
    865   }
    866 
    867   return EFI_SUCCESS;
    868 }
    869 
    870 EFI_STATUS
    871 ConstructConfigAltResp (
    872   IN  EFI_STRING                  ConfigRequest,  OPTIONAL
    873   OUT EFI_STRING                  *Progress,
    874   OUT EFI_STRING                  *ConfigAltResp,
    875   IN  EFI_GUID                    *Guid,
    876   IN  CHAR16                      *Name,
    877   IN  EFI_HANDLE                  *DriverHandle,
    878   IN  VOID                        *BufferStorage,
    879   IN  UINTN                       BufferStorageSize,
    880   IN  VOID                        *BlockNameArray, OPTIONAL
    881   IN  UINTN                       NumberAltCfg,
    882   ...
    883 //IN  UINT16                      AltCfgId,
    884 //IN  VOID                        *DefaultValueArray,
    885   )
    886 /*++
    887 
    888   Routine Description:
    889 
    890   Construct <ConfigAltResp> for a buffer storage.
    891 
    892   Arguments:
    893     ConfigRequest         - The Config request string. If set to NULL, all the
    894                             configurable elements will be extracted from BlockNameArray.
    895     ConfigAltResp         - The returned <ConfigAltResp>.
    896     Progress              - On return, points to a character in the Request.
    897     Guid                  - GUID of the buffer storage.
    898     Name                  - Name of the buffer storage.
    899     DriverHandle          - The DriverHandle which is used to invoke HiiDatabase
    900                             protocol interface NewPackageList().
    901     BufferStorage         - Content of the buffer storage.
    902     BufferStorageSize     - Length in bytes of the buffer storage.
    903     BlockNameArray        - Array generated by VFR compiler.
    904     NumberAltCfg          - Number of Default value array generated by VFR compiler.
    905                             The sequential input parameters will be number of
    906                             AltCfgId and DefaultValueArray pairs. When set to 0,
    907                             there will be no <AltResp>.
    908 
    909   Returns:
    910     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
    911     EFI_INVALID_PARAMETER - ConfigAltResp is NULL.
    912     EFI_SUCCESS           - Operation successful.
    913 
    914 --*/
    915 {
    916   EFI_STATUS                      Status;
    917   CHAR16                          *ConfigHdr;
    918   CHAR16                          *BlockName;
    919   CHAR16                          *DescHdr;
    920   CHAR16                          *StringPtr;
    921   CHAR16                          **AltCfg;
    922   UINT16                          AltCfgId;
    923   VOID                            *DefaultValueArray;
    924   UINTN                           StrBufferLen;
    925   EFI_STRING                      ConfigResp;
    926   EFI_STRING                      TempStr;
    927   VA_LIST                         Args;
    928   UINTN                           AltRespLen;
    929   UINTN                           Index;
    930   BOOLEAN                         NeedFreeConfigRequest;
    931   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
    932 
    933   if (ConfigAltResp == NULL) {
    934     return EFI_INVALID_PARAMETER;
    935   }
    936 
    937   //
    938   // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."
    939   //
    940   ConfigHdr = NULL;
    941   StrBufferLen = 0;
    942   Status = ConstructConfigHdr (
    943              ConfigHdr,
    944              &StrBufferLen,
    945              Guid,
    946              Name,
    947              DriverHandle
    948              );
    949   if (Status == EFI_BUFFER_TOO_SMALL) {
    950     ConfigHdr = EfiLibAllocateZeroPool (StrBufferLen);
    951     Status = ConstructConfigHdr (
    952                ConfigHdr,
    953                &StrBufferLen,
    954                Guid,
    955                Name,
    956                DriverHandle
    957                );
    958   }
    959 
    960   if (EFI_ERROR (Status) || (ConfigHdr == NULL)) {
    961     return Status;
    962   }
    963 
    964   //
    965   // Construct <ConfigResp>
    966   //
    967   NeedFreeConfigRequest = FALSE;
    968   if (ConfigRequest == NULL) {
    969     //
    970     // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray
    971     //
    972     Status = ExtractBlockName (BlockNameArray, &BlockName);
    973     if (EFI_ERROR (Status)) {
    974       return Status;
    975     }
    976 
    977     StrBufferLen = EfiStrSize (ConfigHdr);
    978     StrBufferLen = StrBufferLen + EfiStrSize (BlockName) - sizeof (CHAR16);
    979     ConfigRequest = EfiLibAllocateZeroPool (StrBufferLen);
    980     EfiStrCpy (ConfigRequest, ConfigHdr);
    981     EfiStrCat (ConfigRequest, BlockName);
    982     NeedFreeConfigRequest = TRUE;
    983   }
    984 
    985   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
    986   if (EFI_ERROR (Status)) {
    987     return Status;
    988   }
    989 
    990   Status = HiiConfigRouting->BlockToConfig (
    991                                HiiConfigRouting,
    992                                ConfigRequest,
    993                                BufferStorage,
    994                                BufferStorageSize,
    995                                &ConfigResp,
    996                                (Progress == NULL) ? &TempStr : Progress
    997                                );
    998   if (EFI_ERROR (Status)) {
    999     return Status;
   1000   }
   1001 
   1002   //
   1003   // Construct <AltResp>
   1004   //
   1005   DescHdr = EfiLibAllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));
   1006   StringPtr = DescHdr;
   1007   AltCfg = EfiLibAllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));
   1008   AltRespLen = 0;
   1009   VA_START (Args, NumberAltCfg);
   1010   for (Index = 0; Index < NumberAltCfg; Index++) {
   1011     AltCfgId = (UINT16) VA_ARG (Args, UINT16);
   1012     DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);
   1013 
   1014     //
   1015     // '&' <ConfigHdr>
   1016     //
   1017     AltRespLen += (EfiStrLen (ConfigHdr) + 1);
   1018 
   1019     StringPtr = DescHdr + Index * 16;
   1020     EfiStrCpy (StringPtr, L"&ALTCFG=");
   1021     AltRespLen += (8 + sizeof (UINT16) * 2);
   1022 
   1023     StrBufferLen = 5;
   1024     BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));
   1025     Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);
   1026     if (EFI_ERROR (Status)) {
   1027       VA_END (Args);
   1028       return Status;
   1029     }
   1030     AltRespLen += EfiStrLen (AltCfg[Index]);
   1031   }
   1032   VA_END (Args);
   1033 
   1034   //
   1035   // Generate the final <ConfigAltResp>
   1036   //
   1037   StrBufferLen = (EfiStrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);
   1038   TempStr = EfiLibAllocateZeroPool (StrBufferLen);
   1039   *ConfigAltResp = TempStr;
   1040   if (TempStr == NULL) {
   1041     return EFI_OUT_OF_RESOURCES;
   1042   }
   1043 
   1044   //
   1045   // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*
   1046   //
   1047   EfiStrCpy (TempStr, ConfigResp);
   1048   for (Index = 0; Index < NumberAltCfg; Index++) {
   1049     EfiStrCat (TempStr, L"&");
   1050     EfiStrCat (TempStr, ConfigHdr);
   1051     EfiStrCat (TempStr, DescHdr + Index * 16);
   1052     EfiStrCat (TempStr, AltCfg[Index]);
   1053 
   1054     gBS->FreePool (AltCfg[Index]);
   1055   }
   1056 
   1057   if (NeedFreeConfigRequest) {
   1058     gBS->FreePool (ConfigRequest);
   1059   }
   1060   gBS->FreePool (ConfigHdr);
   1061   gBS->FreePool (ConfigResp);
   1062   gBS->FreePool (DescHdr);
   1063   gBS->FreePool (AltCfg);
   1064 
   1065   return EFI_SUCCESS;
   1066 }
   1067 
   1068 VOID
   1069 SwapBuffer (
   1070   IN OUT UINT8     *Buffer,
   1071   IN UINTN         BufferSize
   1072   )
   1073 /*++
   1074 
   1075 Routine Description:
   1076   Swap bytes in the buffer.
   1077 
   1078 Arguments:
   1079   Buffer     -  Binary buffer.
   1080   BufferSize -  Size of the buffer in bytes.
   1081 
   1082 Returns:
   1083   None.
   1084 
   1085 --*/
   1086 {
   1087   UINTN  Index;
   1088   UINT8  Temp;
   1089   UINTN  SwapCount;
   1090 
   1091   SwapCount = BufferSize / 2;
   1092   for (Index = 0; Index < SwapCount; Index++) {
   1093     Temp = Buffer[Index];
   1094     Buffer[Index] = Buffer[BufferSize - 1 - Index];
   1095     Buffer[BufferSize - 1 - Index] = Temp;
   1096   }
   1097 }
   1098 
   1099 VOID
   1100 ToLower (
   1101   IN OUT CHAR16    *Str
   1102   )
   1103 /*++
   1104 
   1105 Routine Description:
   1106   Converts the unicode character of the string from uppercase to lowercase.
   1107 
   1108 Arguments:
   1109   Str        -  String to be converted
   1110 
   1111 Returns:
   1112 
   1113 --*/
   1114 {
   1115   CHAR16      *Ptr;
   1116 
   1117   for (Ptr = Str; *Ptr != L'\0'; Ptr++) {
   1118     if (*Ptr >= L'A' && *Ptr <= L'Z') {
   1119       *Ptr = (CHAR16) (*Ptr - L'A' + L'a');
   1120     }
   1121   }
   1122 }
   1123 
   1124 EFI_STATUS
   1125 BufferToHexString (
   1126   IN OUT CHAR16    *Str,
   1127   IN UINT8         *Buffer,
   1128   IN UINTN         BufferSize
   1129   )
   1130 /*++
   1131 
   1132 Routine Description:
   1133   Converts binary buffer to Unicode string in reversed byte order from BufToHexString().
   1134 
   1135 Arguments:
   1136   Str        -  String for output
   1137   Buffer     -  Binary buffer.
   1138   BufferSize -  Size of the buffer in bytes.
   1139 
   1140 Returns:
   1141   EFI_SUCCESS  -  The function completed successfully.
   1142 
   1143 --*/
   1144 {
   1145   EFI_STATUS  Status;
   1146   UINT8       *NewBuffer;
   1147   UINTN       StrBufferLen;
   1148 
   1149   NewBuffer = EfiLibAllocateCopyPool (BufferSize, Buffer);
   1150   SwapBuffer (NewBuffer, BufferSize);
   1151 
   1152   StrBufferLen = BufferSize * 2 + 1;
   1153   Status = BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
   1154 
   1155   gBS->FreePool (NewBuffer);
   1156   //
   1157   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
   1158   //
   1159   ToLower (Str);
   1160 
   1161   return Status;
   1162 }
   1163 
   1164 EFI_STATUS
   1165 HexStringToBuffer (
   1166   IN OUT UINT8         *Buffer,
   1167   IN OUT UINTN         *BufferSize,
   1168   IN CHAR16            *Str
   1169   )
   1170 /*++
   1171 
   1172 Routine Description:
   1173   Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().
   1174 
   1175 Arguments:
   1176     Buffer     - Pointer to buffer that receives the data.
   1177     BufferSize - Length in bytes of the buffer to hold converted data.
   1178                  If routine return with EFI_SUCCESS, containing length of converted data.
   1179                  If routine return with EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
   1180     Str        - String to be converted from.
   1181 
   1182 Returns:
   1183   EFI_SUCCESS    -  The function completed successfully.
   1184 
   1185 --*/
   1186 {
   1187   EFI_STATUS  Status;
   1188   UINTN       ConvertedStrLen;
   1189 
   1190   ConvertedStrLen = 0;
   1191   Status = HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
   1192   if (!EFI_ERROR (Status)) {
   1193     SwapBuffer (Buffer, (ConvertedStrLen + 1) / 2);
   1194   }
   1195 
   1196   return Status;
   1197 }
   1198 
   1199 EFI_STATUS
   1200 ConfigStringToUnicode (
   1201   IN OUT CHAR16                *UnicodeString,
   1202   IN OUT UINTN                 *StrBufferLen,
   1203   IN CHAR16                    *ConfigString
   1204   )
   1205 /*++
   1206 
   1207 Routine Description:
   1208   Convert binary representation Config string (e.g. "0041004200430044") to the
   1209   original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.
   1210   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
   1211 
   1212 Arguments:
   1213   UnicodeString - Original Unicode string.
   1214   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
   1215                   Includes tailing '\0' character.
   1216                   On output:
   1217                     If return EFI_SUCCESS, containing length of Unicode string buffer.
   1218                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
   1219   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
   1220 
   1221 Returns:
   1222   EFI_SUCCESS          - Routine success.
   1223   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
   1224 
   1225 --*/
   1226 {
   1227   UINTN       Index;
   1228   UINTN       Len;
   1229   UINTN       BufferSize;
   1230   CHAR16      BackupChar;
   1231 
   1232   Len = EfiStrLen (ConfigString) / 4;
   1233   BufferSize = (Len + 1) * sizeof (CHAR16);
   1234 
   1235   if (*StrBufferLen < BufferSize) {
   1236     *StrBufferLen = BufferSize;
   1237     return EFI_BUFFER_TOO_SMALL;
   1238   }
   1239 
   1240   *StrBufferLen = BufferSize;
   1241 
   1242   for (Index = 0; Index < Len; Index++) {
   1243     BackupChar = ConfigString[4];
   1244     ConfigString[4] = L'\0';
   1245 
   1246     HexStringToBuf ((UINT8 *) UnicodeString, &BufferSize, ConfigString, NULL);
   1247 
   1248     ConfigString[4] = BackupChar;
   1249 
   1250     ConfigString += 4;
   1251     UnicodeString += 1;
   1252   }
   1253 
   1254   //
   1255   // Add tailing '\0' character
   1256   //
   1257   *UnicodeString = L'\0';
   1258 
   1259   return EFI_SUCCESS;
   1260 }
   1261 
   1262 EFI_STATUS
   1263 UnicodeToConfigString (
   1264   IN OUT CHAR16                *ConfigString,
   1265   IN OUT UINTN                 *StrBufferLen,
   1266   IN CHAR16                    *UnicodeString
   1267   )
   1268 /*++
   1269 
   1270 Routine Description:
   1271   Convert Unicode string to binary representation Config string, e.g.
   1272   "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.
   1273   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
   1274 
   1275 Arguments:
   1276   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
   1277   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
   1278                   Includes tailing '\0' character.
   1279                   On output:
   1280                     If return EFI_SUCCESS, containing length of Unicode string buffer.
   1281                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
   1282   UnicodeString - Original Unicode string.
   1283 
   1284 Returns:
   1285   EFI_SUCCESS          - Routine success.
   1286   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
   1287 
   1288 --*/
   1289 {
   1290   UINTN       Index;
   1291   UINTN       Len;
   1292   UINTN       BufferSize;
   1293   CHAR16      *String;
   1294 
   1295   Len = EfiStrLen (UnicodeString);
   1296   BufferSize = (Len * 4 + 1) * sizeof (CHAR16);
   1297 
   1298   if (*StrBufferLen < BufferSize) {
   1299     *StrBufferLen = BufferSize;
   1300     return EFI_BUFFER_TOO_SMALL;
   1301   }
   1302 
   1303   *StrBufferLen = BufferSize;
   1304   String        = ConfigString;
   1305 
   1306   for (Index = 0; Index < Len; Index++) {
   1307     BufToHexString (ConfigString, &BufferSize, (UINT8 *) UnicodeString, 2);
   1308 
   1309     ConfigString += 4;
   1310     UnicodeString += 1;
   1311   }
   1312 
   1313   //
   1314   // Add tailing '\0' character
   1315   //
   1316   *ConfigString = L'\0';
   1317 
   1318   //
   1319   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
   1320   //
   1321   ToLower (String);
   1322   return EFI_SUCCESS;
   1323 }
   1324 
   1325 EFI_STATUS
   1326 ConstructConfigHdr (
   1327   IN OUT CHAR16                *ConfigHdr,
   1328   IN OUT UINTN                 *StrBufferLen,
   1329   IN EFI_GUID                  *Guid,
   1330   IN CHAR16                    *Name, OPTIONAL
   1331   IN EFI_HANDLE                *DriverHandle
   1332   )
   1333 /*++
   1334 
   1335 Routine Description:
   1336   Construct <ConfigHdr> using routing information GUID/NAME/PATH.
   1337 
   1338 Arguments:
   1339   ConfigHdr    - Pointer to the ConfigHdr string.
   1340   StrBufferLen - On input: Length in bytes of buffer to hold the ConfigHdr string.
   1341                  Includes tailing '\0' character.
   1342                  On output:
   1343                     If return EFI_SUCCESS, containing length of ConfigHdr string buffer.
   1344                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
   1345   Guid         - Routing information: GUID.
   1346   Name         - Routing information: NAME.
   1347   DriverHandle - Driver handle which contains the routing information: PATH.
   1348 
   1349 Returns:
   1350   EFI_SUCCESS          - Routine success.
   1351   EFI_BUFFER_TOO_SMALL - The ConfigHdr string buffer is too small.
   1352 
   1353 --*/
   1354 {
   1355   EFI_STATUS                Status;
   1356   UINTN                     NameStrLen;
   1357   UINTN                     DevicePathSize;
   1358   UINTN                     BufferSize;
   1359   CHAR16                    *StrPtr;
   1360   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   1361 
   1362   if (Name == NULL) {
   1363     //
   1364     // There will be no "NAME" in <ConfigHdr> for  Name/Value storage
   1365     //
   1366     NameStrLen = 0;
   1367   } else {
   1368     //
   1369     // For buffer storage
   1370     //
   1371     NameStrLen = EfiStrLen (Name);
   1372   }
   1373 
   1374   //
   1375   // Retrieve DevicePath Protocol associated with this HiiPackageList
   1376   //
   1377   Status = gBS->HandleProtocol (
   1378                   DriverHandle,
   1379                   &gEfiDevicePathProtocolGuid,
   1380                   (VOID **) &DevicePath
   1381                   );
   1382   if (EFI_ERROR (Status)) {
   1383     return Status;
   1384   }
   1385 
   1386   DevicePathSize = EfiDevicePathSize (DevicePath);
   1387 
   1388   //
   1389   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
   1390   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
   1391   //
   1392   BufferSize = (5 + 32 + 6 + NameStrLen * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
   1393   if (*StrBufferLen < BufferSize) {
   1394     *StrBufferLen = BufferSize;
   1395     return EFI_BUFFER_TOO_SMALL;
   1396   }
   1397 
   1398   if (ConfigHdr == NULL) {
   1399     return EFI_INVALID_PARAMETER;
   1400   }
   1401 
   1402   *StrBufferLen = BufferSize;
   1403 
   1404   StrPtr = ConfigHdr;
   1405 
   1406   EfiStrCpy (StrPtr, L"GUID=");
   1407   StrPtr += 5;
   1408   BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
   1409   StrPtr += 32;
   1410 
   1411   //
   1412   // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
   1413   //
   1414   EfiStrCpy (StrPtr, L"&NAME=");
   1415   StrPtr += 6;
   1416   if (Name != NULL) {
   1417     BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);
   1418     UnicodeToConfigString (StrPtr, &BufferSize, Name);
   1419     StrPtr += (NameStrLen * 4);
   1420   }
   1421 
   1422   EfiStrCpy (StrPtr, L"&PATH=");
   1423   StrPtr += 6;
   1424   BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
   1425 
   1426   return EFI_SUCCESS;
   1427 }
   1428 
   1429 BOOLEAN
   1430 IsConfigHdrMatch (
   1431   IN EFI_STRING                ConfigString,
   1432   IN EFI_GUID                  *StorageGuid, OPTIONAL
   1433   IN CHAR16                    *StorageName  OPTIONAL
   1434   )
   1435 /*++
   1436 
   1437 Routine Description:
   1438   Determines if the Routing data (Guid and Name) is correct in <ConfigHdr>.
   1439 
   1440 Arguments:
   1441   ConfigString - Either <ConfigRequest> or <ConfigResp>.
   1442   StorageGuid  - GUID of the storage.
   1443   StorageName  - Name of the stoarge.
   1444 
   1445 Returns:
   1446   TRUE         - Routing information is correct in ConfigString.
   1447   FALSE        - Routing information is incorrect in ConfigString.
   1448 
   1449 --*/
   1450 {
   1451   EFI_STATUS  Status;
   1452   BOOLEAN     Match;
   1453   EFI_GUID    Guid;
   1454   CHAR16      *Name;
   1455   CHAR16      *StrPtr;
   1456   UINTN       BufferSize;
   1457 
   1458   //
   1459   // <ConfigHdr> ::=
   1460   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
   1461   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
   1462   //
   1463   if (EfiStrLen (ConfigString) <= (5 + 32 + 6)) {
   1464     return FALSE;
   1465   }
   1466 
   1467   //
   1468   // Compare GUID
   1469   //
   1470   if (StorageGuid != NULL) {
   1471 
   1472     StrPtr = ConfigString + 5 + 32;
   1473     if (*StrPtr != L'&') {
   1474       return FALSE;
   1475     }
   1476     *StrPtr = L'\0';
   1477 
   1478     BufferSize = sizeof (EFI_GUID);
   1479     Status = HexStringToBuffer (
   1480                (UINT8 *) &Guid,
   1481                &BufferSize,
   1482                ConfigString + 5
   1483                );
   1484     *StrPtr = L'&';
   1485 
   1486     if (EFI_ERROR (Status)) {
   1487       return FALSE;
   1488     }
   1489 
   1490     if (!EfiCompareGuid (&Guid, StorageGuid)) {
   1491       return FALSE;
   1492     }
   1493   }
   1494 
   1495   //
   1496   // Compare Name
   1497   //
   1498   Match = TRUE;
   1499   if (StorageName != NULL) {
   1500     StrPtr = ConfigString + 5 + 32 + 6;
   1501     while (*StrPtr != L'\0' && *StrPtr != L'&') {
   1502       StrPtr++;
   1503     }
   1504     if (*StrPtr != L'&') {
   1505       return FALSE;
   1506     }
   1507 
   1508     *StrPtr = L'\0';
   1509     BufferSize = (EfiStrLen (ConfigString + 5 + 32 + 6) + 1) * sizeof (CHAR16);
   1510     Name = EfiLibAllocatePool (BufferSize);
   1511     ASSERT (Name != NULL);
   1512     Status = ConfigStringToUnicode (
   1513                Name,
   1514                &BufferSize,
   1515                ConfigString + 5 + 32 + 6
   1516                );
   1517     *StrPtr = L'&';
   1518 
   1519     if (EFI_ERROR (Status) || (EfiStrCmp (Name, StorageName) != 0)) {
   1520       Match = FALSE;
   1521     }
   1522     gBS->FreePool (Name);
   1523   }
   1524 
   1525   return Match;
   1526 }
   1527 
   1528 BOOLEAN
   1529 FindBlockName (
   1530   IN OUT CHAR16                *String,
   1531   UINTN                        Offset,
   1532   UINTN                        Width
   1533   )
   1534 /*++
   1535 
   1536 Routine Description:
   1537   Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
   1538 
   1539 Arguments:
   1540   String       - The string to be searched in.
   1541   Offset       - Offset in BlockName.
   1542   Width        - Width in BlockName.
   1543 
   1544 Returns:
   1545   TRUE         - Block name found.
   1546   FALSE        - Block name not found.
   1547 
   1548 --*/
   1549 {
   1550   EFI_STATUS  Status;
   1551   UINTN       Data;
   1552   UINTN       BufferSize;
   1553   UINTN       ConvertedStrLen;
   1554 
   1555   while ((String = EfiStrStr (String, L"&OFFSET=")) != NULL) {
   1556     //
   1557     // Skip '&OFFSET='
   1558     //
   1559     String = String + 8;
   1560 
   1561     Data = 0;
   1562     BufferSize = sizeof (UINTN);
   1563     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
   1564     if (EFI_ERROR (Status)) {
   1565       return FALSE;
   1566     }
   1567     String = String + ConvertedStrLen;
   1568 
   1569     if (Data != Offset) {
   1570       continue;
   1571     }
   1572 
   1573     if (EfiStrnCmp (String, L"&WIDTH=", 7) != 0) {
   1574       return FALSE;
   1575     }
   1576     String = String + 7;
   1577 
   1578     Data = 0;
   1579     BufferSize = sizeof (UINTN);
   1580     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
   1581     if (EFI_ERROR (Status)) {
   1582       return FALSE;
   1583     }
   1584     if (Data == Width) {
   1585       return TRUE;
   1586     }
   1587 
   1588     String = String + ConvertedStrLen;
   1589   }
   1590 
   1591   return FALSE;
   1592 }
   1593 
   1594 EFI_STATUS
   1595 GetBrowserData (
   1596   EFI_GUID                   *VariableGuid, OPTIONAL
   1597   CHAR16                     *VariableName, OPTIONAL
   1598   UINTN                      *BufferSize,
   1599   UINT8                      *Buffer
   1600   )
   1601 /*++
   1602 
   1603 Routine Description:
   1604   This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
   1605 
   1606 Arguments:
   1607   VariableGuid  - An optional field to indicate the target variable GUID name to use.
   1608   VariableName  - An optional field to indicate the target human-readable variable name.
   1609   BufferSize    - On input: Length in bytes of buffer to hold retrived data.
   1610                   On output:
   1611                     If return EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
   1612   Buffer        - Buffer to hold retrived data.
   1613 
   1614 Returns:
   1615   EFI_SUCCESS          - Routine success.
   1616   EFI_BUFFER_TOO_SMALL - The intput buffer is too small.
   1617 
   1618 --*/
   1619 {
   1620   EFI_STATUS                      Status;
   1621   CHAR16                          *ConfigHdr;
   1622   CHAR16                          *ConfigResp;
   1623   CHAR16                          *StringPtr;
   1624   UINTN                           HeaderLen;
   1625   UINTN                           BufferLen;
   1626   CHAR16                          *Progress;
   1627   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
   1628   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
   1629 
   1630   //
   1631   // Locate protocols for use
   1632   //
   1633   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
   1634   if (EFI_ERROR (Status)) {
   1635     return Status;
   1636   }
   1637 
   1638   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
   1639   if (EFI_ERROR (Status)) {
   1640     return Status;
   1641   }
   1642 
   1643   //
   1644   // Retrieve formset storage data from Form Browser
   1645   //
   1646   ConfigHdr = mFakeConfigHdr;
   1647   HeaderLen = EfiStrLen (ConfigHdr);
   1648 
   1649   BufferLen = 0x4000;
   1650   ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
   1651 
   1652   StringPtr = ConfigResp + HeaderLen;
   1653   *StringPtr = L'&';
   1654   StringPtr++;
   1655 
   1656   Status = FormBrowser2->BrowserCallback (
   1657                            FormBrowser2,
   1658                            &BufferLen,
   1659                            StringPtr,
   1660                            TRUE,
   1661                            VariableGuid,
   1662                            VariableName
   1663                            );
   1664   if (Status == EFI_BUFFER_TOO_SMALL) {
   1665     gBS->FreePool (ConfigResp);
   1666     ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
   1667 
   1668     StringPtr = ConfigResp + HeaderLen;
   1669     *StringPtr = L'&';
   1670     StringPtr++;
   1671 
   1672     Status = FormBrowser2->BrowserCallback (
   1673                              FormBrowser2,
   1674                              &BufferLen,
   1675                              StringPtr,
   1676                              TRUE,
   1677                              VariableGuid,
   1678                              VariableName
   1679                              );
   1680   }
   1681   if (EFI_ERROR (Status)) {
   1682     gBS->FreePool (ConfigResp);
   1683     return Status;
   1684   }
   1685   EfiCopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
   1686 
   1687   //
   1688   // Convert <ConfigResp> to buffer data
   1689   //
   1690   Status = HiiConfigRouting->ConfigToBlock (
   1691                                HiiConfigRouting,
   1692                                ConfigResp,
   1693                                Buffer,
   1694                                BufferSize,
   1695                                &Progress
   1696                                );
   1697   gBS->FreePool (ConfigResp);
   1698 
   1699   return Status;
   1700 }
   1701 
   1702 EFI_STATUS
   1703 SetBrowserData (
   1704   EFI_GUID                   *VariableGuid, OPTIONAL
   1705   CHAR16                     *VariableName, OPTIONAL
   1706   UINTN                      BufferSize,
   1707   UINT8                      *Buffer,
   1708   CHAR16                     *RequestElement  OPTIONAL
   1709   )
   1710 /*++
   1711 
   1712 Routine Description:
   1713   This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
   1714 
   1715 Arguments:
   1716   VariableGuid   - An optional field to indicate the target variable GUID name to use.
   1717   VariableName   - An optional field to indicate the target human-readable variable name.
   1718   BufferSize     - Length in bytes of buffer to hold retrived data.
   1719   Buffer         - Buffer to hold retrived data.
   1720   RequestElement - An optional field to specify which part of the buffer data
   1721                    will be send back to Browser. If NULL, the whole buffer of
   1722                    data will be committed to Browser.
   1723                    <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
   1724 
   1725 Returns:
   1726   EFI_SUCCESS  - Routine success.
   1727   Other        - Updating Browser uncommitted data failed.
   1728 
   1729 --*/
   1730 {
   1731   EFI_STATUS                      Status;
   1732   CHAR16                          *ConfigHdr;
   1733   CHAR16                          *ConfigResp;
   1734   CHAR16                          *StringPtr;
   1735   UINTN                           HeaderLen;
   1736   UINTN                           BufferLen;
   1737   CHAR16                          *Progress;
   1738   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
   1739   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
   1740   CHAR16                          BlockName[33];
   1741   CHAR16                          *ConfigRequest;
   1742   CHAR16                          *Request;
   1743 
   1744   //
   1745   // Locate protocols for use
   1746   //
   1747   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
   1748   if (EFI_ERROR (Status)) {
   1749     return Status;
   1750   }
   1751 
   1752   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
   1753   if (EFI_ERROR (Status)) {
   1754     return Status;
   1755   }
   1756 
   1757   //
   1758   // Prepare <ConfigRequest>
   1759   //
   1760   ConfigHdr = mFakeConfigHdr;
   1761   HeaderLen = EfiStrLen (ConfigHdr);
   1762 
   1763   if (RequestElement == NULL) {
   1764     //
   1765     // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
   1766     //
   1767     BlockName[0] = L'\0';
   1768     EfiStrCpy (BlockName, L"&OFFSET=0&WIDTH=");
   1769 
   1770     //
   1771     // String lenghth of L"&OFFSET=0&WIDTH=" is 16
   1772     //
   1773     StringPtr = BlockName + 16;
   1774     BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
   1775     BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
   1776 
   1777     Request = BlockName;
   1778   } else {
   1779     Request = RequestElement;
   1780   }
   1781 
   1782   BufferLen = HeaderLen * sizeof (CHAR16) + EfiStrSize (Request);
   1783   ConfigRequest = EfiLibAllocateZeroPool (BufferLen);
   1784 
   1785   EfiCopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
   1786   StringPtr = ConfigRequest + HeaderLen;
   1787   EfiStrCpy (StringPtr, Request);
   1788 
   1789   //
   1790   // Convert buffer to <ConfigResp>
   1791   //
   1792   Status = HiiConfigRouting->BlockToConfig (
   1793                                 HiiConfigRouting,
   1794                                 ConfigRequest,
   1795                                 Buffer,
   1796                                 BufferSize,
   1797                                 &ConfigResp,
   1798                                 &Progress
   1799                                 );
   1800   if (EFI_ERROR (Status)) {
   1801     gBS->FreePool (ConfigRequest);
   1802     return Status;
   1803   }
   1804 
   1805   //
   1806   // Skip <ConfigHdr> and '&'
   1807   //
   1808   StringPtr = ConfigResp + HeaderLen + 1;
   1809 
   1810   //
   1811   // Change uncommitted data in Browser
   1812   //
   1813   Status = FormBrowser2->BrowserCallback (
   1814                            FormBrowser2,
   1815                            &BufferSize,
   1816                            StringPtr,
   1817                            FALSE,
   1818                            VariableGuid,
   1819                            VariableName
   1820                            );
   1821   gBS->FreePool (ConfigResp);
   1822   gBS->FreePool (ConfigRequest);
   1823   return Status;
   1824 }
   1825