Home | History | Annotate | Download | only in HiiDatabaseDxe
      1 /** @file
      2 Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL.
      3 
      4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 
     16 #include "HiiDatabase.h"
     17 
     18 extern HII_DATABASE_PRIVATE_DATA mPrivate;
     19 
     20 /**
     21   Convert the hex UNICODE %02x encoding of a UEFI device path to binary
     22   from <PathHdr> of <MultiKeywordRequest>.
     23 
     24   This is a internal function.
     25 
     26   @param  String                 MultiKeywordRequest string.
     27   @param  DevicePathData         Binary of a UEFI device path.
     28   @param  NextString             string follow the possible PathHdr string.
     29 
     30   @retval EFI_INVALID_PARAMETER  The device path is not valid or the incoming parameter is invalid.
     31   @retval EFI_OUT_OF_RESOURCES   Lake of resources to store necessary structures.
     32   @retval EFI_SUCCESS            The device path is retrieved and translated to binary format.
     33                                  The Input string not include PathHdr section.
     34 
     35 **/
     36 EFI_STATUS
     37 ExtractDevicePath (
     38   IN  EFI_STRING                   String,
     39   OUT UINT8                        **DevicePathData,
     40   OUT EFI_STRING                   *NextString
     41   )
     42 {
     43   UINTN                    Length;
     44   EFI_STRING               PathHdr;
     45   UINT8                    *DevicePathBuffer;
     46   CHAR16                   TemStr[2];
     47   UINTN                    Index;
     48   UINT8                    DigitUint8;
     49   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
     50 
     51   ASSERT (NextString != NULL && DevicePathData != NULL);
     52 
     53   //
     54   // KeywordRequest == NULL case.
     55   //
     56   if (String == NULL) {
     57     *DevicePathData = NULL;
     58     *NextString = NULL;
     59     return EFI_SUCCESS;
     60   }
     61 
     62   //
     63   // Skip '&' if exist.
     64   //
     65   if (*String == L'&') {
     66     String ++;
     67   }
     68 
     69   //
     70   // Find the 'PATH=' of <PathHdr>.
     71   //
     72   if (StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0) {
     73     if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
     74       return EFI_INVALID_PARAMETER;
     75     } else {
     76       //
     77       // Not include PathHdr, return success and DevicePath = NULL.
     78       //
     79       *DevicePathData = NULL;
     80       *NextString = String;
     81       return EFI_SUCCESS;
     82     }
     83   }
     84 
     85   //
     86   // Check whether path data does exist.
     87   //
     88   String += StrLen (L"PATH=");
     89   if (*String == 0) {
     90     return EFI_INVALID_PARAMETER;
     91   }
     92   PathHdr = String;
     93 
     94   //
     95   // The content between 'PATH=' of <ConfigHdr> and '&' of next element
     96   // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
     97   // of UEFI device path.
     98   //
     99   for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
    100 
    101   //
    102   // Save the return next keyword string value.
    103   //
    104   *NextString = String;
    105 
    106   //
    107   // Check DevicePath Length
    108   //
    109   if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
    110     return EFI_INVALID_PARAMETER;
    111   }
    112 
    113   //
    114   // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
    115   // as the device path resides in RAM memory.
    116   // Translate the data into binary.
    117   //
    118   DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
    119   if (DevicePathBuffer == NULL) {
    120     return EFI_OUT_OF_RESOURCES;
    121   }
    122 
    123   //
    124   // Convert DevicePath
    125   //
    126   ZeroMem (TemStr, sizeof (TemStr));
    127   for (Index = 0; Index < Length; Index ++) {
    128     TemStr[0] = PathHdr[Index];
    129     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
    130     if ((Index & 1) == 0) {
    131       DevicePathBuffer [Index/2] = DigitUint8;
    132     } else {
    133       DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
    134     }
    135   }
    136 
    137   //
    138   // Validate DevicePath
    139   //
    140   DevicePath  = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
    141   while (!IsDevicePathEnd (DevicePath)) {
    142     if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
    143       //
    144       // Invalid device path
    145       //
    146       FreePool (DevicePathBuffer);
    147       return EFI_INVALID_PARAMETER;
    148     }
    149     DevicePath = NextDevicePathNode (DevicePath);
    150   }
    151 
    152   //
    153   // return the device path
    154   //
    155   *DevicePathData = DevicePathBuffer;
    156 
    157   return EFI_SUCCESS;
    158 }
    159 
    160 /**
    161   Get NameSpace from the input NameSpaceId string.
    162 
    163   This is a internal function.
    164 
    165   @param  String                 <NameSpaceId> format string.
    166   @param  NameSpace              Return the name space string.
    167   @param  NextString             Return the next string follow namespace.
    168 
    169   @retval   EFI_SUCCESS             Get the namespace string success.
    170   @retval   EFI_INVALID_PARAMETER   The NameSpaceId string not follow spec definition.
    171 
    172 **/
    173 EFI_STATUS
    174 ExtractNameSpace (
    175   IN  EFI_STRING                   String,
    176   OUT CHAR8                        **NameSpace,
    177   OUT EFI_STRING                   *NextString
    178   )
    179 {
    180   CHAR16    *TmpPtr;
    181   UINTN     NameSpaceSize;
    182 
    183   ASSERT (NameSpace != NULL);
    184 
    185   TmpPtr = NULL;
    186 
    187   //
    188   // Input NameSpaceId == NULL
    189   //
    190   if (String == NULL) {
    191     *NameSpace = NULL;
    192     if (NextString != NULL) {
    193       *NextString = NULL;
    194     }
    195     return EFI_SUCCESS;
    196   }
    197 
    198   //
    199   // Skip '&' if exist.
    200   //
    201   if (*String == L'&') {
    202     String++;
    203   }
    204 
    205   if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) {
    206     return EFI_INVALID_PARAMETER;
    207   }
    208   String += StrLen (L"NAMESPACE=");
    209 
    210   TmpPtr = StrStr (String, L"&");
    211   if (TmpPtr != NULL) {
    212     *TmpPtr = 0;
    213   }
    214   if (NextString != NULL) {
    215     *NextString = String + StrLen (String);
    216   }
    217 
    218   //
    219   // Input NameSpace is unicode string. The language in String package is ascii string.
    220   // Here will convert the unicode string to ascii and save it.
    221   //
    222   NameSpaceSize = StrLen (String) + 1;
    223   *NameSpace = AllocatePool (NameSpaceSize);
    224   if (*NameSpace == NULL) {
    225     return EFI_OUT_OF_RESOURCES;
    226   }
    227   UnicodeStrToAsciiStrS (String, *NameSpace, NameSpaceSize);
    228 
    229   if (TmpPtr != NULL) {
    230     *TmpPtr = L'&';
    231   }
    232 
    233   return EFI_SUCCESS;
    234 }
    235 
    236 /**
    237   Get Keyword from the input KeywordRequest string.
    238 
    239   This is a internal function.
    240 
    241   @param  String                 KeywordRequestformat string.
    242   @param  Keyword                return the extract keyword string.
    243   @param  NextString             return the next string follow this keyword section.
    244 
    245   @retval EFI_SUCCESS            Success to get the keyword string.
    246   @retval EFI_INVALID_PARAMETER  Parse the input string return error.
    247 
    248 **/
    249 EFI_STATUS
    250 ExtractKeyword (
    251   IN  EFI_STRING                   String,
    252   OUT EFI_STRING                   *Keyword,
    253   OUT EFI_STRING                   *NextString
    254   )
    255 {
    256   EFI_STRING  TmpPtr;
    257 
    258   ASSERT ((Keyword != NULL) && (NextString != NULL));
    259 
    260   TmpPtr = NULL;
    261 
    262   //
    263   // KeywordRequest == NULL case.
    264   //
    265   if (String == NULL) {
    266     *Keyword = NULL;
    267     *NextString = NULL;
    268     return EFI_SUCCESS;
    269   }
    270 
    271   //
    272   // Skip '&' if exist.
    273   //
    274   if (*String == L'&') {
    275     String++;
    276   }
    277 
    278   if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
    279     return EFI_INVALID_PARAMETER;
    280   }
    281 
    282   String += StrLen (L"KEYWORD=");
    283 
    284   TmpPtr = StrStr (String, L"&");
    285   if (TmpPtr != NULL) {
    286     *TmpPtr = 0;
    287   }
    288   *NextString = String + StrLen (String);
    289 
    290   *Keyword = AllocateCopyPool (StrSize (String), String);
    291   if (*Keyword == NULL) {
    292     return EFI_OUT_OF_RESOURCES;
    293   }
    294 
    295   if (TmpPtr != NULL) {
    296     *TmpPtr = L'&';
    297   }
    298 
    299   return EFI_SUCCESS;
    300 }
    301 
    302 /**
    303   Get value from the input KeywordRequest string.
    304 
    305   This is a internal function.
    306 
    307   @param  String                 KeywordRequestformat string.
    308   @param  Value                  return the extract value string.
    309   @param  NextString             return the next string follow this keyword section.
    310 
    311   @retval EFI_SUCCESS            Success to get the keyword string.
    312   @retval EFI_INVALID_PARAMETER  Parse the input string return error.
    313 
    314 **/
    315 EFI_STATUS
    316 ExtractValue (
    317   IN  EFI_STRING                   String,
    318   OUT EFI_STRING                   *Value,
    319   OUT EFI_STRING                   *NextString
    320   )
    321 {
    322   EFI_STRING  TmpPtr;
    323 
    324   ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL));
    325 
    326   //
    327   // Skip '&' if exist.
    328   //
    329   if (*String == L'&') {
    330     String++;
    331   }
    332 
    333   if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) {
    334     return EFI_INVALID_PARAMETER;
    335   }
    336 
    337   String += StrLen (L"VALUE=");
    338 
    339   TmpPtr = StrStr (String, L"&");
    340   if (TmpPtr != NULL) {
    341     *TmpPtr = 0;
    342   }
    343   *NextString = String + StrLen (String);
    344 
    345   *Value = AllocateCopyPool (StrSize (String), String);
    346   if (*Value == NULL) {
    347     return EFI_OUT_OF_RESOURCES;
    348   }
    349 
    350   if (TmpPtr != NULL) {
    351     *TmpPtr = L'&';
    352   }
    353 
    354   return EFI_SUCCESS;
    355 }
    356 
    357 /**
    358   Get filter from the input KeywordRequest string.
    359 
    360   This is a internal function.
    361 
    362   @param  String                 KeywordRequestformat string.
    363   @param  FilterFlags            return the filter condition.
    364   @param  NextString             return the next string follow this keyword section.
    365 
    366   @retval EFI_SUCCESS            Success to get the keyword string.
    367   @retval EFI_INVALID_PARAMETER  Parse the input string return error.
    368 
    369 **/
    370 BOOLEAN
    371 ExtractFilter (
    372   IN  EFI_STRING                   String,
    373   OUT UINT8                        *FilterFlags,
    374   OUT EFI_STRING                   *NextString
    375   )
    376 {
    377   CHAR16      *PathPtr;
    378   CHAR16      *KeywordPtr;
    379   BOOLEAN     RetVal;
    380 
    381   ASSERT ((FilterFlags != NULL) && (NextString != NULL));
    382 
    383   //
    384   // String end, no filter section.
    385   //
    386   if (String == NULL) {
    387     *NextString = NULL;
    388     return FALSE;
    389   }
    390 
    391   *FilterFlags = 0;
    392   RetVal = TRUE;
    393 
    394   //
    395   // Skip '&' if exist.
    396   //
    397   if (*String == L'&') {
    398     String++;
    399   }
    400 
    401   if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) {
    402     //
    403     // Find ReadOnly filter.
    404     //
    405     *FilterFlags |= EFI_KEYWORD_FILTER_READONY;
    406     String += StrLen (L"ReadOnly");
    407   } else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) {
    408     //
    409     // Find ReadWrite filter.
    410     //
    411     *FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE;
    412     String += StrLen (L"ReadWrite");
    413   } else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) {
    414     //
    415     // Find Buffer Filter.
    416     //
    417     *FilterFlags |= EFI_KEYWORD_FILTER_BUFFER;
    418     String += StrLen (L"Buffer");
    419   } else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) {
    420     //
    421     // Find Numeric Filter
    422     //
    423     String += StrLen (L"Numeric");
    424     if (*String != L':') {
    425       *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC;
    426     } else {
    427       String++;
    428       switch (*String) {
    429       case L'1':
    430         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1;
    431         break;
    432       case L'2':
    433         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2;
    434         break;
    435       case L'4':
    436         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4;
    437         break;
    438       case L'8':
    439         *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8;
    440         break;
    441       default:
    442         ASSERT (FALSE);
    443         break;
    444       }
    445       String++;
    446     }
    447   } else {
    448     //
    449     // Check whether other filter item defined by Platform.
    450     //
    451     if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) ||
    452         (StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) {
    453       //
    454       // New KeywordRequest start, no platform defined filter.
    455       //
    456     } else {
    457       //
    458       // Platform defined filter rule.
    459       // Just skip platform defined filter rule, return success.
    460       //
    461       PathPtr = StrStr(String, L"&PATH");
    462       KeywordPtr = StrStr(String, L"&KEYWORD");
    463       if (PathPtr != NULL && KeywordPtr != NULL) {
    464         //
    465         // If both sections exist, return the first follow string.
    466         //
    467         String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr;
    468       } else if (PathPtr != NULL) {
    469         //
    470         // Should not exist PathPtr != NULL && KeywordPtr == NULL case.
    471         //
    472         ASSERT (FALSE);
    473       } else if (KeywordPtr != NULL) {
    474         //
    475         // Just to the next keyword section.
    476         //
    477         String = KeywordPtr;
    478       } else {
    479         //
    480         // Only has platform defined filter section, just skip it.
    481         //
    482         String += StrLen (String);
    483       }
    484     }
    485     RetVal = FALSE;
    486   }
    487 
    488   *NextString = String;
    489 
    490   return RetVal;
    491 }
    492 
    493 /**
    494   Extract Readonly flag from opcode.
    495 
    496   This is a internal function.
    497 
    498   @param  OpCodeData             Input opcode for this question.
    499 
    500   @retval TRUE                   This question is readonly.
    501   @retval FALSE                  This question is not readonly.
    502 
    503 **/
    504 BOOLEAN
    505 ExtractReadOnlyFromOpCode (
    506   IN  UINT8         *OpCodeData
    507   )
    508 {
    509   EFI_IFR_QUESTION_HEADER   *QuestionHdr;
    510 
    511   ASSERT (OpCodeData != NULL);
    512 
    513   QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
    514 
    515   return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0;
    516 }
    517 
    518 /**
    519   Create a circuit to check the filter section.
    520 
    521   This is a internal function.
    522 
    523   @param  OpCodeData             The question binary ifr data.
    524   @param  KeywordRequest         KeywordRequestformat string.
    525   @param  NextString             return the next string follow this keyword section.
    526   @param  ReadOnly               Return whether this question is read only.
    527 
    528   @retval KEYWORD_HANDLER_NO_ERROR                     Success validate.
    529   @retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED  Validate fail.
    530 
    531 **/
    532 UINT32
    533 ValidateFilter (
    534   IN  UINT8         *OpCodeData,
    535   IN  CHAR16        *KeywordRequest,
    536   OUT CHAR16        **NextString,
    537   OUT BOOLEAN       *ReadOnly
    538   )
    539 {
    540   CHAR16                    *NextFilter;
    541   CHAR16                    *StringPtr;
    542   UINT8                     FilterFlags;
    543   EFI_IFR_QUESTION_HEADER   *QuestionHdr;
    544   EFI_IFR_OP_HEADER         *OpCodeHdr;
    545   UINT8                     Flags;
    546   UINT32                    RetVal;
    547 
    548   RetVal = KEYWORD_HANDLER_NO_ERROR;
    549   StringPtr = KeywordRequest;
    550 
    551   OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData;
    552   QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
    553   if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
    554     Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER));
    555   } else {
    556     Flags = 0;
    557   }
    558 
    559   //
    560   // Get ReadOnly flag from Question.
    561   //
    562   *ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData);
    563 
    564   while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) {
    565     switch (FilterFlags) {
    566     case EFI_KEYWORD_FILTER_READONY:
    567       if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) {
    568         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    569         goto Done;
    570       }
    571       break;
    572 
    573     case EFI_KEYWORD_FILTER_REAWRITE:
    574       if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) {
    575         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    576         goto Done;
    577       }
    578       break;
    579 
    580     case EFI_KEYWORD_FILTER_BUFFER:
    581       //
    582       // Only these three opcode use numeric value type.
    583       //
    584       if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) {
    585         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    586         goto Done;
    587       }
    588       break;
    589 
    590     case EFI_KEYWORD_FILTER_NUMERIC:
    591       if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
    592         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    593         goto Done;
    594       }
    595       break;
    596 
    597     case EFI_KEYWORD_FILTER_NUMERIC_1:
    598     case EFI_KEYWORD_FILTER_NUMERIC_2:
    599     case EFI_KEYWORD_FILTER_NUMERIC_4:
    600     case EFI_KEYWORD_FILTER_NUMERIC_8:
    601       if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
    602         RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    603         goto Done;
    604       }
    605 
    606       //
    607       // For numeric and oneof, it has flags field to specify the detail numeric type.
    608       //
    609       if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
    610         switch (Flags & EFI_IFR_NUMERIC_SIZE) {
    611         case EFI_IFR_NUMERIC_SIZE_1:
    612           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) {
    613             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    614             goto Done;
    615           }
    616           break;
    617 
    618         case EFI_IFR_NUMERIC_SIZE_2:
    619           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) {
    620             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    621             goto Done;
    622           }
    623           break;
    624 
    625         case EFI_IFR_NUMERIC_SIZE_4:
    626           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) {
    627             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    628             goto Done;
    629           }
    630           break;
    631 
    632         case EFI_IFR_NUMERIC_SIZE_8:
    633           if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) {
    634             RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
    635             goto Done;
    636           }
    637           break;
    638 
    639         default:
    640           ASSERT (FALSE);
    641           break;
    642         }
    643       }
    644       break;
    645 
    646     default:
    647       ASSERT (FALSE);
    648       break;
    649     }
    650 
    651     //
    652     // Jump to the next filter.
    653     //
    654     StringPtr = NextFilter;
    655   }
    656 
    657 Done:
    658   //
    659   // The current filter which is processing.
    660   //
    661   *NextString = StringPtr;
    662 
    663   return RetVal;
    664 }
    665 
    666 /**
    667   Get HII_DATABASE_RECORD from the input device path info.
    668 
    669   This is a internal function.
    670 
    671   @param  DevicePath             UEFI device path protocol.
    672 
    673   @retval Internal data base record.
    674 
    675 **/
    676 HII_DATABASE_RECORD *
    677 GetRecordFromDevicePath (
    678   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
    679   )
    680 {
    681   LIST_ENTRY             *Link;
    682   UINT8                  *DevicePathPkg;
    683   UINT8                  *CurrentDevicePath;
    684   UINTN                  DevicePathSize;
    685   HII_DATABASE_RECORD    *TempDatabase;
    686 
    687   ASSERT (DevicePath != NULL);
    688 
    689   for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
    690     TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
    691     DevicePathPkg = TempDatabase->PackageList->DevicePathPkg;
    692     if (DevicePathPkg != NULL) {
    693       CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
    694       DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
    695       if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) {
    696         return TempDatabase;
    697       }
    698     }
    699   }
    700 
    701   return NULL;
    702 }
    703 
    704 /**
    705   Calculate the size of StringSrc and output it. Also copy string text from src
    706   to dest.
    707 
    708   This is a internal function.
    709 
    710   @param  StringSrc              Points to current null-terminated string.
    711   @param  BufferSize             Length of the buffer.
    712   @param  StringDest             Buffer to store the string text.
    713 
    714   @retval EFI_SUCCESS            The string text was outputted successfully.
    715   @retval EFI_OUT_OF_RESOURCES   Out of resource.
    716 
    717 **/
    718 EFI_STATUS
    719 GetUnicodeStringTextAndSize (
    720   IN  UINT8            *StringSrc,
    721   OUT UINTN            *BufferSize,
    722   OUT EFI_STRING       *StringDest
    723   )
    724 {
    725   UINTN  StringSize;
    726   UINT8  *StringPtr;
    727 
    728   ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL);
    729 
    730   StringSize = sizeof (CHAR16);
    731   StringPtr  = StringSrc;
    732   while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) {
    733     StringSize += sizeof (CHAR16);
    734     StringPtr += sizeof (CHAR16);
    735   }
    736 
    737   *StringDest = AllocatePool (StringSize);
    738   if (*StringDest == NULL) {
    739     return EFI_OUT_OF_RESOURCES;
    740   }
    741 
    742   CopyMem (*StringDest, StringSrc, StringSize);
    743 
    744   *BufferSize = StringSize;
    745   return EFI_SUCCESS;
    746 }
    747 
    748 /**
    749   Find the string id for the input keyword.
    750 
    751   @param  StringPackage           Hii string package instance.
    752   @param  KeywordValue            Input keyword value.
    753   @param  StringId                The string's id, which is unique within PackageList.
    754 
    755 
    756   @retval EFI_SUCCESS             The string text and font is retrieved
    757                                   successfully.
    758   @retval EFI_NOT_FOUND           The specified text or font info can not be found
    759                                   out.
    760   @retval EFI_OUT_OF_RESOURCES    The system is out of resources to accomplish the
    761                                   task.
    762 **/
    763 EFI_STATUS
    764 GetStringIdFromString (
    765   IN HII_STRING_PACKAGE_INSTANCE      *StringPackage,
    766   IN CHAR16                           *KeywordValue,
    767   OUT EFI_STRING_ID                   *StringId
    768   )
    769 {
    770   UINT8                                *BlockHdr;
    771   EFI_STRING_ID                        CurrentStringId;
    772   UINTN                                BlockSize;
    773   UINTN                                Index;
    774   UINT8                                *StringTextPtr;
    775   UINTN                                Offset;
    776   UINT16                               StringCount;
    777   UINT16                               SkipCount;
    778   UINT8                                Length8;
    779   EFI_HII_SIBT_EXT2_BLOCK              Ext2;
    780   UINT32                               Length32;
    781   UINTN                                StringSize;
    782   CHAR16                               *String;
    783   CHAR8                                *AsciiKeywordValue;
    784   UINTN                                KeywordValueSize;
    785   EFI_STATUS                           Status;
    786 
    787   ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL);
    788   ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
    789 
    790   CurrentStringId = 1;
    791   Status = EFI_SUCCESS;
    792   String = NULL;
    793   BlockHdr = StringPackage->StringBlock;
    794   BlockSize = 0;
    795   Offset = 0;
    796 
    797   //
    798   // Make a ascii keyword value for later use.
    799   //
    800   KeywordValueSize = StrLen (KeywordValue) + 1;
    801   AsciiKeywordValue = AllocatePool (KeywordValueSize);
    802   if (AsciiKeywordValue == NULL) {
    803     return EFI_OUT_OF_RESOURCES;
    804   }
    805   UnicodeStrToAsciiStrS (KeywordValue, AsciiKeywordValue, KeywordValueSize);
    806 
    807   while (*BlockHdr != EFI_HII_SIBT_END) {
    808     switch (*BlockHdr) {
    809     case EFI_HII_SIBT_STRING_SCSU:
    810       Offset = sizeof (EFI_HII_STRING_BLOCK);
    811       StringTextPtr = BlockHdr + Offset;
    812       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
    813       if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
    814         *StringId = CurrentStringId;
    815         goto Done;
    816       }
    817       CurrentStringId++;
    818       break;
    819 
    820     case EFI_HII_SIBT_STRING_SCSU_FONT:
    821       Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
    822       StringTextPtr = BlockHdr + Offset;
    823       if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
    824         *StringId = CurrentStringId;
    825         goto Done;
    826       }
    827       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
    828       CurrentStringId++;
    829       break;
    830 
    831     case EFI_HII_SIBT_STRINGS_SCSU:
    832       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
    833       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
    834       BlockSize += StringTextPtr - BlockHdr;
    835 
    836       for (Index = 0; Index < StringCount; Index++) {
    837         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
    838         if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
    839           *StringId = CurrentStringId;
    840           goto Done;
    841         }
    842         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
    843         CurrentStringId++;
    844       }
    845       break;
    846 
    847     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
    848       CopyMem (
    849         &StringCount,
    850         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    851         sizeof (UINT16)
    852         );
    853       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
    854       BlockSize += StringTextPtr - BlockHdr;
    855 
    856       for (Index = 0; Index < StringCount; Index++) {
    857         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
    858         if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
    859           *StringId = CurrentStringId;
    860           goto Done;
    861         }
    862         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
    863         CurrentStringId++;
    864       }
    865       break;
    866 
    867     case EFI_HII_SIBT_STRING_UCS2:
    868       Offset        = sizeof (EFI_HII_STRING_BLOCK);
    869       StringTextPtr = BlockHdr + Offset;
    870       //
    871       // Use StringSize to store the size of the specified string, including the NULL
    872       // terminator.
    873       //
    874       Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
    875       if (EFI_ERROR (Status)) {
    876         goto Done;
    877       }
    878       ASSERT (String != NULL);
    879       if (StrCmp(KeywordValue, String) == 0) {
    880         *StringId = CurrentStringId;
    881         goto Done;
    882       }
    883       BlockSize += Offset + StringSize;
    884       CurrentStringId++;
    885       break;
    886 
    887     case EFI_HII_SIBT_STRING_UCS2_FONT:
    888       Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK)  - sizeof (CHAR16);
    889       StringTextPtr = BlockHdr + Offset;
    890       //
    891       // Use StringSize to store the size of the specified string, including the NULL
    892       // terminator.
    893       //
    894       Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
    895       if (EFI_ERROR (Status)) {
    896         goto Done;
    897       }
    898       ASSERT (String != NULL);
    899       if (StrCmp(KeywordValue, String) == 0) {
    900         *StringId = CurrentStringId;
    901         goto Done;
    902       }
    903       BlockSize += Offset + StringSize;
    904       CurrentStringId++;
    905       break;
    906 
    907     case EFI_HII_SIBT_STRINGS_UCS2:
    908       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
    909       StringTextPtr = BlockHdr + Offset;
    910       BlockSize += Offset;
    911       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
    912       for (Index = 0; Index < StringCount; Index++) {
    913         Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
    914         if (EFI_ERROR (Status)) {
    915           goto Done;
    916         }
    917         ASSERT (String != NULL);
    918         BlockSize += StringSize;
    919         if (StrCmp(KeywordValue, String) == 0) {
    920           *StringId = CurrentStringId;
    921           goto Done;
    922         }
    923         StringTextPtr = StringTextPtr + StringSize;
    924         CurrentStringId++;
    925       }
    926       break;
    927 
    928     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
    929       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
    930       StringTextPtr = BlockHdr + Offset;
    931       BlockSize += Offset;
    932       CopyMem (
    933         &StringCount,
    934         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    935         sizeof (UINT16)
    936         );
    937       for (Index = 0; Index < StringCount; Index++) {
    938         Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
    939         if (EFI_ERROR (Status)) {
    940           goto Done;
    941         }
    942         ASSERT (String != NULL);
    943         BlockSize += StringSize;
    944         if (StrCmp(KeywordValue, String) == 0) {
    945           *StringId = CurrentStringId;
    946           goto Done;
    947         }
    948         StringTextPtr = StringTextPtr + StringSize;
    949         CurrentStringId++;
    950       }
    951       break;
    952 
    953     case EFI_HII_SIBT_DUPLICATE:
    954       BlockSize       += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
    955       CurrentStringId++;
    956       break;
    957 
    958     case EFI_HII_SIBT_SKIP1:
    959       SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
    960       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
    961       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
    962       break;
    963 
    964     case EFI_HII_SIBT_SKIP2:
    965       CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
    966       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
    967       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
    968       break;
    969 
    970     case EFI_HII_SIBT_EXT1:
    971       CopyMem (
    972         &Length8,
    973         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    974         sizeof (UINT8)
    975         );
    976       BlockSize += Length8;
    977       break;
    978 
    979     case EFI_HII_SIBT_EXT2:
    980       CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
    981       BlockSize += Ext2.Length;
    982       break;
    983 
    984     case EFI_HII_SIBT_EXT4:
    985       CopyMem (
    986         &Length32,
    987         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
    988         sizeof (UINT32)
    989         );
    990 
    991       BlockSize += Length32;
    992       break;
    993 
    994     default:
    995       break;
    996     }
    997 
    998     if (String != NULL) {
    999       FreePool (String);
   1000       String = NULL;
   1001     }
   1002 
   1003     BlockHdr  = StringPackage->StringBlock + BlockSize;
   1004   }
   1005 
   1006   Status = EFI_NOT_FOUND;
   1007 
   1008 Done:
   1009   if (AsciiKeywordValue != NULL) {
   1010     FreePool (AsciiKeywordValue);
   1011   }
   1012   if (String != NULL) {
   1013     FreePool (String);
   1014   }
   1015   return Status;
   1016 }
   1017 
   1018 /**
   1019   Find the next valid string id for the input string id.
   1020 
   1021   @param  StringPackage           Hii string package instance.
   1022   @param  StringId                The current string id which is already got.
   1023                                   1 means just begin to get the string id.
   1024   @param  KeywordValue            Return the string for the next string id.
   1025 
   1026 
   1027   @retval EFI_STRING_ID           Not 0 means a valid stringid found.
   1028                                   0 means not found a valid string id.
   1029 **/
   1030 EFI_STRING_ID
   1031 GetNextStringId (
   1032   IN  HII_STRING_PACKAGE_INSTANCE      *StringPackage,
   1033   IN  EFI_STRING_ID                    StringId,
   1034   OUT EFI_STRING                       *KeywordValue
   1035   )
   1036 {
   1037   UINT8                                *BlockHdr;
   1038   EFI_STRING_ID                        CurrentStringId;
   1039   UINTN                                BlockSize;
   1040   UINTN                                Index;
   1041   UINT8                                *StringTextPtr;
   1042   UINTN                                Offset;
   1043   UINT16                               StringCount;
   1044   UINT16                               SkipCount;
   1045   UINT8                                Length8;
   1046   EFI_HII_SIBT_EXT2_BLOCK              Ext2;
   1047   UINT32                               Length32;
   1048   BOOLEAN                              FindString;
   1049   UINTN                                StringSize;
   1050   CHAR16                               *String;
   1051 
   1052   ASSERT (StringPackage != NULL);
   1053   ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
   1054 
   1055   CurrentStringId = 1;
   1056   FindString = FALSE;
   1057   String = NULL;
   1058 
   1059   //
   1060   // Parse the string blocks to get the string text and font.
   1061   //
   1062   BlockHdr  = StringPackage->StringBlock;
   1063   BlockSize = 0;
   1064   Offset    = 0;
   1065   while (*BlockHdr != EFI_HII_SIBT_END) {
   1066     switch (*BlockHdr) {
   1067     case EFI_HII_SIBT_STRING_SCSU:
   1068       Offset = sizeof (EFI_HII_STRING_BLOCK);
   1069       StringTextPtr = BlockHdr + Offset;
   1070 
   1071       if (FindString) {
   1072         StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
   1073         *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
   1074         if (*KeywordValue == NULL) {
   1075           return 0;
   1076         }
   1077         AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
   1078         return CurrentStringId;
   1079       } else if (CurrentStringId == StringId) {
   1080         FindString = TRUE;
   1081       }
   1082 
   1083       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
   1084       CurrentStringId++;
   1085       break;
   1086 
   1087     case EFI_HII_SIBT_STRING_SCSU_FONT:
   1088       Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
   1089       StringTextPtr = BlockHdr + Offset;
   1090 
   1091       if (FindString) {
   1092         StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
   1093         *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
   1094         if (*KeywordValue == NULL) {
   1095           return 0;
   1096         }
   1097         AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
   1098         return CurrentStringId;
   1099       } else if (CurrentStringId == StringId) {
   1100         FindString = TRUE;
   1101       }
   1102 
   1103       BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
   1104       CurrentStringId++;
   1105       break;
   1106 
   1107     case EFI_HII_SIBT_STRINGS_SCSU:
   1108       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
   1109       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
   1110       BlockSize += StringTextPtr - BlockHdr;
   1111 
   1112       for (Index = 0; Index < StringCount; Index++) {
   1113         if (FindString) {
   1114           StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
   1115           *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
   1116           if (*KeywordValue == NULL) {
   1117             return 0;
   1118           }
   1119           AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
   1120           return CurrentStringId;
   1121         } else if (CurrentStringId == StringId) {
   1122           FindString = TRUE;
   1123         }
   1124 
   1125         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
   1126         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
   1127         CurrentStringId++;
   1128       }
   1129       break;
   1130 
   1131     case EFI_HII_SIBT_STRINGS_SCSU_FONT:
   1132       CopyMem (
   1133         &StringCount,
   1134         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
   1135         sizeof (UINT16)
   1136         );
   1137       StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
   1138       BlockSize += StringTextPtr - BlockHdr;
   1139 
   1140       for (Index = 0; Index < StringCount; Index++) {
   1141         if (FindString) {
   1142           StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr);
   1143           *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16));
   1144           if (*KeywordValue == NULL) {
   1145             return 0;
   1146           }
   1147           AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize);
   1148           return CurrentStringId;
   1149         } else if (CurrentStringId == StringId) {
   1150           FindString = TRUE;
   1151         }
   1152 
   1153         BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
   1154         StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
   1155         CurrentStringId++;
   1156       }
   1157       break;
   1158 
   1159     case EFI_HII_SIBT_STRING_UCS2:
   1160       Offset        = sizeof (EFI_HII_STRING_BLOCK);
   1161       StringTextPtr = BlockHdr + Offset;
   1162       //
   1163       // Use StringSize to store the size of the specified string, including the NULL
   1164       // terminator.
   1165       //
   1166       GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
   1167       if (FindString && (String != NULL) && (*String != L'\0')) {
   1168         //
   1169         // String protocol use this type for the string id which has value for other package.
   1170         // It will allocate an empty string block for this string id. so here we also check
   1171         // *String != L'\0' to prohibit this case.
   1172         //
   1173         *KeywordValue = String;
   1174         return CurrentStringId;
   1175       } else if (CurrentStringId == StringId) {
   1176         FindString = TRUE;
   1177       }
   1178 
   1179       BlockSize += Offset + StringSize;
   1180       CurrentStringId++;
   1181       break;
   1182 
   1183     case EFI_HII_SIBT_STRING_UCS2_FONT:
   1184       Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK)  - sizeof (CHAR16);
   1185       StringTextPtr = BlockHdr + Offset;
   1186       //
   1187       // Use StringSize to store the size of the specified string, including the NULL
   1188       // terminator.
   1189       //
   1190       GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
   1191       if (FindString) {
   1192         *KeywordValue = String;
   1193         return CurrentStringId;
   1194       } else if (CurrentStringId == StringId) {
   1195         FindString = TRUE;
   1196       }
   1197 
   1198       BlockSize += Offset + StringSize;
   1199       CurrentStringId++;
   1200       break;
   1201 
   1202     case EFI_HII_SIBT_STRINGS_UCS2:
   1203       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
   1204       StringTextPtr = BlockHdr + Offset;
   1205       BlockSize += Offset;
   1206       CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
   1207       for (Index = 0; Index < StringCount; Index++) {
   1208         GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
   1209 
   1210         if (FindString) {
   1211           *KeywordValue = String;
   1212           return CurrentStringId;
   1213         } else if (CurrentStringId == StringId) {
   1214           FindString = TRUE;
   1215         }
   1216 
   1217         BlockSize += StringSize;
   1218         StringTextPtr = StringTextPtr + StringSize;
   1219         CurrentStringId++;
   1220       }
   1221       break;
   1222 
   1223     case EFI_HII_SIBT_STRINGS_UCS2_FONT:
   1224       Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
   1225       StringTextPtr = BlockHdr + Offset;
   1226       BlockSize += Offset;
   1227       CopyMem (
   1228         &StringCount,
   1229         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
   1230         sizeof (UINT16)
   1231         );
   1232       for (Index = 0; Index < StringCount; Index++) {
   1233         GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
   1234         if (FindString) {
   1235           *KeywordValue = String;
   1236           return CurrentStringId;
   1237         } else if (CurrentStringId == StringId) {
   1238           FindString = TRUE;
   1239         }
   1240 
   1241         BlockSize += StringSize;
   1242         StringTextPtr = StringTextPtr + StringSize;
   1243         CurrentStringId++;
   1244       }
   1245       break;
   1246 
   1247     case EFI_HII_SIBT_DUPLICATE:
   1248       BlockSize       += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
   1249       CurrentStringId++;
   1250       break;
   1251 
   1252     case EFI_HII_SIBT_SKIP1:
   1253       SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
   1254       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
   1255       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
   1256       break;
   1257 
   1258     case EFI_HII_SIBT_SKIP2:
   1259       CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
   1260       CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
   1261       BlockSize       +=  sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
   1262       break;
   1263 
   1264     case EFI_HII_SIBT_EXT1:
   1265       CopyMem (
   1266         &Length8,
   1267         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
   1268         sizeof (UINT8)
   1269         );
   1270       BlockSize += Length8;
   1271       break;
   1272 
   1273     case EFI_HII_SIBT_EXT2:
   1274       CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
   1275       BlockSize += Ext2.Length;
   1276       break;
   1277 
   1278     case EFI_HII_SIBT_EXT4:
   1279       CopyMem (
   1280         &Length32,
   1281         (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
   1282         sizeof (UINT32)
   1283         );
   1284 
   1285       BlockSize += Length32;
   1286       break;
   1287 
   1288     default:
   1289       break;
   1290     }
   1291 
   1292     if (String != NULL) {
   1293       FreePool (String);
   1294       String = NULL;
   1295     }
   1296 
   1297     BlockHdr  = StringPackage->StringBlock + BlockSize;
   1298   }
   1299 
   1300   return 0;
   1301 }
   1302 
   1303 /**
   1304   Get string package from the input NameSpace string.
   1305 
   1306   This is a internal function.
   1307 
   1308   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
   1309   @param  NameSpace                      NameSpace format string.
   1310   @param  KeywordValue                   Keyword value.
   1311   @param  StringId                       String Id for this keyword.
   1312 
   1313   @retval KEYWORD_HANDLER_NO_ERROR                     Get String id successfully.
   1314   @retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND            Not found the string id in the string package.
   1315   @retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND       Not found the string package for this namespace.
   1316   @retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR   Out of resource error.
   1317 
   1318 **/
   1319 UINT32
   1320 GetStringIdFromRecord (
   1321   IN HII_DATABASE_RECORD   *DatabaseRecord,
   1322   IN CHAR8                 **NameSpace,
   1323   IN CHAR16                *KeywordValue,
   1324   OUT EFI_STRING_ID        *StringId
   1325   )
   1326 {
   1327   LIST_ENTRY                          *Link;
   1328   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1329   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   1330   EFI_STATUS                          Status;
   1331   CHAR8                               *Name;
   1332   UINT32                              RetVal;
   1333 
   1334   ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL);
   1335 
   1336   PackageListNode = DatabaseRecord->PackageList;
   1337   RetVal = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
   1338 
   1339   if (*NameSpace != NULL) {
   1340     Name = *NameSpace;
   1341   } else {
   1342     Name = UEFI_CONFIG_LANG;
   1343   }
   1344 
   1345   for (Link = PackageListNode->StringPkgHdr.ForwardLink; Link != &PackageListNode->StringPkgHdr; Link = Link->ForwardLink) {
   1346     StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   1347 
   1348     if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) {
   1349       Status = GetStringIdFromString (StringPackage, KeywordValue, StringId);
   1350       if (EFI_ERROR (Status)) {
   1351         return KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
   1352       } else {
   1353         if (*NameSpace == NULL) {
   1354           *NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
   1355           if (*NameSpace == NULL) {
   1356             return KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
   1357           }
   1358         }
   1359         return KEYWORD_HANDLER_NO_ERROR;
   1360       }
   1361     }
   1362   }
   1363 
   1364   return RetVal;
   1365 }
   1366 
   1367 /**
   1368   Tell whether this Operand is an Statement OpCode.
   1369 
   1370   @param  Operand                Operand of an IFR OpCode.
   1371 
   1372   @retval TRUE                   This is an Statement OpCode.
   1373   @retval FALSE                  Not an Statement OpCode.
   1374 
   1375 **/
   1376 BOOLEAN
   1377 IsStatementOpCode (
   1378   IN UINT8              Operand
   1379   )
   1380 {
   1381   if ((Operand == EFI_IFR_SUBTITLE_OP) ||
   1382       (Operand == EFI_IFR_TEXT_OP) ||
   1383       (Operand == EFI_IFR_RESET_BUTTON_OP) ||
   1384       (Operand == EFI_IFR_REF_OP) ||
   1385       (Operand == EFI_IFR_ACTION_OP) ||
   1386       (Operand == EFI_IFR_NUMERIC_OP) ||
   1387       (Operand == EFI_IFR_ORDERED_LIST_OP) ||
   1388       (Operand == EFI_IFR_CHECKBOX_OP) ||
   1389       (Operand == EFI_IFR_STRING_OP) ||
   1390       (Operand == EFI_IFR_PASSWORD_OP) ||
   1391       (Operand == EFI_IFR_DATE_OP) ||
   1392       (Operand == EFI_IFR_TIME_OP) ||
   1393       (Operand == EFI_IFR_GUID_OP) ||
   1394       (Operand == EFI_IFR_ONE_OF_OP)) {
   1395     return TRUE;
   1396   }
   1397 
   1398   return FALSE;
   1399 }
   1400 
   1401 /**
   1402   Tell whether this Operand is an Statement OpCode.
   1403 
   1404   @param  Operand                Operand of an IFR OpCode.
   1405 
   1406   @retval TRUE                   This is an Statement OpCode.
   1407   @retval FALSE                  Not an Statement OpCode.
   1408 
   1409 **/
   1410 BOOLEAN
   1411 IsStorageOpCode (
   1412   IN UINT8              Operand
   1413   )
   1414 {
   1415   if ((Operand == EFI_IFR_VARSTORE_OP) ||
   1416       (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
   1417       (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
   1418     return TRUE;
   1419   }
   1420 
   1421   return FALSE;
   1422 }
   1423 
   1424 /**
   1425   Base on the prompt string id to find the question.
   1426 
   1427   @param  FormPackage            The input form package.
   1428   @param  KeywordStrId           The input prompt string id for one question.
   1429 
   1430   @retval  the opcode for the question.
   1431 
   1432 **/
   1433 UINT8 *
   1434 FindQuestionFromStringId (
   1435   IN HII_IFR_PACKAGE_INSTANCE      *FormPackage,
   1436   IN EFI_STRING_ID                 KeywordStrId
   1437   )
   1438 {
   1439   UINT8                        *OpCodeData;
   1440   UINT32                       Offset;
   1441   EFI_IFR_STATEMENT_HEADER     *StatementHeader;
   1442   EFI_IFR_OP_HEADER            *OpCodeHeader;
   1443   UINT32                       FormDataLen;
   1444 
   1445   ASSERT (FormPackage != NULL);
   1446 
   1447   FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
   1448   Offset = 0;
   1449   while (Offset < FormDataLen) {
   1450     OpCodeData = FormPackage->IfrData + Offset;
   1451     OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
   1452 
   1453     if (IsStatementOpCode(OpCodeHeader->OpCode)) {
   1454       StatementHeader = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
   1455       if (StatementHeader->Prompt == KeywordStrId) {
   1456         return OpCodeData;
   1457       }
   1458     }
   1459 
   1460     Offset += OpCodeHeader->Length;
   1461   }
   1462 
   1463   return NULL;
   1464 }
   1465 
   1466 /**
   1467   Base on the varstore id to find the storage info.
   1468 
   1469   @param  FormPackage            The input form package.
   1470   @param  VarStoreId             The input storage id.
   1471 
   1472   @retval  the opcode for the storage.
   1473 
   1474 **/
   1475 UINT8 *
   1476 FindStorageFromVarId (
   1477   IN HII_IFR_PACKAGE_INSTANCE      *FormPackage,
   1478   IN EFI_VARSTORE_ID               VarStoreId
   1479   )
   1480 {
   1481   UINT8                        *OpCodeData;
   1482   UINT32                       Offset;
   1483   EFI_IFR_OP_HEADER            *OpCodeHeader;
   1484   UINT32                       FormDataLen;
   1485 
   1486   ASSERT (FormPackage != NULL);
   1487 
   1488   FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
   1489   Offset = 0;
   1490   while (Offset < FormDataLen) {
   1491     OpCodeData = FormPackage->IfrData + Offset;
   1492     OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
   1493 
   1494     if (IsStorageOpCode(OpCodeHeader->OpCode)) {
   1495       switch (OpCodeHeader->OpCode) {
   1496       case EFI_IFR_VARSTORE_OP:
   1497         if (VarStoreId == ((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId) {
   1498           return OpCodeData;
   1499         }
   1500         break;
   1501 
   1502       case EFI_IFR_VARSTORE_NAME_VALUE_OP:
   1503         if (VarStoreId == ((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId) {
   1504           return OpCodeData;
   1505         }
   1506         break;
   1507 
   1508       case EFI_IFR_VARSTORE_EFI_OP:
   1509         if (VarStoreId == ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId) {
   1510           return OpCodeData;
   1511         }
   1512         break;
   1513 
   1514       default:
   1515         break;
   1516       }
   1517     }
   1518 
   1519     Offset += OpCodeHeader->Length;
   1520   }
   1521 
   1522   return NULL;
   1523 }
   1524 
   1525 /**
   1526   Get width info for one question.
   1527 
   1528   @param  OpCodeData            The input opcode for one question.
   1529 
   1530   @retval  the width info for one question.
   1531 
   1532 **/
   1533 UINT16
   1534 GetWidth (
   1535   IN UINT8        *OpCodeData
   1536   )
   1537 {
   1538   UINT8      *NextOpCodeData;
   1539 
   1540   ASSERT (OpCodeData != NULL);
   1541 
   1542   switch (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode) {
   1543   case EFI_IFR_REF_OP:
   1544     return (UINT16) sizeof (EFI_HII_REF);
   1545 
   1546   case EFI_IFR_ONE_OF_OP:
   1547   case EFI_IFR_NUMERIC_OP:
   1548     switch (((EFI_IFR_ONE_OF *) OpCodeData)->Flags & EFI_IFR_NUMERIC_SIZE) {
   1549     case EFI_IFR_NUMERIC_SIZE_1:
   1550       return (UINT16) sizeof (UINT8);
   1551 
   1552     case EFI_IFR_NUMERIC_SIZE_2:
   1553       return  (UINT16) sizeof (UINT16);
   1554 
   1555     case EFI_IFR_NUMERIC_SIZE_4:
   1556       return (UINT16) sizeof (UINT32);
   1557 
   1558     case EFI_IFR_NUMERIC_SIZE_8:
   1559       return (UINT16) sizeof (UINT64);
   1560 
   1561     default:
   1562       ASSERT (FALSE);
   1563       return 0;
   1564     }
   1565 
   1566   case EFI_IFR_ORDERED_LIST_OP:
   1567     NextOpCodeData = OpCodeData + ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Header.Length;
   1568     //
   1569     // OneOfOption must follow the orderedlist opcode.
   1570     //
   1571     ASSERT (((EFI_IFR_OP_HEADER *) NextOpCodeData)->OpCode == EFI_IFR_ONE_OF_OPTION_OP);
   1572     switch (((EFI_IFR_ONE_OF_OPTION *) NextOpCodeData)->Type) {
   1573     case EFI_IFR_TYPE_NUM_SIZE_8:
   1574       return (UINT16) sizeof (UINT8) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
   1575 
   1576     case EFI_IFR_TYPE_NUM_SIZE_16:
   1577       return (UINT16) sizeof (UINT16) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers ;
   1578 
   1579     case EFI_IFR_TYPE_NUM_SIZE_32:
   1580       return (UINT16) sizeof (UINT32) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
   1581 
   1582     case EFI_IFR_TYPE_NUM_SIZE_64:
   1583       return (UINT16) sizeof (UINT64) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
   1584 
   1585     default:
   1586       ASSERT (FALSE);
   1587       return 0;
   1588     }
   1589 
   1590   case EFI_IFR_CHECKBOX_OP:
   1591     return (UINT16) sizeof (BOOLEAN);
   1592 
   1593   case EFI_IFR_PASSWORD_OP:
   1594     return (UINT16)((UINTN) ((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize * sizeof (CHAR16));
   1595 
   1596   case EFI_IFR_STRING_OP:
   1597     return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16));
   1598 
   1599   case EFI_IFR_DATE_OP:
   1600     return (UINT16) sizeof (EFI_HII_DATE);
   1601 
   1602   case EFI_IFR_TIME_OP:
   1603     return (UINT16) sizeof (EFI_HII_TIME);
   1604 
   1605   default:
   1606     ASSERT (FALSE);
   1607     return 0;
   1608   }
   1609 }
   1610 
   1611 /**
   1612   Converts all hex string characters in range ['A'..'F'] to ['a'..'f'] for
   1613   hex digits that appear between a '=' and a '&' in a config string.
   1614 
   1615   If ConfigString is NULL, then ASSERT().
   1616 
   1617   @param[in] ConfigString  Pointer to a Null-terminated Unicode string.
   1618 
   1619   @return  Pointer to the Null-terminated Unicode result string.
   1620 
   1621 **/
   1622 EFI_STRING
   1623 EFIAPI
   1624 InternalLowerConfigString (
   1625   IN EFI_STRING  ConfigString
   1626   )
   1627 {
   1628   EFI_STRING  String;
   1629   BOOLEAN     Lower;
   1630 
   1631   ASSERT (ConfigString != NULL);
   1632 
   1633   //
   1634   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
   1635   //
   1636   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
   1637     if (*String == L'=') {
   1638       Lower = TRUE;
   1639     } else if (*String == L'&') {
   1640       Lower = FALSE;
   1641     } else if (Lower && *String >= L'A' && *String <= L'F') {
   1642       *String = (CHAR16) (*String - L'A' + L'a');
   1643     }
   1644   }
   1645 
   1646   return ConfigString;
   1647 }
   1648 
   1649 /**
   1650   Allocates and returns a Null-terminated Unicode <ConfigHdr> string.
   1651 
   1652   The format of a <ConfigHdr> is as follows:
   1653 
   1654     GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
   1655 
   1656   @param[in]  OpCodeData    The opcode for the storage.
   1657   @param[in]  DriverHandle  The driver handle which supports a Device Path Protocol
   1658                             that is the routing information PATH.  Each byte of
   1659                             the Device Path associated with DriverHandle is converted
   1660                             to a 2 Unicode character hexadecimal string.
   1661 
   1662   @retval NULL   DriverHandle does not support the Device Path Protocol.
   1663   @retval Other  A pointer to the Null-terminate Unicode <ConfigHdr> string
   1664 
   1665 **/
   1666 EFI_STRING
   1667 ConstructConfigHdr (
   1668   IN UINT8           *OpCodeData,
   1669   IN EFI_HANDLE      DriverHandle
   1670   )
   1671 {
   1672   UINTN                     NameLength;
   1673   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   1674   UINTN                     DevicePathSize;
   1675   CHAR16                    *String;
   1676   CHAR16                    *ReturnString;
   1677   UINTN                     Index;
   1678   UINT8                     *Buffer;
   1679   CHAR16                    *Name;
   1680   CHAR8                     *AsciiName;
   1681   UINTN                     NameSize;
   1682   EFI_GUID                  *Guid;
   1683   UINTN                     MaxLen;
   1684 
   1685   ASSERT (OpCodeData != NULL);
   1686 
   1687   switch (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode) {
   1688   case EFI_IFR_VARSTORE_OP:
   1689     Guid      = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE *) OpCodeData)->Guid;
   1690     AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
   1691     break;
   1692 
   1693   case EFI_IFR_VARSTORE_NAME_VALUE_OP:
   1694     Guid      = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid;
   1695     AsciiName = NULL;
   1696     break;
   1697 
   1698   case EFI_IFR_VARSTORE_EFI_OP:
   1699     Guid      = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid;
   1700     AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
   1701     break;
   1702 
   1703   default:
   1704     ASSERT (FALSE);
   1705     Guid      = NULL;
   1706     AsciiName = NULL;
   1707     break;
   1708   }
   1709 
   1710   if (AsciiName != NULL) {
   1711     NameSize = AsciiStrSize (AsciiName);
   1712     Name = AllocateZeroPool (NameSize * sizeof (CHAR16));
   1713     ASSERT (Name != NULL);
   1714     AsciiStrToUnicodeStrS (AsciiName, Name, NameSize);
   1715   } else {
   1716     Name = NULL;
   1717   }
   1718 
   1719   //
   1720   // Compute the length of Name in Unicode characters.
   1721   // If Name is NULL, then the length is 0.
   1722   //
   1723   NameLength = 0;
   1724   if (Name != NULL) {
   1725     NameLength = StrLen (Name);
   1726   }
   1727 
   1728   DevicePath = NULL;
   1729   DevicePathSize = 0;
   1730   //
   1731   // Retrieve DevicePath Protocol associated with DriverHandle
   1732   //
   1733   if (DriverHandle != NULL) {
   1734     DevicePath = DevicePathFromHandle (DriverHandle);
   1735     if (DevicePath == NULL) {
   1736       return NULL;
   1737     }
   1738     //
   1739     // Compute the size of the device path in bytes
   1740     //
   1741     DevicePathSize = GetDevicePathSize (DevicePath);
   1742   }
   1743 
   1744   //
   1745   // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
   1746   // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
   1747   //
   1748   MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
   1749   String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1750   if (String == NULL) {
   1751     return NULL;
   1752   }
   1753 
   1754   //
   1755   // Start with L"GUID="
   1756   //
   1757   StrCpyS (String, MaxLen, L"GUID=");
   1758   ReturnString = String;
   1759   String += StrLen (String);
   1760 
   1761   if (Guid != NULL) {
   1762     //
   1763     // Append Guid converted to <HexCh>32
   1764     //
   1765     for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
   1766       String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
   1767     }
   1768   }
   1769 
   1770   //
   1771   // Append L"&NAME="
   1772   //
   1773   StrCatS (ReturnString, MaxLen, L"&NAME=");
   1774   String += StrLen (String);
   1775 
   1776   if (Name != NULL) {
   1777     //
   1778     // Append Name converted to <Char>NameLength
   1779     //
   1780     for (; *Name != L'\0'; Name++) {
   1781       String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4);
   1782     }
   1783   }
   1784 
   1785   //
   1786   // Append L"&PATH="
   1787   //
   1788   StrCatS (ReturnString, MaxLen, L"&PATH=");
   1789   String += StrLen (String);
   1790 
   1791   //
   1792   // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
   1793   //
   1794   for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
   1795     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
   1796   }
   1797 
   1798   //
   1799   // Null terminate the Unicode string
   1800   //
   1801   *String = L'\0';
   1802 
   1803   //
   1804   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
   1805   //
   1806   return InternalLowerConfigString (ReturnString);
   1807 }
   1808 
   1809 /**
   1810   Generate the Config request element for one question.
   1811 
   1812   @param   Name    The name info for one question.
   1813   @param   Offset  The offset info for one question.
   1814   @param   Width   The width info for one question.
   1815 
   1816   @return  Pointer to the Null-terminated Unicode request element string.
   1817 
   1818 **/
   1819 EFI_STRING
   1820 ConstructRequestElement (
   1821   IN CHAR16      *Name,
   1822   IN UINT16      Offset,
   1823   IN UINT16      Width
   1824   )
   1825 {
   1826   CHAR16    *StringPtr;
   1827   UINTN     Length;
   1828 
   1829   if (Name != NULL) {
   1830     //
   1831     // Add <BlockName> length for each Name
   1832     //
   1833     // <BlockName> ::= Name + \0
   1834     //                 StrLen(Name) | 1
   1835     //
   1836     Length = StrLen (Name) + 1;
   1837   } else {
   1838     //
   1839     // Add <BlockName> length for each Offset/Width pair
   1840     //
   1841     // <BlockName> ::= OFFSET=1234&WIDTH=1234 + \0
   1842     //                 |  7   | 4 |   7  | 4 |  1
   1843     //
   1844     Length = (7 + 4 + 7 + 4 + 1);
   1845   }
   1846 
   1847   //
   1848   // Allocate buffer for the entire <ConfigRequest>
   1849   //
   1850   StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
   1851   ASSERT (StringPtr != NULL);
   1852 
   1853   if (Name != NULL) {
   1854     //
   1855     // Append Name\0
   1856     //
   1857     UnicodeSPrint (
   1858       StringPtr,
   1859       (StrLen (Name) + 1) * sizeof (CHAR16),
   1860       L"%s",
   1861       Name
   1862     );
   1863   } else {
   1864     //
   1865     // Append OFFSET=XXXX&WIDTH=YYYY\0
   1866     //
   1867     UnicodeSPrint (
   1868       StringPtr,
   1869       (7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
   1870       L"OFFSET=%04X&WIDTH=%04X",
   1871       Offset,
   1872       Width
   1873     );
   1874   }
   1875 
   1876   return StringPtr;
   1877 }
   1878 
   1879 /**
   1880   Get string value for question's name field.
   1881 
   1882   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
   1883   @param  NameId                         The string id for the name field.
   1884 
   1885   @retval Name string.
   1886 
   1887 **/
   1888 CHAR16 *
   1889 GetNameFromId (
   1890   IN HII_DATABASE_RECORD   *DatabaseRecord,
   1891   IN EFI_STRING_ID         NameId
   1892   )
   1893 {
   1894   CHAR16      *Name;
   1895   CHAR8       *PlatformLanguage;
   1896   CHAR8       *SupportedLanguages;
   1897   CHAR8       *BestLanguage;
   1898   UINTN       StringSize;
   1899   CHAR16      TempString;
   1900   EFI_STATUS  Status;
   1901 
   1902   Name = NULL;
   1903   BestLanguage = NULL;
   1904   PlatformLanguage = NULL;
   1905   SupportedLanguages = NULL;
   1906 
   1907   GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
   1908   SupportedLanguages = GetSupportedLanguages(DatabaseRecord->Handle);
   1909 
   1910   //
   1911   // Get the best matching language from SupportedLanguages
   1912   //
   1913   BestLanguage = GetBestLanguage (
   1914                    SupportedLanguages,
   1915                    FALSE,                                             // RFC 4646 mode
   1916                    PlatformLanguage != NULL ? PlatformLanguage : "",  // Highest priority
   1917                    SupportedLanguages,                                // Lowest priority
   1918                    NULL
   1919                    );
   1920   if (BestLanguage == NULL) {
   1921     BestLanguage = AllocateCopyPool (AsciiStrLen ("en-US"), "en-US");
   1922     ASSERT (BestLanguage != NULL);
   1923   }
   1924 
   1925   StringSize = 0;
   1926   Status = mPrivate.HiiString.GetString (
   1927                                  &mPrivate.HiiString,
   1928                                  BestLanguage,
   1929                                  DatabaseRecord->Handle,
   1930                                  NameId,
   1931                                  &TempString,
   1932                                  &StringSize,
   1933                                  NULL
   1934                                  );
   1935   if (Status != EFI_BUFFER_TOO_SMALL) {
   1936     goto Done;
   1937   }
   1938 
   1939   Name = AllocateZeroPool (StringSize);
   1940   if (Name == NULL) {
   1941     goto Done;
   1942   }
   1943 
   1944   Status = mPrivate.HiiString.GetString (
   1945                           &mPrivate.HiiString,
   1946                           BestLanguage,
   1947                           DatabaseRecord->Handle,
   1948                           NameId,
   1949                           Name,
   1950                           &StringSize,
   1951                           NULL
   1952                           );
   1953 
   1954   if (EFI_ERROR (Status)) {
   1955     FreePool (Name);
   1956     Name = NULL;
   1957     goto Done;
   1958   }
   1959 
   1960 Done:
   1961   if (SupportedLanguages != NULL) {
   1962     FreePool(SupportedLanguages);
   1963   }
   1964   if (BestLanguage != NULL) {
   1965     FreePool (BestLanguage);
   1966   }
   1967   if (PlatformLanguage != NULL) {
   1968     FreePool (PlatformLanguage);
   1969   }
   1970 
   1971   return Name;
   1972 }
   1973 
   1974 /**
   1975   Base on the input parameter to generate the ConfigRequest string.
   1976 
   1977   This is a internal function.
   1978 
   1979   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
   1980   @param  KeywordStrId                   Keyword string id.
   1981   @param  OpCodeData                     The IFR data for this question.
   1982   @param  ConfigRequest                  Return the generate ConfigRequest string.
   1983 
   1984   @retval EFI_SUCCESS               Generate ConfigResp string success.
   1985   @retval EFI_OUT_OF_RESOURCES      System out of memory resource error.
   1986   @retval EFI_NOT_FOUND             Not found the question which use this string id
   1987                                     as the prompt string id.
   1988 **/
   1989 EFI_STATUS
   1990 ExtractConfigRequest (
   1991   IN  HII_DATABASE_RECORD   *DatabaseRecord,
   1992   IN  EFI_STRING_ID         KeywordStrId,
   1993   OUT UINT8                 **OpCodeData,
   1994   OUT EFI_STRING            *ConfigRequest
   1995   )
   1996 {
   1997   LIST_ENTRY                          *Link;
   1998   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   1999   HII_IFR_PACKAGE_INSTANCE            *FormPackage;
   2000   EFI_IFR_QUESTION_HEADER             *Header;
   2001   UINT8                               *Storage;
   2002   UINT8                               *OpCode;
   2003   CHAR16                              *Name;
   2004   UINT16                              Offset;
   2005   UINT16                              Width;
   2006   CHAR16                              *ConfigHdr;
   2007   CHAR16                              *RequestElement;
   2008   UINTN                               MaxLen;
   2009   CHAR16                              *StringPtr;
   2010 
   2011   ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL);
   2012 
   2013   OpCode = NULL;
   2014   Name   = NULL;
   2015   Width  = 0;
   2016   Offset = 0;
   2017 
   2018   PackageListNode = DatabaseRecord->PackageList;
   2019 
   2020   //
   2021   // Search the languages in the specified packagelist.
   2022   //
   2023   for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
   2024     FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
   2025 
   2026     OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
   2027     if (OpCode != NULL) {
   2028       *OpCodeData = OpCode;
   2029       Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
   2030       //
   2031       // Header->VarStoreId == 0 means no storage for this question.
   2032       //
   2033       ASSERT (Header->VarStoreId != 0);
   2034       DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
   2035 
   2036       Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
   2037       ASSERT (Storage != NULL);
   2038 
   2039       if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
   2040         Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
   2041       } else {
   2042         Offset = Header->VarStoreInfo.VarOffset;
   2043         Width = GetWidth (OpCode);
   2044       }
   2045       RequestElement = ConstructRequestElement(Name, Offset, Width);
   2046       ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
   2047       ASSERT (ConfigHdr != NULL);
   2048 
   2049       MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1;
   2050       *ConfigRequest = AllocatePool (MaxLen * sizeof (CHAR16));
   2051       if (*ConfigRequest == NULL) {
   2052         FreePool (ConfigHdr);
   2053         FreePool (RequestElement);
   2054         return EFI_OUT_OF_RESOURCES;
   2055       }
   2056       StringPtr = *ConfigRequest;
   2057 
   2058       StrCpyS (StringPtr, MaxLen, ConfigHdr);
   2059 
   2060       StrCatS (StringPtr, MaxLen, L"&");
   2061 
   2062       StrCatS (StringPtr, MaxLen, RequestElement);
   2063 
   2064       FreePool (ConfigHdr);
   2065       FreePool (RequestElement);
   2066 
   2067       return EFI_SUCCESS;
   2068     }
   2069   }
   2070 
   2071   return EFI_NOT_FOUND;
   2072 }
   2073 
   2074 /**
   2075   Base on the input parameter to generate the ConfigResp string.
   2076 
   2077   This is a internal function.
   2078 
   2079   @param  DatabaseRecord                 HII_DATABASE_RECORD format string.
   2080   @param  KeywordStrId                   Keyword string id.
   2081   @param  ValueElement                   The value for the question which use keyword string id
   2082                                          as the prompt string id.
   2083   @param  OpCodeData                     The IFR data for this question.
   2084   @param  ConfigResp                     Return the generate ConfigResp string.
   2085 
   2086   @retval EFI_SUCCESS               Generate ConfigResp string success.
   2087   @retval EFI_OUT_OF_RESOURCES      System out of memory resource error.
   2088   @retval EFI_NOT_FOUND             Not found the question which use this string id
   2089                                     as the prompt string id.
   2090 **/
   2091 EFI_STATUS
   2092 ExtractConfigResp (
   2093   IN  HII_DATABASE_RECORD   *DatabaseRecord,
   2094   IN  EFI_STRING_ID         KeywordStrId,
   2095   IN  EFI_STRING            ValueElement,
   2096   OUT UINT8                 **OpCodeData,
   2097   OUT EFI_STRING            *ConfigResp
   2098   )
   2099 {
   2100   LIST_ENTRY                          *Link;
   2101   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   2102   HII_IFR_PACKAGE_INSTANCE            *FormPackage;
   2103   EFI_IFR_QUESTION_HEADER             *Header;
   2104   UINT8                               *Storage;
   2105   UINT8                               *OpCode;
   2106   CHAR16                              *Name;
   2107   UINT16                              Offset;
   2108   UINT16                              Width;
   2109   CHAR16                              *ConfigHdr;
   2110   CHAR16                              *RequestElement;
   2111   UINTN                               MaxLen;
   2112   CHAR16                              *StringPtr;
   2113 
   2114   ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL));
   2115 
   2116   OpCode = NULL;
   2117   Name   = NULL;
   2118   Width  = 0;
   2119   Offset = 0;
   2120 
   2121   PackageListNode = DatabaseRecord->PackageList;
   2122 
   2123   //
   2124   // Search the languages in the specified packagelist.
   2125   //
   2126   for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
   2127     FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
   2128 
   2129     OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
   2130     if (OpCode != NULL) {
   2131       *OpCodeData = OpCode;
   2132       Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
   2133       //
   2134       // Header->VarStoreId == 0 means no storage for this question.
   2135       //
   2136       ASSERT (Header->VarStoreId != 0);
   2137       DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
   2138 
   2139       Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
   2140       ASSERT (Storage != NULL);
   2141 
   2142       if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
   2143         Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
   2144       } else {
   2145         Offset = Header->VarStoreInfo.VarOffset;
   2146         Width  = GetWidth (OpCode);
   2147       }
   2148       RequestElement = ConstructRequestElement(Name, Offset, Width);
   2149 
   2150       ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
   2151       ASSERT (ConfigHdr != NULL);
   2152 
   2153       MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1;
   2154       *ConfigResp = AllocatePool (MaxLen * sizeof (CHAR16));
   2155       if (*ConfigResp == NULL) {
   2156         FreePool (ConfigHdr);
   2157         FreePool (RequestElement);
   2158         return EFI_OUT_OF_RESOURCES;
   2159       }
   2160       StringPtr = *ConfigResp;
   2161 
   2162       StrCpyS (StringPtr, MaxLen, ConfigHdr);
   2163 
   2164       StrCatS (StringPtr, MaxLen, L"&");
   2165 
   2166 
   2167       StrCatS (StringPtr, MaxLen, RequestElement);
   2168 
   2169       StrCatS (StringPtr, MaxLen, L"&");
   2170 
   2171       StrCatS (StringPtr, MaxLen, L"VALUE=");
   2172 
   2173       StrCatS (StringPtr, MaxLen, ValueElement);
   2174 
   2175       FreePool (ConfigHdr);
   2176       FreePool (RequestElement);
   2177 
   2178       return EFI_SUCCESS;
   2179     }
   2180   }
   2181 
   2182   return EFI_NOT_FOUND;
   2183 }
   2184 
   2185 /**
   2186   Get the Value section from the Hii driver.
   2187 
   2188   This is a internal function.
   2189 
   2190   @param  ConfigRequest                  The input ConfigRequest string.
   2191   @param  ValueElement                   The respond Value section from the hii driver.
   2192 
   2193   @retval Misc value                     The error status return from ExtractConfig function.
   2194   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated
   2195   @retval EFI_SUCCESS                    Get the value section success.
   2196 
   2197 **/
   2198 EFI_STATUS
   2199 ExtractValueFromDriver (
   2200   IN  CHAR16           *ConfigRequest,
   2201   OUT CHAR16           **ValueElement
   2202   )
   2203 {
   2204   EFI_STATUS   Status;
   2205   EFI_STRING   Result;
   2206   EFI_STRING   Progress;
   2207   CHAR16       *StringPtr;
   2208   CHAR16       *StringEnd;
   2209 
   2210   ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL));
   2211 
   2212   Status = mPrivate.ConfigRouting.ExtractConfig (
   2213                       &mPrivate.ConfigRouting,
   2214                       (EFI_STRING) ConfigRequest,
   2215                       &Progress,
   2216                       &Result
   2217                       );
   2218   if (EFI_ERROR (Status)) {
   2219     return Status;
   2220   }
   2221 
   2222   //
   2223   // Find Value Section and return it.
   2224   //
   2225   StringPtr = StrStr (Result, L"&VALUE=");
   2226   ASSERT (StringPtr != NULL);
   2227   StringEnd = StrStr (StringPtr + 1, L"&");
   2228   if (StringEnd != NULL) {
   2229     *StringEnd = L'\0';
   2230   }
   2231 
   2232   *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr);
   2233   if (*ValueElement == NULL) {
   2234     return EFI_OUT_OF_RESOURCES;
   2235   }
   2236 
   2237   if (StringEnd != NULL) {
   2238     *StringEnd = L'&';
   2239   }
   2240   FreePool (Result);
   2241 
   2242   return EFI_SUCCESS;
   2243 }
   2244 
   2245 /**
   2246   Get EFI_STRING_ID info from the input device path, namespace and keyword.
   2247 
   2248   This is a internal function.
   2249 
   2250   @param  DevicePath                     Input device path info.
   2251   @param  NameSpace                      NameSpace format string.
   2252   @param  KeywordData                    Keyword used to get string id.
   2253   @param  ProgressErr                    Return extra error type.
   2254   @param  KeywordStringId                Return EFI_STRING_ID.
   2255   @param  DataBaseRecord                 DataBase record data for this driver.
   2256 
   2257   @retval EFI_INVALID_PARAMETER          Can't find the database record base on the input device path or namespace.
   2258   @retval EFI_NOT_FOUND                  Can't find the EFI_STRING_ID for the keyword.
   2259   @retval EFI_SUCCESS                    Find the EFI_STRING_ID.
   2260 
   2261 **/
   2262 EFI_STATUS
   2263 GetStringIdFromDatabase (
   2264   IN  EFI_DEVICE_PATH_PROTOCOL            **DevicePath,
   2265   IN  CHAR8                               **NameSpace,
   2266   IN  CHAR16                              *KeywordData,
   2267   OUT UINT32                              *ProgressErr,
   2268   OUT EFI_STRING_ID                       *KeywordStringId,
   2269   OUT HII_DATABASE_RECORD                 **DataBaseRecord
   2270  )
   2271 {
   2272   HII_DATABASE_RECORD                 *Record;
   2273   LIST_ENTRY                          *Link;
   2274   BOOLEAN                             FindNameSpace;
   2275   EFI_DEVICE_PATH_PROTOCOL            *DestDevicePath;
   2276   UINT8                               *DevicePathPkg;
   2277   UINTN                               DevicePathSize;
   2278 
   2279   ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL));
   2280 
   2281   FindNameSpace = FALSE;
   2282 
   2283   if (*DevicePath != NULL) {
   2284     //
   2285     // Get DataBaseRecord from device path protocol.
   2286     //
   2287     Record = GetRecordFromDevicePath(*DevicePath);
   2288     if (Record == NULL) {
   2289       //
   2290       // Can't find the DatabaseRecord base on the input device path info.
   2291       // NEED TO CONFIRM the return ProgressErr.
   2292       //
   2293       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   2294       return EFI_INVALID_PARAMETER;
   2295     }
   2296 
   2297     //
   2298     // Get string id from the record.
   2299     //
   2300     *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
   2301     switch (*ProgressErr) {
   2302     case KEYWORD_HANDLER_NO_ERROR:
   2303       *DataBaseRecord = Record;
   2304       return EFI_SUCCESS;
   2305 
   2306     case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND:
   2307       return EFI_INVALID_PARAMETER;
   2308 
   2309     default:
   2310       ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND);
   2311       return EFI_NOT_FOUND;
   2312     }
   2313   } else {
   2314     //
   2315     // Find driver which matches the routing data.
   2316     //
   2317     for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
   2318       Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   2319 
   2320       *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
   2321       if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) {
   2322         *DataBaseRecord = Record;
   2323 
   2324         if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) {
   2325           DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER));
   2326           DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath);
   2327           *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath);
   2328           if (*DevicePath == NULL) {
   2329             return EFI_OUT_OF_RESOURCES;
   2330           }
   2331         } else {
   2332           //
   2333           // Need to verify this ASSERT.
   2334           //
   2335           ASSERT (FALSE);
   2336         }
   2337 
   2338         return EFI_SUCCESS;
   2339       } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) {
   2340         return EFI_OUT_OF_RESOURCES;
   2341       } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) {
   2342         FindNameSpace = TRUE;
   2343       }
   2344     }
   2345 
   2346     //
   2347     // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND.
   2348     // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND.
   2349     //
   2350     if (FindNameSpace) {
   2351       return EFI_NOT_FOUND;
   2352     } else {
   2353       return EFI_INVALID_PARAMETER;
   2354     }
   2355   }
   2356 }
   2357 
   2358 /**
   2359   Generate the KeywordResp String.
   2360 
   2361   <KeywordResp> ::= <NameSpaceId><PathHdr>'&'<Keyword>'&VALUE='<Number>['&READONLY']
   2362 
   2363   @param  NameSpace                      NameSpace format string.
   2364   @param  DevicePath                     Input device path info.
   2365   @param  KeywordData                    Keyword used to get string id.
   2366   @param  ValueStr                       The value section for the keyword.
   2367   @param  ReadOnly                       Whether this value is readonly.
   2368   @param  KeywordResp                    Return the point to the KeywordResp string.
   2369 
   2370   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated.
   2371   @retval EFI_SUCCESS                    Generate the KeywordResp string.
   2372 
   2373 **/
   2374 EFI_STATUS
   2375 GenerateKeywordResp (
   2376   IN  CHAR8                          *NameSpace,
   2377   IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,
   2378   IN  EFI_STRING                     KeywordData,
   2379   IN  EFI_STRING                     ValueStr,
   2380   IN  BOOLEAN                        ReadOnly,
   2381   OUT EFI_STRING                     *KeywordResp
   2382   )
   2383 {
   2384   UINTN     RespStrLen;
   2385   CHAR16    *RespStr;
   2386   CHAR16    *PathHdr;
   2387   CHAR16    *UnicodeNameSpace;
   2388   UINTN     NameSpaceLength;
   2389 
   2390   ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL));
   2391 
   2392   //
   2393   // 1. Calculate the string length.
   2394   //
   2395   //
   2396   // 1.1 NameSpaceId size.
   2397   // 'NAMESPACE='<String>
   2398   //
   2399   NameSpaceLength = AsciiStrLen (NameSpace);
   2400   RespStrLen = 10 + NameSpaceLength;
   2401   UnicodeNameSpace = AllocatePool ((NameSpaceLength + 1) * sizeof (CHAR16));
   2402   if (UnicodeNameSpace == NULL) {
   2403     return EFI_OUT_OF_RESOURCES;
   2404   }
   2405   AsciiStrToUnicodeStrS (NameSpace, UnicodeNameSpace, NameSpaceLength + 1);
   2406 
   2407   //
   2408   // 1.2 PathHdr size.
   2409   // PATH=<UEFI binary Device Path represented as hex number>'&'
   2410   // Attention: The output include the '&' at the end.
   2411   //
   2412   GenerateSubStr (
   2413     L"&PATH=",
   2414     GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
   2415     (VOID *) DevicePath,
   2416     1,
   2417     &PathHdr
   2418     );
   2419   RespStrLen += StrLen (PathHdr);
   2420 
   2421   //
   2422   // 1.3 Keyword section.
   2423   // 'KEYWORD='<String>[':'<DecCh>(1/4)]
   2424   //
   2425   RespStrLen += 8 + StrLen (KeywordData);
   2426 
   2427   //
   2428   // 1.4 Value section.
   2429   // ValueStr = '&VALUE='<Number>
   2430   //
   2431   RespStrLen += StrLen (ValueStr);
   2432 
   2433   //
   2434   // 1.5 ReadOnly Section.
   2435   // '&READONLY'
   2436   //
   2437   if (ReadOnly) {
   2438     RespStrLen += 9;
   2439   }
   2440 
   2441   //
   2442   // 2. Allocate the buffer and create the KeywordResp string include '\0'.
   2443   //
   2444   RespStrLen += 1;
   2445   *KeywordResp = AllocatePool (RespStrLen * sizeof (CHAR16));
   2446   if (*KeywordResp == NULL) {
   2447     if (UnicodeNameSpace != NULL) {
   2448       FreePool (UnicodeNameSpace);
   2449     }
   2450 
   2451     return EFI_OUT_OF_RESOURCES;
   2452   }
   2453   RespStr = *KeywordResp;
   2454 
   2455   //
   2456   // 2.1 Copy NameSpaceId section.
   2457   //
   2458   StrCpyS (RespStr, RespStrLen, L"NAMESPACE=");
   2459 
   2460   StrCatS (RespStr, RespStrLen, UnicodeNameSpace);
   2461 
   2462   //
   2463   // 2.2 Copy PathHdr section.
   2464   //
   2465   StrCatS (RespStr, RespStrLen, PathHdr);
   2466 
   2467   //
   2468   // 2.3 Copy Keyword section.
   2469   //
   2470   StrCatS (RespStr, RespStrLen, L"KEYWORD=");
   2471 
   2472   StrCatS (RespStr, RespStrLen, KeywordData);
   2473 
   2474   //
   2475   // 2.4 Copy the Value section.
   2476   //
   2477   StrCatS (RespStr, RespStrLen, ValueStr);
   2478 
   2479   //
   2480   // 2.5 Copy ReadOnly section if exist.
   2481   //
   2482   if (ReadOnly) {
   2483     StrCatS (RespStr, RespStrLen, L"&READONLY");
   2484   }
   2485 
   2486   if (UnicodeNameSpace != NULL) {
   2487     FreePool (UnicodeNameSpace);
   2488   }
   2489   if (PathHdr != NULL) {
   2490     FreePool (PathHdr);
   2491   }
   2492 
   2493   return EFI_SUCCESS;
   2494 }
   2495 
   2496 /**
   2497   Merge the KeywordResp String to MultiKeywordResp string.
   2498 
   2499   This is a internal function.
   2500 
   2501   @param  MultiKeywordResp               The existed multikeywordresp string.
   2502   @param  KeywordResp                    The input keywordResp string.
   2503 
   2504   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated.
   2505   @retval EFI_SUCCESS                    Generate the MultiKeywordResp string.
   2506 
   2507 **/
   2508 EFI_STATUS
   2509 MergeToMultiKeywordResp (
   2510   IN OUT EFI_STRING         *MultiKeywordResp,
   2511   IN     EFI_STRING         *KeywordResp
   2512   )
   2513 {
   2514   UINTN       MultiKeywordRespLen;
   2515   EFI_STRING  StringPtr;
   2516 
   2517   if (*MultiKeywordResp == NULL) {
   2518     *MultiKeywordResp = *KeywordResp;
   2519     *KeywordResp = NULL;
   2520     return EFI_SUCCESS;
   2521   }
   2522 
   2523   MultiKeywordRespLen = (StrLen (*MultiKeywordResp) + 1 + StrLen (*KeywordResp) + 1) * sizeof (CHAR16);
   2524 
   2525   StringPtr = AllocateCopyPool (MultiKeywordRespLen, *MultiKeywordResp);
   2526   if (StringPtr == NULL) {
   2527     return EFI_OUT_OF_RESOURCES;
   2528   }
   2529 
   2530   FreePool (*MultiKeywordResp);
   2531   *MultiKeywordResp = StringPtr;
   2532 
   2533   StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), L"&");
   2534 
   2535   StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp);
   2536 
   2537   return EFI_SUCCESS;
   2538 }
   2539 
   2540 /**
   2541   Enumerate all keyword in the system.
   2542 
   2543   If error occur when parse one keyword, just skip it and parse the next one.
   2544 
   2545   This is a internal function.
   2546 
   2547   @param  NameSpace                      The namespace used to search the string.
   2548   @param  MultiResp                      Return the MultiKeywordResp string for the system.
   2549   @param  ProgressErr                    Return the error status.
   2550 
   2551   @retval EFI_OUT_OF_RESOURCES           The memory can't be allocated.
   2552   @retval EFI_SUCCESS                    Generate the MultiKeywordResp string.
   2553   @retval EFI_NOT_FOUND                  No keyword found.
   2554 
   2555 **/
   2556 EFI_STATUS
   2557 EnumerateAllKeywords (
   2558   IN  CHAR8             *NameSpace,
   2559   OUT EFI_STRING        *MultiResp,
   2560   OUT UINT32            *ProgressErr
   2561   )
   2562 {
   2563   LIST_ENTRY                          *Link;
   2564   LIST_ENTRY                          *StringLink;
   2565   UINT8                               *DevicePathPkg;
   2566   UINT8                               *DevicePath;
   2567   HII_DATABASE_RECORD                 *DataBaseRecord;
   2568   HII_DATABASE_PACKAGE_LIST_INSTANCE  *PackageListNode;
   2569   HII_STRING_PACKAGE_INSTANCE         *StringPackage;
   2570   CHAR8                               *LocalNameSpace;
   2571   EFI_STRING_ID                       NextStringId;
   2572   EFI_STATUS                          Status;
   2573   UINT8                               *OpCode;
   2574   CHAR16                              *ConfigRequest;
   2575   CHAR16                              *ValueElement;
   2576   CHAR16                              *KeywordResp;
   2577   CHAR16                              *MultiKeywordResp;
   2578   CHAR16                              *KeywordData;
   2579   BOOLEAN                             ReadOnly;
   2580   BOOLEAN                             FindKeywordPackages;
   2581 
   2582   DataBaseRecord   = NULL;
   2583   Status           = EFI_SUCCESS;
   2584   MultiKeywordResp = NULL;
   2585   DevicePath       = NULL;
   2586   LocalNameSpace   = NULL;
   2587   ConfigRequest    = NULL;
   2588   ValueElement     = NULL;
   2589   KeywordResp      = NULL;
   2590   FindKeywordPackages = FALSE;
   2591 
   2592   if (NameSpace == NULL) {
   2593     NameSpace = UEFI_CONFIG_LANG;
   2594   }
   2595 
   2596   //
   2597   // Find driver which matches the routing data.
   2598   //
   2599   for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
   2600     DataBaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
   2601     if ((DevicePathPkg = DataBaseRecord->PackageList->DevicePathPkg) != NULL) {
   2602       DevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
   2603     }
   2604     PackageListNode = DataBaseRecord->PackageList;
   2605 
   2606     for (StringLink = PackageListNode->StringPkgHdr.ForwardLink; StringLink != &PackageListNode->StringPkgHdr; StringLink = StringLink->ForwardLink) {
   2607       StringPackage = CR (StringLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
   2608 
   2609       //
   2610       // Check whether has keyword string package.
   2611       //
   2612       if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) {
   2613         FindKeywordPackages = TRUE;
   2614         //
   2615         // Keep the NameSpace string.
   2616         //
   2617         LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
   2618         if (LocalNameSpace == NULL) {
   2619           return EFI_OUT_OF_RESOURCES;
   2620         }
   2621 
   2622         //
   2623         // 1 means just begin the enumerate the valid string ids.
   2624         // StringId == 1 is always used to save the language for this string package.
   2625         // Any valid string start from 2. so here initial it to 1.
   2626         //
   2627         NextStringId = 1;
   2628 
   2629         //
   2630         // Enumerate all valid stringid in the package.
   2631         //
   2632         while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) {
   2633           //
   2634           // 3.3 Construct the ConfigRequest string.
   2635           //
   2636           Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest);
   2637           if (EFI_ERROR (Status)) {
   2638             //
   2639             // If can't generate ConfigRequest for this question, skip it and start the next.
   2640             //
   2641             goto Error;
   2642           }
   2643 
   2644           //
   2645           // 3.4 Extract Value for the input keyword.
   2646           //
   2647           Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
   2648           if (EFI_ERROR (Status)) {
   2649             if (Status != EFI_OUT_OF_RESOURCES) {
   2650               //
   2651               // If can't generate ConfigRequest for this question, skip it and start the next.
   2652               //
   2653               goto Error;
   2654             }
   2655             //
   2656             // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
   2657             //
   2658             goto Done;
   2659           }
   2660 
   2661           //
   2662           // Extract readonly flag from opcode.
   2663           //
   2664           ReadOnly = ExtractReadOnlyFromOpCode(OpCode);
   2665 
   2666           //
   2667           // 5. Generate KeywordResp string.
   2668           //
   2669           ASSERT (DevicePath != NULL);
   2670           Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
   2671           if (Status != EFI_SUCCESS) {
   2672             //
   2673             // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
   2674             //
   2675             goto Done;
   2676           }
   2677 
   2678           //
   2679           // 6. Merge to the MultiKeywordResp string.
   2680           //
   2681           Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
   2682           if (EFI_ERROR (Status)) {
   2683             goto Done;
   2684           }
   2685 Error:
   2686           //
   2687           // Clean the temp buffer to later use again.
   2688           //
   2689           if (ConfigRequest != NULL) {
   2690             FreePool (ConfigRequest);
   2691             ConfigRequest = NULL;
   2692           }
   2693           if (ValueElement != NULL) {
   2694             FreePool (ValueElement);
   2695             ValueElement = NULL;
   2696           }
   2697           if (KeywordResp != NULL) {
   2698             FreePool (KeywordResp);
   2699             KeywordResp = NULL;
   2700           }
   2701         }
   2702 
   2703         if (LocalNameSpace != NULL) {
   2704           FreePool (LocalNameSpace);
   2705           LocalNameSpace = NULL;
   2706         }
   2707       }
   2708     }
   2709   }
   2710 
   2711   //
   2712   // return the already get MultiKeywordString even error occurred.
   2713   //
   2714   if (MultiKeywordResp == NULL) {
   2715     Status = EFI_NOT_FOUND;
   2716     if (!FindKeywordPackages) {
   2717       *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
   2718     } else {
   2719       *ProgressErr = KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
   2720     }
   2721   } else {
   2722     Status = EFI_SUCCESS;
   2723   }
   2724   *MultiResp = MultiKeywordResp;
   2725 
   2726 Done:
   2727   if (LocalNameSpace != NULL) {
   2728     FreePool (LocalNameSpace);
   2729   }
   2730   if (ConfigRequest != NULL) {
   2731     FreePool (ConfigRequest);
   2732   }
   2733   if (ValueElement != NULL) {
   2734     FreePool (ValueElement);
   2735   }
   2736 
   2737   return Status;
   2738 }
   2739 
   2740 /**
   2741 
   2742   This function accepts a <MultiKeywordResp> formatted string, finds the associated
   2743   keyword owners, creates a <MultiConfigResp> string from it and forwards it to the
   2744   EFI_HII_ROUTING_PROTOCOL.RouteConfig function.
   2745 
   2746   If there is an issue in resolving the contents of the KeywordString, then the
   2747   function returns an error and also sets the Progress and ProgressErr with the
   2748   appropriate information about where the issue occurred and additional data about
   2749   the nature of the issue.
   2750 
   2751   In the case when KeywordString containing multiple keywords, when an EFI_NOT_FOUND
   2752   error is generated during processing the second or later keyword element, the system
   2753   storage associated with earlier keywords is not modified. All elements of the
   2754   KeywordString must successfully pass all tests for format and access prior to making
   2755   any modifications to storage.
   2756 
   2757   In the case when EFI_DEVICE_ERROR is returned from the processing of a KeywordString
   2758   containing multiple keywords, the state of storage associated with earlier keywords
   2759   is undefined.
   2760 
   2761 
   2762   @param This             Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
   2763 
   2764   @param KeywordString    A null-terminated string in <MultiKeywordResp> format.
   2765 
   2766   @param Progress         On return, points to a character in the KeywordString.
   2767                           Points to the string's NULL terminator if the request
   2768                           was successful. Points to the most recent '&' before
   2769                           the first failing name / value pair (or the beginning
   2770                           of the string if the failure is in the first name / value
   2771                           pair) if the request was not successful.
   2772 
   2773   @param ProgressErr      If during the processing of the KeywordString there was
   2774                           a failure, this parameter gives additional information
   2775                           about the possible source of the problem. The various
   2776                           errors are defined in "Related Definitions" below.
   2777 
   2778 
   2779   @retval EFI_SUCCESS             The specified action was completed successfully.
   2780 
   2781   @retval EFI_INVALID_PARAMETER   One or more of the following are TRUE:
   2782                                   1. KeywordString is NULL.
   2783                                   2. Parsing of the KeywordString resulted in an
   2784                                      error. See Progress and ProgressErr for more data.
   2785 
   2786   @retval EFI_NOT_FOUND           An element of the KeywordString was not found.
   2787                                   See ProgressErr for more data.
   2788 
   2789   @retval EFI_OUT_OF_RESOURCES    Required system resources could not be allocated.
   2790                                   See ProgressErr for more data.
   2791 
   2792   @retval EFI_ACCESS_DENIED       The action violated system policy. See ProgressErr
   2793                                   for more data.
   2794 
   2795   @retval EFI_DEVICE_ERROR        An unexpected system error occurred. See ProgressErr
   2796                                   for more data.
   2797 
   2798 **/
   2799 EFI_STATUS
   2800 EFIAPI
   2801 EfiConfigKeywordHandlerSetData (
   2802   IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
   2803   IN CONST EFI_STRING                    KeywordString,
   2804   OUT EFI_STRING                         *Progress,
   2805   OUT UINT32                             *ProgressErr
   2806   )
   2807 {
   2808   CHAR8                               *NameSpace;
   2809   EFI_STATUS                          Status;
   2810   CHAR16                              *StringPtr;
   2811   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
   2812   CHAR16                              *NextStringPtr;
   2813   CHAR16                              *KeywordData;
   2814   EFI_STRING_ID                       KeywordStringId;
   2815   UINT32                              RetVal;
   2816   HII_DATABASE_RECORD                 *DataBaseRecord;
   2817   UINT8                               *OpCode;
   2818   CHAR16                              *ConfigResp;
   2819   CHAR16                              *MultiConfigResp;
   2820   CHAR16                              *ValueElement;
   2821   BOOLEAN                             ReadOnly;
   2822   EFI_STRING                          InternalProgress;
   2823   CHAR16                              *TempString;
   2824   CHAR16                              *KeywordStartPos;
   2825 
   2826   if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) {
   2827     return EFI_INVALID_PARAMETER;
   2828   }
   2829 
   2830   *Progress    = KeywordString;
   2831   *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
   2832   Status       = EFI_SUCCESS;
   2833   MultiConfigResp = NULL;
   2834   NameSpace       = NULL;
   2835   DevicePath      = NULL;
   2836   KeywordData     = NULL;
   2837   ValueElement    = NULL;
   2838   ConfigResp      = NULL;
   2839   KeywordStartPos = NULL;
   2840   KeywordStringId = 0;
   2841 
   2842   //
   2843   // Use temp string to avoid changing input string buffer.
   2844   //
   2845   TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
   2846   ASSERT (TempString != NULL);
   2847   StringPtr = TempString;
   2848 
   2849   while ((StringPtr != NULL) && (*StringPtr != L'\0')) {
   2850     //
   2851     // 1. Get NameSpace from NameSpaceId keyword.
   2852     //
   2853     Status = ExtractNameSpace (StringPtr, &NameSpace, &NextStringPtr);
   2854     if (EFI_ERROR (Status)) {
   2855       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   2856       goto Done;
   2857     }
   2858     ASSERT (NameSpace != NULL);
   2859     //
   2860     // 1.1 Check whether the input namespace is valid.
   2861     //
   2862     if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
   2863       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   2864       Status = EFI_INVALID_PARAMETER;
   2865       goto Done;
   2866     }
   2867 
   2868     StringPtr = NextStringPtr;
   2869 
   2870     //
   2871     // 2. Get possible Device Path info from KeywordString.
   2872     //
   2873     Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
   2874     if (EFI_ERROR (Status)) {
   2875       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   2876       goto Done;
   2877     }
   2878     StringPtr = NextStringPtr;
   2879 
   2880     //
   2881     // 3. Extract keyword from the KeywordRequest string.
   2882     //
   2883     KeywordStartPos = StringPtr;
   2884     Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
   2885     if (EFI_ERROR (Status)) {
   2886       //
   2887       // Can't find Keyword base on the input device path info.
   2888       //
   2889       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   2890       Status = EFI_INVALID_PARAMETER;
   2891       goto Done;
   2892     }
   2893     StringPtr = NextStringPtr;
   2894 
   2895     //
   2896     // 4. Extract Value from the KeywordRequest string.
   2897     //
   2898     Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr);
   2899     if (EFI_ERROR (Status)) {
   2900       //
   2901       // Can't find Value base on the input device path info.
   2902       //
   2903       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   2904       Status = EFI_INVALID_PARAMETER;
   2905       goto Done;
   2906     }
   2907     StringPtr = NextStringPtr;
   2908 
   2909     //
   2910     // 5. Find READONLY tag.
   2911     //
   2912     if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&READONLY", StrLen (L"&READONLY")) == 0) {
   2913       ReadOnly = TRUE;
   2914       StringPtr += StrLen (L"&READONLY");
   2915     } else {
   2916       ReadOnly = FALSE;
   2917     }
   2918 
   2919     //
   2920     // 6. Get EFI_STRING_ID for the input keyword.
   2921     //
   2922     Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
   2923     if (EFI_ERROR (Status)) {
   2924       *ProgressErr = RetVal;
   2925       goto Done;
   2926     }
   2927 
   2928     //
   2929     // 7. Construct the ConfigRequest string.
   2930     //
   2931     Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp);
   2932     if (EFI_ERROR (Status)) {
   2933       goto Done;
   2934     }
   2935 
   2936     //
   2937     // 8. Check the readonly flag.
   2938     //
   2939     if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) {
   2940       //
   2941       // Extracting readonly flag form opcode and extracting "READONLY" tag form KeywordString should have the same results.
   2942       // If not, the input KeywordString must be incorrect, return the error status to caller.
   2943       //
   2944       *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
   2945       Status = EFI_INVALID_PARAMETER;
   2946       goto Done;
   2947     }
   2948     if (ReadOnly) {
   2949       *ProgressErr = KEYWORD_HANDLER_ACCESS_NOT_PERMITTED;
   2950       Status = EFI_ACCESS_DENIED;
   2951       goto Done;
   2952     }
   2953 
   2954     //
   2955     // 9. Merge to the MultiKeywordResp string.
   2956     //
   2957     Status = MergeToMultiKeywordResp(&MultiConfigResp, &ConfigResp);
   2958     if (EFI_ERROR (Status)) {
   2959       goto Done;
   2960     }
   2961 
   2962     //
   2963     // 10. Clean the temp buffer point.
   2964     //
   2965     FreePool (NameSpace);
   2966     FreePool (DevicePath);
   2967     FreePool (KeywordData);
   2968     FreePool (ValueElement);
   2969     NameSpace = NULL;
   2970     DevicePath = NULL;
   2971     KeywordData = NULL;
   2972     ValueElement = NULL;
   2973     if (ConfigResp != NULL) {
   2974       FreePool (ConfigResp);
   2975       ConfigResp = NULL;
   2976     }
   2977     KeywordStartPos = NULL;
   2978   }
   2979 
   2980   //
   2981   // 11. Set value to driver.
   2982   //
   2983   Status = mPrivate.ConfigRouting.RouteConfig(
   2984                     &mPrivate.ConfigRouting,
   2985                     (EFI_STRING) MultiConfigResp,
   2986                     &InternalProgress
   2987                     );
   2988   if (EFI_ERROR (Status)) {
   2989     Status = EFI_DEVICE_ERROR;
   2990     goto Done;
   2991   }
   2992 
   2993   *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
   2994 
   2995 Done:
   2996   if (KeywordStartPos != NULL) {
   2997     *Progress = KeywordString + (KeywordStartPos - TempString);
   2998   } else {
   2999     *Progress = KeywordString + (StringPtr - TempString);
   3000   }
   3001 
   3002   ASSERT (TempString != NULL);
   3003   FreePool (TempString);
   3004   if (NameSpace != NULL) {
   3005     FreePool (NameSpace);
   3006   }
   3007   if (DevicePath != NULL) {
   3008     FreePool (DevicePath);
   3009   }
   3010   if (KeywordData != NULL) {
   3011     FreePool (KeywordData);
   3012   }
   3013   if (ValueElement != NULL) {
   3014     FreePool (ValueElement);
   3015   }
   3016   if (ConfigResp != NULL) {
   3017     FreePool (ConfigResp);
   3018   }
   3019   if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) {
   3020     FreePool (MultiConfigResp);
   3021   }
   3022 
   3023   return Status;
   3024 }
   3025 
   3026 /**
   3027 
   3028   This function accepts a <MultiKeywordRequest> formatted string, finds the underlying
   3029   keyword owners, creates a <MultiConfigRequest> string from it and forwards it to the
   3030   EFI_HII_ROUTING_PROTOCOL.ExtractConfig function.
   3031 
   3032   If there is an issue in resolving the contents of the KeywordString, then the function
   3033   returns an EFI_INVALID_PARAMETER and also set the Progress and ProgressErr with the
   3034   appropriate information about where the issue occurred and additional data about the
   3035   nature of the issue.
   3036 
   3037   In the case when KeywordString is NULL, or contains multiple keywords, or when
   3038   EFI_NOT_FOUND is generated while processing the keyword elements, the Results string
   3039   contains values returned for all keywords processed prior to the keyword generating the
   3040   error but no values for the keyword with error or any following keywords.
   3041 
   3042 
   3043   @param This           Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
   3044 
   3045   @param NameSpaceId    A null-terminated string containing the platform configuration
   3046                         language to search through in the system. If a NULL is passed
   3047                         in, then it is assumed that any platform configuration language
   3048                         with the prefix of "x-UEFI-" are searched.
   3049 
   3050   @param KeywordString  A null-terminated string in <MultiKeywordRequest> format. If a
   3051                         NULL is passed in the KeywordString field, all of the known
   3052                         keywords in the system for the NameSpaceId specified are
   3053                         returned in the Results field.
   3054 
   3055   @param Progress       On return, points to a character in the KeywordString. Points
   3056                         to the string's NULL terminator if the request was successful.
   3057                         Points to the most recent '&' before the first failing name / value
   3058                         pair (or the beginning of the string if the failure is in the first
   3059                         name / value pair) if the request was not successful.
   3060 
   3061   @param ProgressErr    If during the processing of the KeywordString there was a
   3062                         failure, this parameter gives additional information about the
   3063                         possible source of the problem. See the definitions in SetData()
   3064                         for valid value definitions.
   3065 
   3066   @param Results        A null-terminated string in <MultiKeywordResp> format is returned
   3067                         which has all the values filled in for the keywords in the
   3068                         KeywordString. This is a callee-allocated field, and must be freed
   3069                         by the caller after being used.
   3070 
   3071   @retval EFI_SUCCESS             The specified action was completed successfully.
   3072 
   3073   @retval EFI_INVALID_PARAMETER   One or more of the following are TRUE:
   3074                                   1.Progress, ProgressErr, or Results is NULL.
   3075                                   2.Parsing of the KeywordString resulted in an error. See
   3076                                     Progress and ProgressErr for more data.
   3077 
   3078 
   3079   @retval EFI_NOT_FOUND           An element of the KeywordString was not found. See
   3080                                   ProgressErr for more data.
   3081 
   3082   @retval EFI_NOT_FOUND           The NamespaceId specified was not found.  See ProgressErr
   3083                                   for more data.
   3084 
   3085   @retval EFI_OUT_OF_RESOURCES    Required system resources could not be allocated.  See
   3086                                   ProgressErr for more data.
   3087 
   3088   @retval EFI_ACCESS_DENIED       The action violated system policy.  See ProgressErr for
   3089                                   more data.
   3090 
   3091   @retval EFI_DEVICE_ERROR        An unexpected system error occurred.  See ProgressErr
   3092                                   for more data.
   3093 
   3094 **/
   3095 EFI_STATUS
   3096 EFIAPI
   3097 EfiConfigKeywordHandlerGetData (
   3098   IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL  *This,
   3099   IN CONST EFI_STRING                     NameSpaceId, OPTIONAL
   3100   IN CONST EFI_STRING                     KeywordString, OPTIONAL
   3101   OUT EFI_STRING                          *Progress,
   3102   OUT UINT32                              *ProgressErr,
   3103   OUT EFI_STRING                          *Results
   3104   )
   3105 {
   3106   CHAR8                               *NameSpace;
   3107   EFI_STATUS                          Status;
   3108   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
   3109   HII_DATABASE_RECORD                 *DataBaseRecord;
   3110   CHAR16                              *StringPtr;
   3111   CHAR16                              *NextStringPtr;
   3112   CHAR16                              *KeywordData;
   3113   EFI_STRING_ID                       KeywordStringId;
   3114   UINT8                               *OpCode;
   3115   CHAR16                              *ConfigRequest;
   3116   CHAR16                              *ValueElement;
   3117   UINT32                              RetVal;
   3118   BOOLEAN                             ReadOnly;
   3119   CHAR16                              *KeywordResp;
   3120   CHAR16                              *MultiKeywordResp;
   3121   CHAR16                              *TempString;
   3122 
   3123   if (This == NULL || Progress == NULL || ProgressErr == NULL || Results == NULL) {
   3124     return EFI_INVALID_PARAMETER;
   3125   }
   3126 
   3127   *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
   3128   Status       = EFI_SUCCESS;
   3129   DevicePath   = NULL;
   3130   NameSpace    = NULL;
   3131   KeywordData  = NULL;
   3132   ConfigRequest= NULL;
   3133   StringPtr    = KeywordString;
   3134   ReadOnly     = FALSE;
   3135   MultiKeywordResp = NULL;
   3136   KeywordStringId  = 0;
   3137   TempString   = NULL;
   3138 
   3139   //
   3140   // Use temp string to avoid changing input string buffer.
   3141   //
   3142   if (NameSpaceId != NULL) {
   3143     TempString = AllocateCopyPool (StrSize (NameSpaceId), NameSpaceId);
   3144     ASSERT (TempString != NULL);
   3145   }
   3146   //
   3147   // 1. Get NameSpace from NameSpaceId keyword.
   3148   //
   3149   Status = ExtractNameSpace (TempString, &NameSpace, NULL);
   3150   if (TempString != NULL) {
   3151     FreePool (TempString);
   3152     TempString = NULL;
   3153   }
   3154   if (EFI_ERROR (Status)) {
   3155     *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   3156     return Status;
   3157   }
   3158   //
   3159   // 1.1 Check whether the input namespace is valid.
   3160   //
   3161   if (NameSpace != NULL){
   3162     if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
   3163       *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   3164       return EFI_INVALID_PARAMETER;
   3165     }
   3166   }
   3167 
   3168   if (KeywordString != NULL) {
   3169     //
   3170     // Use temp string to avoid changing input string buffer.
   3171     //
   3172     TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
   3173     ASSERT (TempString != NULL);
   3174     StringPtr = TempString;
   3175 
   3176     while (*StringPtr != L'\0') {
   3177       //
   3178       // 2. Get possible Device Path info from KeywordString.
   3179       //
   3180       Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
   3181       if (EFI_ERROR (Status)) {
   3182         *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   3183         goto Done;
   3184       }
   3185       StringPtr = NextStringPtr;
   3186 
   3187 
   3188       //
   3189       // 3. Process Keyword section from the input keywordRequest string.
   3190       //
   3191       // 3.1 Extract keyword from the KeywordRequest string.
   3192       //
   3193       Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
   3194       if (EFI_ERROR (Status)) {
   3195         //
   3196         // Can't find Keyword base on the input device path info.
   3197         //
   3198         *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
   3199         Status = EFI_INVALID_PARAMETER;
   3200         goto Done;
   3201       }
   3202 
   3203       //
   3204       // 3.2 Get EFI_STRING_ID for the input keyword.
   3205       //
   3206       Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
   3207       if (EFI_ERROR (Status)) {
   3208         *ProgressErr = RetVal;
   3209         goto Done;
   3210       }
   3211 
   3212       //
   3213       // 3.3 Construct the ConfigRequest string.
   3214       //
   3215       Status = ExtractConfigRequest (DataBaseRecord, KeywordStringId, &OpCode, &ConfigRequest);
   3216       if (EFI_ERROR (Status)) {
   3217         goto Done;
   3218       }
   3219 
   3220       //
   3221       // 3.4 Extract Value for the input keyword.
   3222       //
   3223       Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
   3224       if (EFI_ERROR (Status)) {
   3225         if (Status != EFI_OUT_OF_RESOURCES) {
   3226           Status = EFI_DEVICE_ERROR;
   3227         }
   3228         goto Done;
   3229       }
   3230       StringPtr = NextStringPtr;
   3231 
   3232       //
   3233       // 4. Process the possible filter section.
   3234       //
   3235       RetVal = ValidateFilter (OpCode, StringPtr, &NextStringPtr, &ReadOnly);
   3236       if (RetVal != KEYWORD_HANDLER_NO_ERROR) {
   3237         *ProgressErr = RetVal;
   3238         Status = EFI_INVALID_PARAMETER;
   3239         goto Done;
   3240       }
   3241       StringPtr = NextStringPtr;
   3242 
   3243 
   3244       //
   3245       // 5. Generate KeywordResp string.
   3246       //
   3247       Status = GenerateKeywordResp(NameSpace, DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
   3248       if (Status != EFI_SUCCESS) {
   3249         goto Done;
   3250       }
   3251 
   3252       //
   3253       // 6. Merge to the MultiKeywordResp string.
   3254       //
   3255       Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
   3256       if (EFI_ERROR (Status)) {
   3257         goto Done;
   3258       }
   3259 
   3260       //
   3261       // 7. Update return value.
   3262       //
   3263       *Results = MultiKeywordResp;
   3264 
   3265       //
   3266       // 8. Clean the temp buffer.
   3267       //
   3268       FreePool (DevicePath);
   3269       FreePool (KeywordData);
   3270       FreePool (ValueElement);
   3271       FreePool (ConfigRequest);
   3272       DevicePath = NULL;
   3273       KeywordData = NULL;
   3274       ValueElement = NULL;
   3275       ConfigRequest = NULL;
   3276       if (KeywordResp != NULL) {
   3277         FreePool (KeywordResp);
   3278         KeywordResp = NULL;
   3279       }
   3280     }
   3281   } else {
   3282     //
   3283     // Enumerate all keyword in the system.
   3284     //
   3285     Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp, ProgressErr);
   3286     if (EFI_ERROR (Status)) {
   3287       goto Done;
   3288     }
   3289     *Results = MultiKeywordResp;
   3290   }
   3291 
   3292   *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
   3293 
   3294 Done:
   3295   *Progress = KeywordString + (StringPtr - TempString);
   3296 
   3297   if (TempString != NULL) {
   3298     FreePool (TempString);
   3299   }
   3300   if (NameSpace != NULL) {
   3301     FreePool (NameSpace);
   3302   }
   3303   if (DevicePath != NULL) {
   3304     FreePool (DevicePath);
   3305   }
   3306   if (KeywordData != NULL) {
   3307     FreePool (KeywordData);
   3308   }
   3309 
   3310   return Status;
   3311 }
   3312