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                         End;
    456   UINTN                         Top;
    457   UINTN                         Bottom;
    458   CHAR16                        *StringPtr;
    459   UINTN                         LeftColumn;
    460   UINTN                         RightColumn;
    461   UINTN                         TopRow;
    462   UINTN                         BottomRow;
    463   UINTN                         DimensionsWidth;
    464   UINTN                         DimensionsHeight;
    465   VA_LIST                       Marker;
    466   EFI_INPUT_KEY                 Key;
    467   UINTN                         LargestString;
    468   CHAR16                        *StackString;
    469   EFI_STATUS                    Status;
    470   UINTN                         StringLen;
    471   CHAR16                        *LineBuffer;
    472   CHAR16                        **StringArray;
    473   EFI_EVENT                     TimerEvent;
    474   EFI_EVENT                     WaitList[2];
    475   UINTN                         CurrentAttribute;
    476   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *ConOut;
    477 
    478   if ((KeyValue == NULL) || (String == NULL)) {
    479     return EFI_INVALID_PARAMETER;
    480   }
    481 
    482   TopRow      = 0;
    483   BottomRow   = 0;
    484   LeftColumn  = 0;
    485   RightColumn = 0;
    486 
    487   ConOut = gST->ConOut;
    488   ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow);
    489 
    490   DimensionsWidth  = RightColumn - LeftColumn;
    491   DimensionsHeight = BottomRow - TopRow;
    492 
    493   CurrentAttribute = ConOut->Mode->Attribute;
    494 
    495   LineBuffer = EfiLibAllocateZeroPool (DimensionsWidth * sizeof (CHAR16));
    496   ASSERT (LineBuffer != NULL);
    497 
    498   //
    499   // Determine the largest string in the dialog box
    500   // Notice we are starting with 1 since String is the first string
    501   //
    502   StringArray = EfiLibAllocateZeroPool (NumberOfLines * sizeof (CHAR16 *));
    503   LargestString = EfiStrLen (String);
    504   StringArray[0] = String;
    505 
    506   VA_START (Marker, String);
    507   for (Index = 1; Index < NumberOfLines; Index++) {
    508     StackString = VA_ARG (Marker, CHAR16 *);
    509 
    510     if (StackString == NULL) {
    511       VA_END (Marker);
    512       return EFI_INVALID_PARAMETER;
    513     }
    514 
    515     StringArray[Index] = StackString;
    516     StringLen = EfiStrLen (StackString);
    517     if (StringLen > LargestString) {
    518       LargestString = StringLen;
    519     }
    520   }
    521   VA_END (Marker);
    522 
    523   if ((LargestString + 2) > DimensionsWidth) {
    524     LargestString = DimensionsWidth - 2;
    525   }
    526 
    527   //
    528   // Subtract the PopUp width from total Columns, allow for one space extra on
    529   // each end plus a border.
    530   //
    531   Start     = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1;
    532   End       = Start + LargestString + 1;
    533 
    534   Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1;
    535   Bottom    = Top + NumberOfLines + 2;
    536 
    537   //
    538   // Disable cursor
    539   //
    540   ConOut->EnableCursor (ConOut, FALSE);
    541   ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
    542 
    543   StringPtr = &LineBuffer[0];
    544   *StringPtr++ = BOXDRAW_DOWN_RIGHT;
    545   for (Index = 0; Index < LargestString; Index++) {
    546     *StringPtr++ = BOXDRAW_HORIZONTAL;
    547   }
    548   *StringPtr++ = BOXDRAW_DOWN_LEFT;
    549   *StringPtr = L'\0';
    550 
    551   ConOut->SetCursorPosition (ConOut, Start, Top);
    552   ConOut->OutputString (ConOut, LineBuffer);
    553 
    554   for (Index = 0; Index < NumberOfLines; Index++) {
    555     StringPtr = &LineBuffer[0];
    556     *StringPtr++ = BOXDRAW_VERTICAL;
    557 
    558     for (Count = 0; Count < LargestString; Count++) {
    559       StringPtr[Count] = L' ';
    560     }
    561 
    562     StringLen = EfiStrLen (StringArray[Index]);
    563     if (StringLen > LargestString) {
    564       StringLen = LargestString;
    565     }
    566     EfiCopyMem (
    567       StringPtr + ((LargestString - StringLen) / 2),
    568       StringArray[Index],
    569       StringLen * sizeof (CHAR16)
    570       );
    571     StringPtr += LargestString;
    572 
    573     *StringPtr++ = BOXDRAW_VERTICAL;
    574     *StringPtr = L'\0';
    575 
    576     ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index);
    577     ConOut->OutputString (ConOut, LineBuffer);
    578   }
    579 
    580   StringPtr = &LineBuffer[0];
    581   *StringPtr++ = BOXDRAW_UP_RIGHT;
    582   for (Index = 0; Index < LargestString; Index++) {
    583     *StringPtr++ = BOXDRAW_HORIZONTAL;
    584   }
    585   *StringPtr++ = BOXDRAW_UP_LEFT;
    586   *StringPtr = L'\0';
    587 
    588   ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1);
    589   ConOut->OutputString (ConOut, LineBuffer);
    590 
    591   do {
    592     Status = gBS->CreateEvent (EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);
    593 
    594     //
    595     // Set a timer event of 1 second expiration
    596     //
    597     gBS->SetTimer (
    598           TimerEvent,
    599           TimerRelative,
    600           10000000
    601           );
    602 
    603     //
    604     // Wait for the keystroke event or the timer
    605     //
    606     WaitList[0] = gST->ConIn->WaitForKey;
    607     WaitList[1] = TimerEvent;
    608     Status      = gBS->WaitForEvent (2, WaitList, &Index);
    609 
    610     //
    611     // Check for the timer expiration
    612     //
    613     if (!EFI_ERROR (Status) && Index == 1) {
    614       Status = EFI_TIMEOUT;
    615     }
    616 
    617     gBS->CloseEvent (TimerEvent);
    618   } while (Status == EFI_TIMEOUT);
    619 
    620   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    621   EfiCopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
    622 
    623   ConOut->SetAttribute (ConOut, CurrentAttribute);
    624   ConOut->EnableCursor (ConOut, TRUE);
    625 
    626   return Status;
    627 }
    628 
    629 EFI_STATUS
    630 ExtractDefault(
    631   IN VOID                         *Buffer,
    632   IN UINTN                        *BufferSize,
    633   UINTN                           Number,
    634   ...
    635   )
    636 /*++
    637 
    638   Routine Description:
    639 
    640     Configure the buffer accrording to ConfigBody strings.
    641 
    642   Arguments:
    643     DefaultId             - the ID of default.
    644     Buffer                - the start address of buffer.
    645     BufferSize            - the size of buffer.
    646     Number                - the number of the strings.
    647 
    648   Returns:
    649     EFI_BUFFER_TOO_SMALL  - the BufferSize is too small to operate.
    650     EFI_INVALID_PARAMETER - Buffer is NULL or BufferSize is 0.
    651     EFI_SUCCESS           - Operation successful.
    652 
    653 --*/
    654 {
    655   VA_LIST                         Args;
    656   UINTN                           Index;
    657   UINT32                          TotalLen;
    658   UINT8                           *BufCfgArray;
    659   UINT8                           *BufferPos;
    660   UINT16                          Offset;
    661   UINT16                          Width;
    662   UINT8                           *Value;
    663 
    664   if ((Buffer == NULL) || (BufferSize == NULL)) {
    665     return EFI_INVALID_PARAMETER;
    666   }
    667 
    668   Offset = 0;
    669   Width  = 0;
    670   Value  = NULL;
    671 
    672   VA_START (Args, Number);
    673   for (Index = 0; Index < Number; Index++) {
    674     BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
    675     EfiCopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
    676     BufferPos = BufCfgArray + sizeof (UINT32);
    677 
    678     while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
    679       EfiCopyMem (&Offset, BufferPos, sizeof (UINT16));
    680       BufferPos += sizeof (UINT16);
    681       EfiCopyMem (&Width, BufferPos, sizeof (UINT16));
    682       BufferPos += sizeof (UINT16);
    683       Value = BufferPos;
    684       BufferPos += Width;
    685 
    686       if ((UINTN)(Offset + Width) > *BufferSize) {
    687         VA_END (Args);
    688         return EFI_BUFFER_TOO_SMALL;
    689       }
    690 
    691       EfiCopyMem ((UINT8 *)Buffer + Offset, Value, Width);
    692     }
    693   }
    694   VA_END (Args);
    695 
    696   *BufferSize = (UINTN)Offset;
    697 
    698   return EFI_SUCCESS;
    699 }
    700 
    701 EFI_STATUS
    702 ExtractBlockName (
    703   IN UINT8                        *Buffer,
    704   OUT CHAR16                      **BlockName
    705   )
    706 /*++
    707 
    708   Routine Description:
    709 
    710     Extract block name from the array generated by VFR compiler. The name of
    711   this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".
    712   Format of this array is:
    713      Array length | 4-bytes
    714        Offset     | 2-bytes
    715        Width      | 2-bytes
    716        Offset     | 2-bytes
    717        Width      | 2-bytes
    718        ... ...
    719 
    720   Arguments:
    721     Buffer                - Array generated by VFR compiler.
    722     BlockName             - The returned <BlockName>
    723 
    724   Returns:
    725     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
    726     EFI_INVALID_PARAMETER - Buffer is NULL or BlockName is NULL.
    727     EFI_SUCCESS           - Operation successful.
    728 
    729 --*/
    730 {
    731   UINTN       Index;
    732   UINT32      Length;
    733   UINT32      BlockNameNumber;
    734   UINTN       HexStringBufferLen;
    735   CHAR16      *StringPtr;
    736 
    737   if ((Buffer == NULL) || (BlockName == NULL)) {
    738     return EFI_INVALID_PARAMETER;
    739   }
    740 
    741   //
    742   // Calculate number of Offset/Width pair
    743   //
    744   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
    745   BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);
    746 
    747   //
    748   // <BlockName> ::= &OFFSET=1234&WIDTH=1234
    749   //                 |   8  | 4 |  7   | 4 |
    750   //
    751   StringPtr = EfiLibAllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));
    752   *BlockName = StringPtr;
    753   if (StringPtr == NULL) {
    754     return EFI_OUT_OF_RESOURCES;
    755   }
    756 
    757   Buffer += sizeof (UINT32);
    758   for (Index = 0; Index < BlockNameNumber; Index++) {
    759     EfiStrCpy (StringPtr, L"&OFFSET=");
    760     StringPtr += 8;
    761 
    762     HexStringBufferLen = 5;
    763     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    764     Buffer += sizeof (UINT16);
    765     StringPtr += 4;
    766 
    767     EfiStrCpy (StringPtr, L"&WIDTH=");
    768     StringPtr += 7;
    769 
    770     HexStringBufferLen = 5;
    771     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    772     Buffer += sizeof (UINT16);
    773     StringPtr += 4;
    774   }
    775 
    776   return EFI_SUCCESS;
    777 }
    778 
    779 EFI_STATUS
    780 ExtractBlockConfig (
    781   IN UINT8                        *Buffer,
    782   OUT CHAR16                      **BlockConfig
    783   )
    784 /*++
    785 
    786   Routine Description:
    787 
    788     Extract block config from the array generated by VFR compiler. The name of
    789   this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".
    790 
    791   Arguments:
    792     Buffer                - Array generated by VFR compiler.
    793     BlockConfig           - The returned <BlockConfig>
    794 
    795   Returns:
    796     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
    797     EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.
    798     EFI_SUCCESS           - Operation successful.
    799 
    800 --*/
    801 {
    802   UINT32      Length;
    803   UINT16      Width;
    804   UINTN       HexStringBufferLen;
    805   CHAR16      *StringPtr;
    806   UINT8       *BufferEnd;
    807   CHAR16      *StringEnd;
    808   EFI_STATUS  Status;
    809 
    810   if ((Buffer == NULL) || (BlockConfig == NULL)) {
    811     return EFI_INVALID_PARAMETER;
    812   }
    813 
    814   //
    815   // Calculate length of AltResp string
    816   // Format of Default value array is:
    817   //  Array length | 4-bytes
    818   //        Offset | 2-bytes
    819   //        Width  | 2-bytes
    820   //        Value  | Variable length
    821   //        Offset | 2-bytes
    822   //        Width  | 2-bytes
    823   //        Value  | Variable length
    824   //        ... ...
    825   // When value is 1 byte in length, overhead of AltResp string will be maximum,
    826   //  BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+
    827   //                   |   8   | 4  |  7   | 4 |  7  |2|
    828   // so the maximum length of BlockConfig could be calculated as:
    829   // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7
    830   //
    831   EfiCopyMem (&Length, Buffer, sizeof (UINT32));
    832   BufferEnd = Buffer + Length;
    833   StringPtr = EfiLibAllocatePool (Length * 7 * sizeof (CHAR16));
    834   *BlockConfig = StringPtr;
    835   if (StringPtr == NULL) {
    836       return EFI_OUT_OF_RESOURCES;
    837   }
    838   StringEnd = StringPtr + (Length * 7);
    839 
    840   Buffer += sizeof (UINT32);
    841   while (Buffer < BufferEnd) {
    842     EfiStrCpy (StringPtr, L"&OFFSET=");
    843     StringPtr += 8;
    844 
    845     HexStringBufferLen = 5;
    846     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    847     Buffer += sizeof (UINT16);
    848     StringPtr += 4;
    849 
    850     EfiStrCpy (StringPtr, L"&WIDTH=");
    851     StringPtr += 7;
    852 
    853     HexStringBufferLen = 5;
    854     BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));
    855     EfiCopyMem (&Width, Buffer, sizeof (UINT16));
    856     Buffer += sizeof (UINT16);
    857     StringPtr += 4;
    858 
    859     EfiStrCpy (StringPtr, L"&VALUE=");
    860     StringPtr += 7;
    861 
    862     HexStringBufferLen = StringEnd - StringPtr;
    863     Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);
    864     if (EFI_ERROR (Status)) {
    865       return Status;
    866     }
    867     Buffer += Width;
    868     StringPtr += (Width * 2);
    869   }
    870 
    871   return EFI_SUCCESS;
    872 }
    873 
    874 EFI_STATUS
    875 ConstructConfigAltResp (
    876   IN  EFI_STRING                  ConfigRequest,  OPTIONAL
    877   OUT EFI_STRING                  *Progress,
    878   OUT EFI_STRING                  *ConfigAltResp,
    879   IN  EFI_GUID                    *Guid,
    880   IN  CHAR16                      *Name,
    881   IN  EFI_HANDLE                  *DriverHandle,
    882   IN  VOID                        *BufferStorage,
    883   IN  UINTN                       BufferStorageSize,
    884   IN  VOID                        *BlockNameArray, OPTIONAL
    885   IN  UINTN                       NumberAltCfg,
    886   ...
    887 //IN  UINT16                      AltCfgId,
    888 //IN  VOID                        *DefaultValueArray,
    889   )
    890 /*++
    891 
    892   Routine Description:
    893 
    894   Construct <ConfigAltResp> for a buffer storage.
    895 
    896   Arguments:
    897     ConfigRequest         - The Config request string. If set to NULL, all the
    898                             configurable elements will be extracted from BlockNameArray.
    899     ConfigAltResp         - The returned <ConfigAltResp>.
    900     Progress              - On return, points to a character in the Request.
    901     Guid                  - GUID of the buffer storage.
    902     Name                  - Name of the buffer storage.
    903     DriverHandle          - The DriverHandle which is used to invoke HiiDatabase
    904                             protocol interface NewPackageList().
    905     BufferStorage         - Content of the buffer storage.
    906     BufferStorageSize     - Length in bytes of the buffer storage.
    907     BlockNameArray        - Array generated by VFR compiler.
    908     NumberAltCfg          - Number of Default value array generated by VFR compiler.
    909                             The sequential input parameters will be number of
    910                             AltCfgId and DefaultValueArray pairs. When set to 0,
    911                             there will be no <AltResp>.
    912 
    913   Returns:
    914     EFI_OUT_OF_RESOURCES  - Run out of memory resource.
    915     EFI_INVALID_PARAMETER - ConfigAltResp is NULL.
    916     EFI_SUCCESS           - Operation successful.
    917 
    918 --*/
    919 {
    920   EFI_STATUS                      Status;
    921   CHAR16                          *ConfigHdr;
    922   CHAR16                          *BlockName;
    923   CHAR16                          *DescHdr;
    924   CHAR16                          *StringPtr;
    925   CHAR16                          **AltCfg;
    926   UINT16                          AltCfgId;
    927   VOID                            *DefaultValueArray;
    928   UINTN                           StrBufferLen;
    929   EFI_STRING                      ConfigResp;
    930   EFI_STRING                      TempStr;
    931   VA_LIST                         Args;
    932   UINTN                           AltRespLen;
    933   UINTN                           Index;
    934   BOOLEAN                         NeedFreeConfigRequest;
    935   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
    936 
    937   if (ConfigAltResp == NULL) {
    938     return EFI_INVALID_PARAMETER;
    939   }
    940 
    941   //
    942   // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."
    943   //
    944   ConfigHdr = NULL;
    945   StrBufferLen = 0;
    946   Status = ConstructConfigHdr (
    947              ConfigHdr,
    948              &StrBufferLen,
    949              Guid,
    950              Name,
    951              DriverHandle
    952              );
    953   if (Status == EFI_BUFFER_TOO_SMALL) {
    954     ConfigHdr = EfiLibAllocateZeroPool (StrBufferLen);
    955     Status = ConstructConfigHdr (
    956                ConfigHdr,
    957                &StrBufferLen,
    958                Guid,
    959                Name,
    960                DriverHandle
    961                );
    962   }
    963 
    964   if (EFI_ERROR (Status) || (ConfigHdr == NULL)) {
    965     return Status;
    966   }
    967 
    968   //
    969   // Construct <ConfigResp>
    970   //
    971   NeedFreeConfigRequest = FALSE;
    972   if (ConfigRequest == NULL) {
    973     //
    974     // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray
    975     //
    976     Status = ExtractBlockName (BlockNameArray, &BlockName);
    977     if (EFI_ERROR (Status)) {
    978       return Status;
    979     }
    980 
    981     StrBufferLen = EfiStrSize (ConfigHdr);
    982     StrBufferLen = StrBufferLen + EfiStrSize (BlockName) - sizeof (CHAR16);
    983     ConfigRequest = EfiLibAllocateZeroPool (StrBufferLen);
    984     EfiStrCpy (ConfigRequest, ConfigHdr);
    985     EfiStrCat (ConfigRequest, BlockName);
    986     NeedFreeConfigRequest = TRUE;
    987   }
    988 
    989   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
    990   if (EFI_ERROR (Status)) {
    991     return Status;
    992   }
    993 
    994   Status = HiiConfigRouting->BlockToConfig (
    995                                HiiConfigRouting,
    996                                ConfigRequest,
    997                                BufferStorage,
    998                                BufferStorageSize,
    999                                &ConfigResp,
   1000                                (Progress == NULL) ? &TempStr : Progress
   1001                                );
   1002   if (EFI_ERROR (Status)) {
   1003     return Status;
   1004   }
   1005 
   1006   //
   1007   // Construct <AltResp>
   1008   //
   1009   DescHdr = EfiLibAllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));
   1010   StringPtr = DescHdr;
   1011   AltCfg = EfiLibAllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));
   1012   AltRespLen = 0;
   1013   VA_START (Args, NumberAltCfg);
   1014   for (Index = 0; Index < NumberAltCfg; Index++) {
   1015     AltCfgId = (UINT16) VA_ARG (Args, UINT16);
   1016     DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);
   1017 
   1018     //
   1019     // '&' <ConfigHdr>
   1020     //
   1021     AltRespLen += (EfiStrLen (ConfigHdr) + 1);
   1022 
   1023     StringPtr = DescHdr + Index * 16;
   1024     EfiStrCpy (StringPtr, L"&ALTCFG=");
   1025     AltRespLen += (8 + sizeof (UINT16) * 2);
   1026 
   1027     StrBufferLen = 5;
   1028     BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));
   1029     Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);
   1030     if (EFI_ERROR (Status)) {
   1031       VA_END (Args);
   1032       return Status;
   1033     }
   1034     AltRespLen += EfiStrLen (AltCfg[Index]);
   1035   }
   1036   VA_END (Args);
   1037 
   1038   //
   1039   // Generate the final <ConfigAltResp>
   1040   //
   1041   StrBufferLen = (EfiStrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);
   1042   TempStr = EfiLibAllocateZeroPool (StrBufferLen);
   1043   *ConfigAltResp = TempStr;
   1044   if (TempStr == NULL) {
   1045     return EFI_OUT_OF_RESOURCES;
   1046   }
   1047 
   1048   //
   1049   // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*
   1050   //
   1051   EfiStrCpy (TempStr, ConfigResp);
   1052   for (Index = 0; Index < NumberAltCfg; Index++) {
   1053     EfiStrCat (TempStr, L"&");
   1054     EfiStrCat (TempStr, ConfigHdr);
   1055     EfiStrCat (TempStr, DescHdr + Index * 16);
   1056     EfiStrCat (TempStr, AltCfg[Index]);
   1057 
   1058     gBS->FreePool (AltCfg[Index]);
   1059   }
   1060 
   1061   if (NeedFreeConfigRequest) {
   1062     gBS->FreePool (ConfigRequest);
   1063   }
   1064   gBS->FreePool (ConfigHdr);
   1065   gBS->FreePool (ConfigResp);
   1066   gBS->FreePool (DescHdr);
   1067   gBS->FreePool (AltCfg);
   1068 
   1069   return EFI_SUCCESS;
   1070 }
   1071 
   1072 VOID
   1073 SwapBuffer (
   1074   IN OUT UINT8     *Buffer,
   1075   IN UINTN         BufferSize
   1076   )
   1077 /*++
   1078 
   1079 Routine Description:
   1080   Swap bytes in the buffer.
   1081 
   1082 Arguments:
   1083   Buffer     -  Binary buffer.
   1084   BufferSize -  Size of the buffer in bytes.
   1085 
   1086 Returns:
   1087   None.
   1088 
   1089 --*/
   1090 {
   1091   UINTN  Index;
   1092   UINT8  Temp;
   1093   UINTN  SwapCount;
   1094 
   1095   SwapCount = BufferSize / 2;
   1096   for (Index = 0; Index < SwapCount; Index++) {
   1097     Temp = Buffer[Index];
   1098     Buffer[Index] = Buffer[BufferSize - 1 - Index];
   1099     Buffer[BufferSize - 1 - Index] = Temp;
   1100   }
   1101 }
   1102 
   1103 VOID
   1104 ToLower (
   1105   IN OUT CHAR16    *Str
   1106   )
   1107 /*++
   1108 
   1109 Routine Description:
   1110   Converts the unicode character of the string from uppercase to lowercase.
   1111 
   1112 Arguments:
   1113   Str        -  String to be converted
   1114 
   1115 Returns:
   1116 
   1117 --*/
   1118 {
   1119   CHAR16      *Ptr;
   1120 
   1121   for (Ptr = Str; *Ptr != L'\0'; Ptr++) {
   1122     if (*Ptr >= L'A' && *Ptr <= L'Z') {
   1123       *Ptr = (CHAR16) (*Ptr - L'A' + L'a');
   1124     }
   1125   }
   1126 }
   1127 
   1128 EFI_STATUS
   1129 BufferToHexString (
   1130   IN OUT CHAR16    *Str,
   1131   IN UINT8         *Buffer,
   1132   IN UINTN         BufferSize
   1133   )
   1134 /*++
   1135 
   1136 Routine Description:
   1137   Converts binary buffer to Unicode string in reversed byte order from BufToHexString().
   1138 
   1139 Arguments:
   1140   Str        -  String for output
   1141   Buffer     -  Binary buffer.
   1142   BufferSize -  Size of the buffer in bytes.
   1143 
   1144 Returns:
   1145   EFI_SUCCESS  -  The function completed successfully.
   1146 
   1147 --*/
   1148 {
   1149   EFI_STATUS  Status;
   1150   UINT8       *NewBuffer;
   1151   UINTN       StrBufferLen;
   1152 
   1153   NewBuffer = EfiLibAllocateCopyPool (BufferSize, Buffer);
   1154   SwapBuffer (NewBuffer, BufferSize);
   1155 
   1156   StrBufferLen = BufferSize * 2 + 1;
   1157   Status = BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize);
   1158 
   1159   gBS->FreePool (NewBuffer);
   1160   //
   1161   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
   1162   //
   1163   ToLower (Str);
   1164 
   1165   return Status;
   1166 }
   1167 
   1168 EFI_STATUS
   1169 HexStringToBuffer (
   1170   IN OUT UINT8         *Buffer,
   1171   IN OUT UINTN         *BufferSize,
   1172   IN CHAR16            *Str
   1173   )
   1174 /*++
   1175 
   1176 Routine Description:
   1177   Converts Hex String to binary buffer in reversed byte order from HexStringToBuf().
   1178 
   1179 Arguments:
   1180     Buffer     - Pointer to buffer that receives the data.
   1181     BufferSize - Length in bytes of the buffer to hold converted data.
   1182                  If routine return with EFI_SUCCESS, containing length of converted data.
   1183                  If routine return with EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
   1184     Str        - String to be converted from.
   1185 
   1186 Returns:
   1187   EFI_SUCCESS    -  The function completed successfully.
   1188 
   1189 --*/
   1190 {
   1191   EFI_STATUS  Status;
   1192   UINTN       ConvertedStrLen;
   1193 
   1194   ConvertedStrLen = 0;
   1195   Status = HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen);
   1196   if (!EFI_ERROR (Status)) {
   1197     SwapBuffer (Buffer, (ConvertedStrLen + 1) / 2);
   1198   }
   1199 
   1200   return Status;
   1201 }
   1202 
   1203 EFI_STATUS
   1204 ConfigStringToUnicode (
   1205   IN OUT CHAR16                *UnicodeString,
   1206   IN OUT UINTN                 *StrBufferLen,
   1207   IN CHAR16                    *ConfigString
   1208   )
   1209 /*++
   1210 
   1211 Routine Description:
   1212   Convert binary representation Config string (e.g. "0041004200430044") to the
   1213   original string (e.g. "ABCD"). Config string appears in <ConfigHdr> (i.e.
   1214   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
   1215 
   1216 Arguments:
   1217   UnicodeString - Original Unicode string.
   1218   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
   1219                   Includes tailing '\0' character.
   1220                   On output:
   1221                     If return EFI_SUCCESS, containing length of Unicode string buffer.
   1222                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
   1223   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
   1224 
   1225 Returns:
   1226   EFI_SUCCESS          - Routine success.
   1227   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
   1228 
   1229 --*/
   1230 {
   1231   UINTN       Index;
   1232   UINTN       Len;
   1233   UINTN       BufferSize;
   1234   CHAR16      BackupChar;
   1235 
   1236   Len = EfiStrLen (ConfigString) / 4;
   1237   BufferSize = (Len + 1) * sizeof (CHAR16);
   1238 
   1239   if (*StrBufferLen < BufferSize) {
   1240     *StrBufferLen = BufferSize;
   1241     return EFI_BUFFER_TOO_SMALL;
   1242   }
   1243 
   1244   *StrBufferLen = BufferSize;
   1245 
   1246   for (Index = 0; Index < Len; Index++) {
   1247     BackupChar = ConfigString[4];
   1248     ConfigString[4] = L'\0';
   1249 
   1250     HexStringToBuf ((UINT8 *) UnicodeString, &BufferSize, ConfigString, NULL);
   1251 
   1252     ConfigString[4] = BackupChar;
   1253 
   1254     ConfigString += 4;
   1255     UnicodeString += 1;
   1256   }
   1257 
   1258   //
   1259   // Add tailing '\0' character
   1260   //
   1261   *UnicodeString = L'\0';
   1262 
   1263   return EFI_SUCCESS;
   1264 }
   1265 
   1266 EFI_STATUS
   1267 UnicodeToConfigString (
   1268   IN OUT CHAR16                *ConfigString,
   1269   IN OUT UINTN                 *StrBufferLen,
   1270   IN CHAR16                    *UnicodeString
   1271   )
   1272 /*++
   1273 
   1274 Routine Description:
   1275   Convert Unicode string to binary representation Config string, e.g.
   1276   "ABCD" => "0041004200430044". Config string appears in <ConfigHdr> (i.e.
   1277   "&NAME=<string>"), or Name/Value pair in <ConfigBody> (i.e. "label=<string>").
   1278 
   1279 Arguments:
   1280   ConfigString  - Binary representation of Unicode String, <string> := (<HexCh>4)+
   1281   StrBufferLen  - On input: Length in bytes of buffer to hold the Unicode string.
   1282                   Includes tailing '\0' character.
   1283                   On output:
   1284                     If return EFI_SUCCESS, containing length of Unicode string buffer.
   1285                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
   1286   UnicodeString - Original Unicode string.
   1287 
   1288 Returns:
   1289   EFI_SUCCESS          - Routine success.
   1290   EFI_BUFFER_TOO_SMALL - The string buffer is too small.
   1291 
   1292 --*/
   1293 {
   1294   UINTN       Index;
   1295   UINTN       Len;
   1296   UINTN       BufferSize;
   1297   CHAR16      *String;
   1298 
   1299   Len = EfiStrLen (UnicodeString);
   1300   BufferSize = (Len * 4 + 1) * sizeof (CHAR16);
   1301 
   1302   if (*StrBufferLen < BufferSize) {
   1303     *StrBufferLen = BufferSize;
   1304     return EFI_BUFFER_TOO_SMALL;
   1305   }
   1306 
   1307   *StrBufferLen = BufferSize;
   1308   String        = ConfigString;
   1309 
   1310   for (Index = 0; Index < Len; Index++) {
   1311     BufToHexString (ConfigString, &BufferSize, (UINT8 *) UnicodeString, 2);
   1312 
   1313     ConfigString += 4;
   1314     UnicodeString += 1;
   1315   }
   1316 
   1317   //
   1318   // Add tailing '\0' character
   1319   //
   1320   *ConfigString = L'\0';
   1321 
   1322   //
   1323   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
   1324   //
   1325   ToLower (String);
   1326   return EFI_SUCCESS;
   1327 }
   1328 
   1329 EFI_STATUS
   1330 ConstructConfigHdr (
   1331   IN OUT CHAR16                *ConfigHdr,
   1332   IN OUT UINTN                 *StrBufferLen,
   1333   IN EFI_GUID                  *Guid,
   1334   IN CHAR16                    *Name, OPTIONAL
   1335   IN EFI_HANDLE                *DriverHandle
   1336   )
   1337 /*++
   1338 
   1339 Routine Description:
   1340   Construct <ConfigHdr> using routing information GUID/NAME/PATH.
   1341 
   1342 Arguments:
   1343   ConfigHdr    - Pointer to the ConfigHdr string.
   1344   StrBufferLen - On input: Length in bytes of buffer to hold the ConfigHdr string.
   1345                  Includes tailing '\0' character.
   1346                  On output:
   1347                     If return EFI_SUCCESS, containing length of ConfigHdr string buffer.
   1348                     If return EFI_BUFFER_TOO_SMALL, containg length of string buffer desired.
   1349   Guid         - Routing information: GUID.
   1350   Name         - Routing information: NAME.
   1351   DriverHandle - Driver handle which contains the routing information: PATH.
   1352 
   1353 Returns:
   1354   EFI_SUCCESS          - Routine success.
   1355   EFI_BUFFER_TOO_SMALL - The ConfigHdr string buffer is too small.
   1356 
   1357 --*/
   1358 {
   1359   EFI_STATUS                Status;
   1360   UINTN                     NameStrLen;
   1361   UINTN                     DevicePathSize;
   1362   UINTN                     BufferSize;
   1363   CHAR16                    *StrPtr;
   1364   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   1365 
   1366   if (Name == NULL) {
   1367     //
   1368     // There will be no "NAME" in <ConfigHdr> for  Name/Value storage
   1369     //
   1370     NameStrLen = 0;
   1371   } else {
   1372     //
   1373     // For buffer storage
   1374     //
   1375     NameStrLen = EfiStrLen (Name);
   1376   }
   1377 
   1378   //
   1379   // Retrieve DevicePath Protocol associated with this HiiPackageList
   1380   //
   1381   Status = gBS->HandleProtocol (
   1382                   DriverHandle,
   1383                   &gEfiDevicePathProtocolGuid,
   1384                   (VOID **) &DevicePath
   1385                   );
   1386   if (EFI_ERROR (Status)) {
   1387     return Status;
   1388   }
   1389 
   1390   DevicePathSize = EfiDevicePathSize (DevicePath);
   1391 
   1392   //
   1393   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
   1394   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
   1395   //
   1396   BufferSize = (5 + 32 + 6 + NameStrLen * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16);
   1397   if (*StrBufferLen < BufferSize) {
   1398     *StrBufferLen = BufferSize;
   1399     return EFI_BUFFER_TOO_SMALL;
   1400   }
   1401 
   1402   if (ConfigHdr == NULL) {
   1403     return EFI_INVALID_PARAMETER;
   1404   }
   1405 
   1406   *StrBufferLen = BufferSize;
   1407 
   1408   StrPtr = ConfigHdr;
   1409 
   1410   EfiStrCpy (StrPtr, L"GUID=");
   1411   StrPtr += 5;
   1412   BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID));
   1413   StrPtr += 32;
   1414 
   1415   //
   1416   // Convert name string, e.g. name "ABCD" => "&NAME=0041004200430044"
   1417   //
   1418   EfiStrCpy (StrPtr, L"&NAME=");
   1419   StrPtr += 6;
   1420   if (Name != NULL) {
   1421     BufferSize = (NameStrLen * 4 + 1) * sizeof (CHAR16);
   1422     UnicodeToConfigString (StrPtr, &BufferSize, Name);
   1423     StrPtr += (NameStrLen * 4);
   1424   }
   1425 
   1426   EfiStrCpy (StrPtr, L"&PATH=");
   1427   StrPtr += 6;
   1428   BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize);
   1429 
   1430   return EFI_SUCCESS;
   1431 }
   1432 
   1433 BOOLEAN
   1434 IsConfigHdrMatch (
   1435   IN EFI_STRING                ConfigString,
   1436   IN EFI_GUID                  *StorageGuid, OPTIONAL
   1437   IN CHAR16                    *StorageName  OPTIONAL
   1438   )
   1439 /*++
   1440 
   1441 Routine Description:
   1442   Determines if the Routing data (Guid and Name) is correct in <ConfigHdr>.
   1443 
   1444 Arguments:
   1445   ConfigString - Either <ConfigRequest> or <ConfigResp>.
   1446   StorageGuid  - GUID of the storage.
   1447   StorageName  - Name of the stoarge.
   1448 
   1449 Returns:
   1450   TRUE         - Routing information is correct in ConfigString.
   1451   FALSE        - Routing information is incorrect in ConfigString.
   1452 
   1453 --*/
   1454 {
   1455   EFI_STATUS  Status;
   1456   BOOLEAN     Match;
   1457   EFI_GUID    Guid;
   1458   CHAR16      *Name;
   1459   CHAR16      *StrPtr;
   1460   UINTN       BufferSize;
   1461 
   1462   //
   1463   // <ConfigHdr> ::=
   1464   // GUID=<HexCh>32&NAME=<Char>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL>
   1465   // | 5  |   32   |  6  |  NameStrLen*4 |  6  |    DevicePathStrLen    | 1 |
   1466   //
   1467   if (EfiStrLen (ConfigString) <= (5 + 32 + 6)) {
   1468     return FALSE;
   1469   }
   1470 
   1471   //
   1472   // Compare GUID
   1473   //
   1474   if (StorageGuid != NULL) {
   1475 
   1476     StrPtr = ConfigString + 5 + 32;
   1477     if (*StrPtr != L'&') {
   1478       return FALSE;
   1479     }
   1480     *StrPtr = L'\0';
   1481 
   1482     BufferSize = sizeof (EFI_GUID);
   1483     Status = HexStringToBuffer (
   1484                (UINT8 *) &Guid,
   1485                &BufferSize,
   1486                ConfigString + 5
   1487                );
   1488     *StrPtr = L'&';
   1489 
   1490     if (EFI_ERROR (Status)) {
   1491       return FALSE;
   1492     }
   1493 
   1494     if (!EfiCompareGuid (&Guid, StorageGuid)) {
   1495       return FALSE;
   1496     }
   1497   }
   1498 
   1499   //
   1500   // Compare Name
   1501   //
   1502   Match = TRUE;
   1503   if (StorageName != NULL) {
   1504     StrPtr = ConfigString + 5 + 32 + 6;
   1505     while (*StrPtr != L'\0' && *StrPtr != L'&') {
   1506       StrPtr++;
   1507     }
   1508     if (*StrPtr != L'&') {
   1509       return FALSE;
   1510     }
   1511 
   1512     *StrPtr = L'\0';
   1513     BufferSize = (EfiStrLen (ConfigString + 5 + 32 + 6) + 1) * sizeof (CHAR16);
   1514     Name = EfiLibAllocatePool (BufferSize);
   1515     ASSERT (Name != NULL);
   1516     Status = ConfigStringToUnicode (
   1517                Name,
   1518                &BufferSize,
   1519                ConfigString + 5 + 32 + 6
   1520                );
   1521     *StrPtr = L'&';
   1522 
   1523     if (EFI_ERROR (Status) || (EfiStrCmp (Name, StorageName) != 0)) {
   1524       Match = FALSE;
   1525     }
   1526     gBS->FreePool (Name);
   1527   }
   1528 
   1529   return Match;
   1530 }
   1531 
   1532 BOOLEAN
   1533 FindBlockName (
   1534   IN OUT CHAR16                *String,
   1535   UINTN                        Offset,
   1536   UINTN                        Width
   1537   )
   1538 /*++
   1539 
   1540 Routine Description:
   1541   Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string.
   1542 
   1543 Arguments:
   1544   String       - The string to be searched in.
   1545   Offset       - Offset in BlockName.
   1546   Width        - Width in BlockName.
   1547 
   1548 Returns:
   1549   TRUE         - Block name found.
   1550   FALSE        - Block name not found.
   1551 
   1552 --*/
   1553 {
   1554   EFI_STATUS  Status;
   1555   UINTN       Data;
   1556   UINTN       BufferSize;
   1557   UINTN       ConvertedStrLen;
   1558 
   1559   while ((String = EfiStrStr (String, L"&OFFSET=")) != NULL) {
   1560     //
   1561     // Skip '&OFFSET='
   1562     //
   1563     String = String + 8;
   1564 
   1565     Data = 0;
   1566     BufferSize = sizeof (UINTN);
   1567     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
   1568     if (EFI_ERROR (Status)) {
   1569       return FALSE;
   1570     }
   1571     String = String + ConvertedStrLen;
   1572 
   1573     if (Data != Offset) {
   1574       continue;
   1575     }
   1576 
   1577     if (EfiStrnCmp (String, L"&WIDTH=", 7) != 0) {
   1578       return FALSE;
   1579     }
   1580     String = String + 7;
   1581 
   1582     Data = 0;
   1583     BufferSize = sizeof (UINTN);
   1584     Status = HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen);
   1585     if (EFI_ERROR (Status)) {
   1586       return FALSE;
   1587     }
   1588     if (Data == Width) {
   1589       return TRUE;
   1590     }
   1591 
   1592     String = String + ConvertedStrLen;
   1593   }
   1594 
   1595   return FALSE;
   1596 }
   1597 
   1598 EFI_STATUS
   1599 GetBrowserData (
   1600   EFI_GUID                   *VariableGuid, OPTIONAL
   1601   CHAR16                     *VariableName, OPTIONAL
   1602   UINTN                      *BufferSize,
   1603   UINT8                      *Buffer
   1604   )
   1605 /*++
   1606 
   1607 Routine Description:
   1608   This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser.
   1609 
   1610 Arguments:
   1611   VariableGuid  - An optional field to indicate the target variable GUID name to use.
   1612   VariableName  - An optional field to indicate the target human-readable variable name.
   1613   BufferSize    - On input: Length in bytes of buffer to hold retrived data.
   1614                   On output:
   1615                     If return EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
   1616   Buffer        - Buffer to hold retrived data.
   1617 
   1618 Returns:
   1619   EFI_SUCCESS          - Routine success.
   1620   EFI_BUFFER_TOO_SMALL - The intput buffer is too small.
   1621 
   1622 --*/
   1623 {
   1624   EFI_STATUS                      Status;
   1625   CHAR16                          *ConfigHdr;
   1626   CHAR16                          *ConfigResp;
   1627   CHAR16                          *StringPtr;
   1628   UINTN                           HeaderLen;
   1629   UINTN                           BufferLen;
   1630   CHAR16                          *Progress;
   1631   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
   1632   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
   1633 
   1634   //
   1635   // Locate protocols for use
   1636   //
   1637   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
   1638   if (EFI_ERROR (Status)) {
   1639     return Status;
   1640   }
   1641 
   1642   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
   1643   if (EFI_ERROR (Status)) {
   1644     return Status;
   1645   }
   1646 
   1647   //
   1648   // Retrive formset storage data from Form Browser
   1649   //
   1650   ConfigHdr = mFakeConfigHdr;
   1651   HeaderLen = EfiStrLen (ConfigHdr);
   1652 
   1653   BufferLen = 0x4000;
   1654   ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
   1655 
   1656   StringPtr = ConfigResp + HeaderLen;
   1657   *StringPtr = L'&';
   1658   StringPtr++;
   1659 
   1660   Status = FormBrowser2->BrowserCallback (
   1661                            FormBrowser2,
   1662                            &BufferLen,
   1663                            StringPtr,
   1664                            TRUE,
   1665                            VariableGuid,
   1666                            VariableName
   1667                            );
   1668   if (Status == EFI_BUFFER_TOO_SMALL) {
   1669     gBS->FreePool (ConfigResp);
   1670     ConfigResp = EfiLibAllocateZeroPool (BufferLen + (HeaderLen + 1) * sizeof (CHAR16));
   1671 
   1672     StringPtr = ConfigResp + HeaderLen;
   1673     *StringPtr = L'&';
   1674     StringPtr++;
   1675 
   1676     Status = FormBrowser2->BrowserCallback (
   1677                              FormBrowser2,
   1678                              &BufferLen,
   1679                              StringPtr,
   1680                              TRUE,
   1681                              VariableGuid,
   1682                              VariableName
   1683                              );
   1684   }
   1685   if (EFI_ERROR (Status)) {
   1686     gBS->FreePool (ConfigResp);
   1687     return Status;
   1688   }
   1689   EfiCopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16));
   1690 
   1691   //
   1692   // Convert <ConfigResp> to buffer data
   1693   //
   1694   Status = HiiConfigRouting->ConfigToBlock (
   1695                                HiiConfigRouting,
   1696                                ConfigResp,
   1697                                Buffer,
   1698                                BufferSize,
   1699                                &Progress
   1700                                );
   1701   gBS->FreePool (ConfigResp);
   1702 
   1703   return Status;
   1704 }
   1705 
   1706 EFI_STATUS
   1707 SetBrowserData (
   1708   EFI_GUID                   *VariableGuid, OPTIONAL
   1709   CHAR16                     *VariableName, OPTIONAL
   1710   UINTN                      BufferSize,
   1711   UINT8                      *Buffer,
   1712   CHAR16                     *RequestElement  OPTIONAL
   1713   )
   1714 /*++
   1715 
   1716 Routine Description:
   1717   This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser.
   1718 
   1719 Arguments:
   1720   VariableGuid   - An optional field to indicate the target variable GUID name to use.
   1721   VariableName   - An optional field to indicate the target human-readable variable name.
   1722   BufferSize     - Length in bytes of buffer to hold retrived data.
   1723   Buffer         - Buffer to hold retrived data.
   1724   RequestElement - An optional field to specify which part of the buffer data
   1725                    will be send back to Browser. If NULL, the whole buffer of
   1726                    data will be committed to Browser.
   1727                    <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
   1728 
   1729 Returns:
   1730   EFI_SUCCESS  - Routine success.
   1731   Other        - Updating Browser uncommitted data failed.
   1732 
   1733 --*/
   1734 {
   1735   EFI_STATUS                      Status;
   1736   CHAR16                          *ConfigHdr;
   1737   CHAR16                          *ConfigResp;
   1738   CHAR16                          *StringPtr;
   1739   UINTN                           HeaderLen;
   1740   UINTN                           BufferLen;
   1741   CHAR16                          *Progress;
   1742   EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;
   1743   EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
   1744   CHAR16                          BlockName[33];
   1745   CHAR16                          *ConfigRequest;
   1746   CHAR16                          *Request;
   1747 
   1748   //
   1749   // Locate protocols for use
   1750   //
   1751   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
   1752   if (EFI_ERROR (Status)) {
   1753     return Status;
   1754   }
   1755 
   1756   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
   1757   if (EFI_ERROR (Status)) {
   1758     return Status;
   1759   }
   1760 
   1761   //
   1762   // Prepare <ConfigRequest>
   1763   //
   1764   ConfigHdr = mFakeConfigHdr;
   1765   HeaderLen = EfiStrLen (ConfigHdr);
   1766 
   1767   if (RequestElement == NULL) {
   1768     //
   1769     // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName>
   1770     //
   1771     BlockName[0] = L'\0';
   1772     EfiStrCpy (BlockName, L"&OFFSET=0&WIDTH=");
   1773 
   1774     //
   1775     // String lenghth of L"&OFFSET=0&WIDTH=" is 16
   1776     //
   1777     StringPtr = BlockName + 16;
   1778     BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16));
   1779     BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN));
   1780 
   1781     Request = BlockName;
   1782   } else {
   1783     Request = RequestElement;
   1784   }
   1785 
   1786   BufferLen = HeaderLen * sizeof (CHAR16) + EfiStrSize (Request);
   1787   ConfigRequest = EfiLibAllocateZeroPool (BufferLen);
   1788 
   1789   EfiCopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16));
   1790   StringPtr = ConfigRequest + HeaderLen;
   1791   EfiStrCpy (StringPtr, Request);
   1792 
   1793   //
   1794   // Convert buffer to <ConfigResp>
   1795   //
   1796   Status = HiiConfigRouting->BlockToConfig (
   1797                                 HiiConfigRouting,
   1798                                 ConfigRequest,
   1799                                 Buffer,
   1800                                 BufferSize,
   1801                                 &ConfigResp,
   1802                                 &Progress
   1803                                 );
   1804   if (EFI_ERROR (Status)) {
   1805     gBS->FreePool (ConfigRequest);
   1806     return Status;
   1807   }
   1808 
   1809   //
   1810   // Skip <ConfigHdr> and '&'
   1811   //
   1812   StringPtr = ConfigResp + HeaderLen + 1;
   1813 
   1814   //
   1815   // Change uncommitted data in Browser
   1816   //
   1817   Status = FormBrowser2->BrowserCallback (
   1818                            FormBrowser2,
   1819                            &BufferSize,
   1820                            StringPtr,
   1821                            FALSE,
   1822                            VariableGuid,
   1823                            VariableName
   1824                            );
   1825   gBS->FreePool (ConfigResp);
   1826   gBS->FreePool (ConfigRequest);
   1827   return Status;
   1828 }
   1829