1 /** @file
2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
3 
4 Copyright (c) 2007 - 2015, 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 extern HII_DATABASE_PRIVATE_DATA mPrivate;
18 
19 /**
20   Calculate the number of Unicode characters of the incoming Configuration string,
21   not including NULL terminator.
22 
23   This is a internal function.
24 
25   @param  String                 String in <MultiConfigRequest> or
26                                  <MultiConfigResp> format.
27 
28   @return The number of Unicode characters.
29 
30 **/
31 UINTN
CalculateConfigStringLen(IN EFI_STRING String)32 CalculateConfigStringLen (
33   IN EFI_STRING                    String
34   )
35 {
36   EFI_STRING  TmpPtr;
37 
38   //
39   // "GUID=" should be the first element of incoming string.
40   //
41   ASSERT (String != NULL);
42   ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
43 
44   //
45   // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
46   // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
47   //
48   TmpPtr = StrStr (String, L"&GUID=");
49   if (TmpPtr == NULL) {
50     return StrLen (String);
51   }
52 
53   return (TmpPtr - String);
54 }
55 
56 
57 /**
58   Convert the hex UNICODE %02x encoding of a UEFI device path to binary
59   from <PathHdr> of <ConfigHdr>.
60 
61   This is a internal function.
62 
63   @param  String                 UEFI configuration string
64   @param  DevicePathData         Binary of a UEFI device path.
65 
66   @retval EFI_NOT_FOUND          The device path is not invalid.
67   @retval EFI_INVALID_PARAMETER  Any incoming parameter is invalid.
68   @retval EFI_OUT_OF_RESOURCES   Lake of resources to store neccesary structures.
69   @retval EFI_SUCCESS            The device path is retrieved and translated to
70                                  binary format.
71 
72 **/
73 EFI_STATUS
GetDevicePath(IN EFI_STRING String,OUT UINT8 ** DevicePathData)74 GetDevicePath (
75   IN  EFI_STRING                   String,
76   OUT UINT8                        **DevicePathData
77   )
78 {
79   UINTN                    Length;
80   EFI_STRING               PathHdr;
81   UINT8                    *DevicePathBuffer;
82   CHAR16                   TemStr[2];
83   UINTN                    Index;
84   UINT8                    DigitUint8;
85   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
86 
87 
88   if (String == NULL || DevicePathData == NULL) {
89     return EFI_INVALID_PARAMETER;
90   }
91 
92   //
93   // Find the 'PATH=' of <PathHdr> and skip it.
94   //
95   for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
96   if (*String == 0) {
97     return EFI_INVALID_PARAMETER;
98   }
99   //
100   // Check whether path data does exist.
101   //
102   String += StrLen (L"PATH=");
103   if (*String == 0) {
104     return EFI_INVALID_PARAMETER;
105   }
106   PathHdr = String;
107 
108   //
109   // The content between 'PATH=' of <ConfigHdr> and '&' of next element
110   // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
111   // of UEFI device path.
112   //
113   for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
114   //
115   // Check DevicePath Length
116   //
117   if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
118     return EFI_NOT_FOUND;
119   }
120 
121   //
122   // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
123   // as the device path resides in RAM memory.
124   // Translate the data into binary.
125   //
126   DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
127   if (DevicePathBuffer == NULL) {
128     return EFI_OUT_OF_RESOURCES;
129   }
130 
131   //
132   // Convert DevicePath
133   //
134   ZeroMem (TemStr, sizeof (TemStr));
135   for (Index = 0; Index < Length; Index ++) {
136     TemStr[0] = PathHdr[Index];
137     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
138     if ((Index & 1) == 0) {
139       DevicePathBuffer [Index/2] = DigitUint8;
140     } else {
141       DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
142     }
143   }
144 
145   //
146   // Validate DevicePath
147   //
148   DevicePath  = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
149   while (!IsDevicePathEnd (DevicePath)) {
150     if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
151       //
152       // Invalid device path
153       //
154       FreePool (DevicePathBuffer);
155       return EFI_NOT_FOUND;
156     }
157     DevicePath = NextDevicePathNode (DevicePath);
158   }
159 
160   //
161   // return the device path
162   //
163   *DevicePathData = DevicePathBuffer;
164   return EFI_SUCCESS;
165 }
166 
167 /**
168   Converts the unicode character of the string from uppercase to lowercase.
169   This is a internal function.
170 
171   @param ConfigString  String to be converted
172 
173 **/
174 VOID
175 EFIAPI
HiiToLower(IN EFI_STRING ConfigString)176 HiiToLower (
177   IN EFI_STRING  ConfigString
178   )
179 {
180   EFI_STRING  String;
181   BOOLEAN     Lower;
182 
183   ASSERT (ConfigString != NULL);
184 
185   //
186   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
187   //
188   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
189     if (*String == L'=') {
190       Lower = TRUE;
191     } else if (*String == L'&') {
192       Lower = FALSE;
193     } else if (Lower && *String >= L'A' && *String <= L'F') {
194       *String = (CHAR16) (*String - L'A' + L'a');
195     }
196   }
197 
198   return;
199 }
200 
201 /**
202   Generate a sub string then output it.
203 
204   This is a internal function.
205 
206   @param  String                 A constant string which is the prefix of the to be
207                                  generated string, e.g. GUID=
208 
209   @param  BufferLen              The length of the Buffer in bytes.
210 
211   @param  Buffer                 Points to a buffer which will be converted to be the
212                                  content of the generated string.
213 
214   @param  Flag                   If 1, the buffer contains data for the value of GUID or PATH stored in
215                                  UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
216                                  if 3, the buffer contains other data.
217 
218   @param  SubStr                 Points to the output string. It's caller's
219                                  responsibility to free this buffer.
220 
221 
222 **/
223 VOID
GenerateSubStr(IN CONST EFI_STRING String,IN UINTN BufferLen,IN VOID * Buffer,IN UINT8 Flag,OUT EFI_STRING * SubStr)224 GenerateSubStr (
225   IN CONST EFI_STRING              String,
226   IN  UINTN                        BufferLen,
227   IN  VOID                         *Buffer,
228   IN  UINT8                        Flag,
229   OUT EFI_STRING                   *SubStr
230   )
231 {
232   UINTN       Length;
233   EFI_STRING  Str;
234   EFI_STRING  StringHeader;
235   CHAR16      *TemString;
236   CHAR16      *TemName;
237   UINT8       *TemBuffer;
238   UINTN       Index;
239 
240   ASSERT (String != NULL && SubStr != NULL);
241 
242   if (Buffer == NULL) {
243     *SubStr = AllocateCopyPool (StrSize (String), String);
244     ASSERT (*SubStr != NULL);
245     return;
246   }
247 
248   //
249   // Header + Data + '&' + '\0'
250   //
251   Length = StrLen (String) + BufferLen * 2 + 1 + 1;
252   Str    = AllocateZeroPool (Length * sizeof (CHAR16));
253   ASSERT (Str != NULL);
254 
255   StrCpyS (Str, Length, String);
256 
257   StringHeader = Str + StrLen (String);
258   TemString    = (CHAR16 *) StringHeader;
259 
260   switch (Flag) {
261   case 1:
262     //
263     // Convert Buffer to Hex String in reverse order
264     //
265     TemBuffer = ((UINT8 *) Buffer);
266     for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) {
267       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
268     }
269     break;
270   case 2:
271     //
272     // Check buffer is enough
273     //
274     TemName = (CHAR16 *) Buffer;
275     ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1));
276     //
277     // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
278     //
279     for (; *TemName != L'\0'; TemName++) {
280       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
281     }
282     break;
283   case 3:
284     //
285     // Convert Buffer to Hex String
286     //
287     TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1;
288     for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) {
289       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
290     }
291     break;
292   default:
293     break;
294   }
295 
296   //
297   // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
298   //
299   StrCatS (Str, Length, L"&");
300   HiiToLower (Str);
301 
302   *SubStr = Str;
303 }
304 
305 
306 /**
307   Retrieve the <ConfigBody> from String then output it.
308 
309   This is a internal function.
310 
311   @param  String                 A sub string of a configuration string in
312                                  <MultiConfigAltResp> format.
313   @param  ConfigBody             Points to the output string. It's caller's
314                                  responsibility to free this buffer.
315 
316   @retval EFI_INVALID_PARAMETER  There is no form package in current hii database.
317   @retval EFI_OUT_OF_RESOURCES   Not enough memory to finish this operation.
318   @retval EFI_SUCCESS            All existing storage is exported.
319 
320 **/
321 EFI_STATUS
OutputConfigBody(IN EFI_STRING String,OUT EFI_STRING * ConfigBody)322 OutputConfigBody (
323   IN  EFI_STRING                   String,
324   OUT EFI_STRING                   *ConfigBody
325   )
326 {
327   EFI_STRING  TmpPtr;
328   EFI_STRING  Result;
329   UINTN       Length;
330 
331   if (String == NULL || ConfigBody == NULL) {
332     return EFI_INVALID_PARAMETER;
333   }
334 
335   //
336   // The setting information should start OFFSET, not ALTCFG.
337   //
338   if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) {
339     return EFI_INVALID_PARAMETER;
340   }
341 
342   TmpPtr = StrStr (String, L"GUID=");
343   if (TmpPtr == NULL) {
344     //
345     // It is the last <ConfigResp> of the incoming configuration string.
346     //
347     Result = AllocateCopyPool (StrSize (String), String);
348     if (Result == NULL) {
349       return EFI_OUT_OF_RESOURCES;
350     } else {
351       *ConfigBody = Result;
352       return EFI_SUCCESS;
353     }
354   }
355 
356   Length = TmpPtr - String;
357   if (Length == 0) {
358     return EFI_NOT_FOUND;
359   }
360   Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
361   if (Result == NULL) {
362     return EFI_OUT_OF_RESOURCES;
363   }
364 
365   *(Result + Length - 1) = 0;
366   *ConfigBody = Result;
367   return EFI_SUCCESS;
368 }
369 
370 /**
371   Append a string to a multi-string format.
372 
373   This is a internal function.
374 
375   @param  MultiString            String in <MultiConfigRequest>,
376                                  <MultiConfigAltResp>, or <MultiConfigResp>. On
377                                  input, the buffer length of  this string is
378                                  MAX_STRING_LENGTH. On output, the  buffer length
379                                  might be updated.
380   @param  AppendString           NULL-terminated Unicode string.
381 
382   @retval EFI_INVALID_PARAMETER  Any incoming parameter is invalid.
383   @retval EFI_SUCCESS            AppendString is append to the end of MultiString
384 
385 **/
386 EFI_STATUS
AppendToMultiString(IN OUT EFI_STRING * MultiString,IN EFI_STRING AppendString)387 AppendToMultiString (
388   IN OUT EFI_STRING                *MultiString,
389   IN EFI_STRING                    AppendString
390   )
391 {
392   UINTN AppendStringSize;
393   UINTN MultiStringSize;
394   UINTN MaxLen;
395 
396   if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
397     return EFI_INVALID_PARAMETER;
398   }
399 
400   AppendStringSize = StrSize (AppendString);
401   MultiStringSize  = StrSize (*MultiString);
402   MaxLen = MAX_STRING_LENGTH / sizeof (CHAR16);
403 
404   //
405   // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
406   //
407   if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
408       MultiStringSize > MAX_STRING_LENGTH) {
409     *MultiString = (EFI_STRING) ReallocatePool (
410                                   MultiStringSize,
411                                   MultiStringSize + AppendStringSize,
412                                   (VOID *) (*MultiString)
413                                   );
414     MaxLen = (MultiStringSize + AppendStringSize) / sizeof (CHAR16);
415     ASSERT (*MultiString != NULL);
416   }
417   //
418   // Append the incoming string
419   //
420   StrCatS (*MultiString, MaxLen, AppendString);
421 
422   return EFI_SUCCESS;
423 }
424 
425 
426 /**
427   Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
428   or WIDTH or VALUE.
429   <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
430 
431   This is a internal function.
432 
433   @param  StringPtr              String in <BlockConfig> format and points to the
434                                  first character of <Number>.
435   @param  Number                 The output value. Caller takes the responsibility
436                                  to free memory.
437   @param  Len                    Length of the <Number>, in characters.
438 
439   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to store neccessary
440                                  structures.
441   @retval EFI_SUCCESS            Value of <Number> is outputted in Number
442                                  successfully.
443 
444 **/
445 EFI_STATUS
GetValueOfNumber(IN EFI_STRING StringPtr,OUT UINT8 ** Number,OUT UINTN * Len)446 GetValueOfNumber (
447   IN EFI_STRING                    StringPtr,
448   OUT UINT8                        **Number,
449   OUT UINTN                        *Len
450   )
451 {
452   EFI_STRING               TmpPtr;
453   UINTN                    Length;
454   EFI_STRING               Str;
455   UINT8                    *Buf;
456   EFI_STATUS               Status;
457   UINT8                    DigitUint8;
458   UINTN                    Index;
459   CHAR16                   TemStr[2];
460 
461   if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) {
462     return EFI_INVALID_PARAMETER;
463   }
464 
465   Buf = NULL;
466 
467   TmpPtr = StringPtr;
468   while (*StringPtr != L'\0' && *StringPtr != L'&') {
469     StringPtr++;
470   }
471   *Len   = StringPtr - TmpPtr;
472   Length = *Len + 1;
473 
474   Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
475   if (Str == NULL) {
476     Status = EFI_OUT_OF_RESOURCES;
477     goto Exit;
478   }
479   CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
480   *(Str + *Len) = L'\0';
481 
482   Length = (Length + 1) / 2;
483   Buf = (UINT8 *) AllocateZeroPool (Length);
484   if (Buf == NULL) {
485     Status = EFI_OUT_OF_RESOURCES;
486     goto Exit;
487   }
488 
489   Length = *Len;
490   ZeroMem (TemStr, sizeof (TemStr));
491   for (Index = 0; Index < Length; Index ++) {
492     TemStr[0] = Str[Length - Index - 1];
493     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
494     if ((Index & 1) == 0) {
495       Buf [Index/2] = DigitUint8;
496     } else {
497       Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
498     }
499   }
500 
501   *Number = Buf;
502   Status  = EFI_SUCCESS;
503 
504 Exit:
505   if (Str != NULL) {
506     FreePool (Str);
507   }
508 
509   return Status;
510 }
511 
512 /**
513   This function merges DefaultAltCfgResp string into AltCfgResp string for
514   the missing AltCfgId in AltCfgResq.
515 
516   @param  AltCfgResp             Pointer to a null-terminated Unicode string in
517                                  <ConfigAltResp> format. The default value string
518                                  will be merged into it.
519   @param  DefaultAltCfgResp      Pointer to a null-terminated Unicode string in
520                                  <MultiConfigAltResp> format. The default value
521                                  string may contain more than one ConfigAltResp
522                                  string for the different varstore buffer.
523 
524   @retval EFI_SUCCESS            The merged string returns.
525   @retval EFI_INVALID_PARAMETER  *AltCfgResp is to NULL.
526 **/
527 EFI_STATUS
528 EFIAPI
MergeDefaultString(IN OUT EFI_STRING * AltCfgResp,IN EFI_STRING DefaultAltCfgResp)529 MergeDefaultString (
530   IN OUT EFI_STRING  *AltCfgResp,
531   IN     EFI_STRING  DefaultAltCfgResp
532   )
533 {
534   EFI_STRING   StringPtrDefault;
535   EFI_STRING   StringPtrEnd;
536   CHAR16       TempChar;
537   EFI_STRING   StringPtr;
538   EFI_STRING   AltConfigHdr;
539   UINTN        HeaderLength;
540   UINTN        SizeAltCfgResp;
541   UINTN        MaxLen;
542   UINTN        TotalSize;
543 
544   if (*AltCfgResp == NULL) {
545     return EFI_INVALID_PARAMETER;
546   }
547 
548   //
549   // Get the requestr ConfigHdr
550   //
551   SizeAltCfgResp  = 0;
552   StringPtr       = *AltCfgResp;
553 
554   //
555   // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
556   //
557   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
558     return EFI_INVALID_PARAMETER;
559   }
560   while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
561     StringPtr++;
562   }
563   while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
564     StringPtr++;
565   }
566   if (*StringPtr == L'\0') {
567     return EFI_INVALID_PARAMETER;
568   }
569   StringPtr += StrLen (L"&PATH=");
570   while (*StringPtr != L'\0' && *StringPtr != L'&') {
571     StringPtr ++;
572   }
573   HeaderLength = StringPtr - *AltCfgResp;
574 
575   //
576   // Construct AltConfigHdr string  "&<ConfigHdr>&ALTCFG=XXXX\0"
577   //                                  |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
578   //
579   MaxLen = 1 + HeaderLength + 8 + 4 + 1;
580   AltConfigHdr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
581   if (AltConfigHdr == NULL) {
582     return EFI_OUT_OF_RESOURCES;
583   }
584   StrCpyS (AltConfigHdr, MaxLen, L"&");
585   StrnCatS (AltConfigHdr, MaxLen, *AltCfgResp, HeaderLength);
586   StrCatS (AltConfigHdr, MaxLen, L"&ALTCFG=");
587   HeaderLength = StrLen (AltConfigHdr);
588 
589   StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
590   while (StringPtrDefault != NULL) {
591     //
592     // Get AltCfg Name
593     //
594     StrnCatS (AltConfigHdr, MaxLen, StringPtrDefault + HeaderLength, 4);
595     StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
596 
597     //
598     // Append the found default value string to the input AltCfgResp
599     //
600     if (StringPtr == NULL) {
601       StringPtrEnd   = StrStr (StringPtrDefault + 1, L"&GUID");
602       SizeAltCfgResp = StrSize (*AltCfgResp);
603       TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);
604       if (StringPtrEnd == NULL) {
605         //
606         // No more default string is found.
607         //
608         *AltCfgResp    = (EFI_STRING) ReallocatePool (
609                                      SizeAltCfgResp,
610                                      TotalSize,
611                                      (VOID *) (*AltCfgResp)
612                                      );
613         if (*AltCfgResp == NULL) {
614           FreePool (AltConfigHdr);
615           return EFI_OUT_OF_RESOURCES;
616         }
617         StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);
618         break;
619       } else {
620         TempChar = *StringPtrEnd;
621         *StringPtrEnd = L'\0';
622         *AltCfgResp = (EFI_STRING) ReallocatePool (
623                                      SizeAltCfgResp,
624                                      TotalSize,
625                                      (VOID *) (*AltCfgResp)
626                                      );
627         if (*AltCfgResp == NULL) {
628           FreePool (AltConfigHdr);
629           return EFI_OUT_OF_RESOURCES;
630         }
631         StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);
632         *StringPtrEnd = TempChar;
633       }
634     }
635 
636     //
637     // Find next AltCfg String
638     //
639     *(AltConfigHdr + HeaderLength) = L'\0';
640     StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
641   }
642 
643   FreePool (AltConfigHdr);
644   return EFI_SUCCESS;
645 }
646 
647 /**
648   This function inserts new DefaultValueData into the BlockData DefaultValue array.
649 
650   @param  BlockData         The BlockData is updated to add new default value.
651   @param  DefaultValueData  The DefaultValue is added.
652 
653 **/
654 VOID
InsertDefaultValue(IN IFR_BLOCK_DATA * BlockData,IN IFR_DEFAULT_DATA * DefaultValueData)655 InsertDefaultValue (
656   IN IFR_BLOCK_DATA         *BlockData,
657   IN IFR_DEFAULT_DATA       *DefaultValueData
658   )
659 {
660   LIST_ENTRY             *Link;
661   IFR_DEFAULT_DATA       *DefaultValueArray;
662   LIST_ENTRY             *DefaultLink;
663 
664   DefaultLink   = &BlockData->DefaultValueEntry;
665 
666   for (Link = DefaultLink->ForwardLink; Link != DefaultLink; Link = Link->ForwardLink) {
667     DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
668     if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
669       //
670       // DEFAULT_VALUE_FROM_OPCODE has high priority, DEFAULT_VALUE_FROM_DEFAULT has low priority.
671       //
672       if (DefaultValueData->Type > DefaultValueArray->Type) {
673         //
674         // Update the default value array in BlockData.
675         //
676         CopyMem (&DefaultValueArray->Value, &DefaultValueData->Value, sizeof (EFI_IFR_TYPE_VALUE));
677         DefaultValueArray->Type  = DefaultValueData->Type;
678         DefaultValueArray->Cleaned = DefaultValueData->Cleaned;
679       }
680       return;
681     }
682   }
683 
684   //
685   // Insert new default value data in tail.
686   //
687   DefaultValueArray = AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
688   ASSERT (DefaultValueArray != NULL);
689   CopyMem (DefaultValueArray, DefaultValueData, sizeof (IFR_DEFAULT_DATA));
690   InsertTailList (Link, &DefaultValueArray->Entry);
691 }
692 
693 /**
694   This function inserts new BlockData into the block link
695 
696   @param  BlockLink      The list entry points to block array.
697   @param  BlockData      The point to BlockData is added.
698 
699 **/
700 VOID
InsertBlockData(IN LIST_ENTRY * BlockLink,IN IFR_BLOCK_DATA ** BlockData)701 InsertBlockData (
702   IN LIST_ENTRY        *BlockLink,
703   IN IFR_BLOCK_DATA    **BlockData
704   )
705 {
706   LIST_ENTRY          *Link;
707   IFR_BLOCK_DATA      *BlockArray;
708   IFR_BLOCK_DATA      *BlockSingleData;
709 
710   BlockSingleData = *BlockData;
711 
712   if (BlockSingleData->Name != NULL) {
713     InsertTailList (BlockLink, &BlockSingleData->Entry);
714     return;
715   }
716 
717   //
718   // Insert block data in its Offset and Width order.
719   //
720   for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
721     BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
722     if (BlockArray->Offset == BlockSingleData->Offset) {
723       if (BlockArray->Width > BlockSingleData->Width) {
724         //
725         // Insert this block data in the front of block array
726         //
727         InsertTailList (Link, &BlockSingleData->Entry);
728         return;
729       }
730 
731       if (BlockArray->Width == BlockSingleData->Width) {
732         //
733         // The same block array has been added.
734         //
735         if (BlockSingleData != BlockArray) {
736           FreePool (BlockSingleData);
737           *BlockData = BlockArray;
738         }
739         return;
740       }
741     } else if (BlockArray->Offset > BlockSingleData->Offset) {
742       //
743       // Insert new block data in the front of block array
744       //
745       InsertTailList (Link, &BlockSingleData->Entry);
746       return;
747     }
748   }
749 
750   //
751   // Add new block data into the tail.
752   //
753   InsertTailList (Link, &BlockSingleData->Entry);
754 }
755 
756 /**
757   Retrieves a pointer to the a Null-terminated ASCII string containing the list
758   of languages that an HII handle in the HII Database supports.  The returned
759   string is allocated using AllocatePool().  The caller is responsible for freeing
760   the returned string using FreePool().  The format of the returned string follows
761   the language format assumed the HII Database.
762 
763   If HiiHandle is NULL, then ASSERT().
764 
765   @param[in]  HiiHandle  A handle that was previously registered in the HII Database.
766 
767   @retval NULL   HiiHandle is not registered in the HII database
768   @retval NULL   There are not enough resources available to retrieve the suported
769                  languages.
770   @retval NULL   The list of suported languages could not be retrieved.
771   @retval Other  A pointer to the Null-terminated ASCII string of supported languages.
772 
773 **/
774 CHAR8 *
GetSupportedLanguages(IN EFI_HII_HANDLE HiiHandle)775 GetSupportedLanguages (
776   IN EFI_HII_HANDLE           HiiHandle
777   )
778 {
779   EFI_STATUS  Status;
780   UINTN       LanguageSize;
781   CHAR8       TempSupportedLanguages;
782   CHAR8       *SupportedLanguages;
783 
784   ASSERT (HiiHandle != NULL);
785 
786   //
787   // Retrieve the size required for the supported languages buffer.
788   //
789   LanguageSize = 0;
790   Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize);
791 
792   //
793   // If GetLanguages() returns EFI_SUCCESS for a zero size,
794   // then there are no supported languages registered for HiiHandle.  If GetLanguages()
795   // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
796   // in the HII Database
797   //
798   if (Status != EFI_BUFFER_TOO_SMALL) {
799     //
800     // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database
801     //
802     return NULL;
803   }
804 
805   //
806   // Allocate the supported languages buffer.
807   //
808   SupportedLanguages = AllocateZeroPool (LanguageSize);
809   if (SupportedLanguages == NULL) {
810     //
811     // Return NULL if allocation fails.
812     //
813     return NULL;
814   }
815 
816   //
817   // Retrieve the supported languages string
818   //
819   Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, SupportedLanguages, &LanguageSize);
820   if (EFI_ERROR (Status)) {
821     //
822     // Free the buffer and return NULL if the supported languages can not be retrieved.
823     //
824     FreePool (SupportedLanguages);
825     return NULL;
826   }
827 
828   //
829   // Return the Null-terminated ASCII string of supported languages
830   //
831   return SupportedLanguages;
832 }
833 
834 /**
835   Retrieves a string from a string package.
836 
837   If HiiHandle is NULL, then ASSERT().
838   If StringId is 0, then ASSET.
839 
840   @param[in]  HiiHandle  A handle that was previously registered in the HII Database.
841   @param[in]  StringId   The identifier of the string to retrieved from the string
842                          package associated with HiiHandle.
843 
844   @retval NULL   The string specified by StringId is not present in the string package.
845   @retval Other  The string was returned.
846 
847 **/
848 EFI_STRING
InternalGetString(IN EFI_HII_HANDLE HiiHandle,IN EFI_STRING_ID StringId)849 InternalGetString (
850   IN EFI_HII_HANDLE  HiiHandle,
851   IN EFI_STRING_ID   StringId
852   )
853 {
854   EFI_STATUS  Status;
855   UINTN       StringSize;
856   CHAR16      TempString;
857   EFI_STRING  String;
858   CHAR8       *SupportedLanguages;
859   CHAR8       *PlatformLanguage;
860   CHAR8       *BestLanguage;
861   CHAR8       *Language;
862 
863   ASSERT (HiiHandle != NULL);
864   ASSERT (StringId != 0);
865 
866   //
867   // Initialize all allocated buffers to NULL
868   //
869   SupportedLanguages = NULL;
870   PlatformLanguage   = NULL;
871   BestLanguage       = NULL;
872   String             = NULL;
873   Language           = "";
874 
875   //
876   // Get the languages that the package specified by HiiHandle supports
877   //
878   SupportedLanguages = GetSupportedLanguages (HiiHandle);
879   if (SupportedLanguages == NULL) {
880     goto Error;
881   }
882 
883   //
884   // Get the current platform language setting
885   //
886   GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
887 
888   //
889   // Get the best matching language from SupportedLanguages
890   //
891   BestLanguage = GetBestLanguage (
892                    SupportedLanguages,
893                    FALSE,                                             // RFC 4646 mode
894                    Language,                                          // Highest priority
895                    PlatformLanguage != NULL ? PlatformLanguage : "",  // Next highest priority
896                    SupportedLanguages,                                // Lowest priority
897                    NULL
898                    );
899   if (BestLanguage == NULL) {
900     goto Error;
901   }
902 
903   //
904   // Retrieve the size of the string in the string package for the BestLanguage
905   //
906   StringSize = 0;
907   Status = mPrivate.HiiString.GetString (
908                          &mPrivate.HiiString,
909                          BestLanguage,
910                          HiiHandle,
911                          StringId,
912                          &TempString,
913                          &StringSize,
914                          NULL
915                          );
916   //
917   // If GetString() returns EFI_SUCCESS for a zero size,
918   // then there are no supported languages registered for HiiHandle.  If GetString()
919   // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
920   // in the HII Database
921   //
922   if (Status != EFI_BUFFER_TOO_SMALL) {
923     goto Error;
924   }
925 
926   //
927   // Allocate a buffer for the return string
928   //
929   String = AllocateZeroPool (StringSize);
930   if (String == NULL) {
931     goto Error;
932   }
933 
934   //
935   // Retrieve the string from the string package
936   //
937   Status = mPrivate.HiiString.GetString (
938                          &mPrivate.HiiString,
939                          BestLanguage,
940                          HiiHandle,
941                          StringId,
942                          String,
943                          &StringSize,
944                          NULL
945                          );
946   if (EFI_ERROR (Status)) {
947     //
948     // Free the buffer and return NULL if the supported languages can not be retrieved.
949     //
950     FreePool (String);
951     String = NULL;
952   }
953 
954 Error:
955   //
956   // Free allocated buffers
957   //
958   if (SupportedLanguages != NULL) {
959     FreePool (SupportedLanguages);
960   }
961   if (PlatformLanguage != NULL) {
962     FreePool (PlatformLanguage);
963   }
964   if (BestLanguage != NULL) {
965     FreePool (BestLanguage);
966   }
967 
968   //
969   // Return the Null-terminated Unicode string
970   //
971   return String;
972 }
973 
974 /**
975   This function checks VarOffset and VarWidth is in the block range.
976 
977   @param  RequestBlockArray  The block array is to be checked.
978   @param  VarOffset          Offset of var to the structure
979   @param  VarWidth           Width of var.
980   @param  IsNameValueType    Whether this varstore is name/value varstore or not.
981   @param  HiiHandle          Hii handle for this hii package.
982 
983   @retval TRUE   This Var is in the block range.
984   @retval FALSE  This Var is not in the block range.
985 **/
986 BOOLEAN
BlockArrayCheck(IN IFR_BLOCK_DATA * RequestBlockArray,IN UINT16 VarOffset,IN UINT16 VarWidth,IN BOOLEAN IsNameValueType,IN EFI_HII_HANDLE HiiHandle)987 BlockArrayCheck (
988   IN IFR_BLOCK_DATA  *RequestBlockArray,
989   IN UINT16          VarOffset,
990   IN UINT16          VarWidth,
991   IN BOOLEAN         IsNameValueType,
992   IN EFI_HII_HANDLE  HiiHandle
993   )
994 {
995   LIST_ENTRY          *Link;
996   IFR_BLOCK_DATA      *BlockData;
997   EFI_STRING          Name;
998 
999   //
1000   // No Request Block array, all vars are got.
1001   //
1002   if (RequestBlockArray == NULL) {
1003     return TRUE;
1004   }
1005 
1006   //
1007   // Check the input var is in the request block range.
1008   //
1009   for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
1010     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1011 
1012     if (IsNameValueType) {
1013       Name = InternalGetString (HiiHandle, VarOffset);
1014       ASSERT (Name != NULL);
1015 
1016       if (StrnCmp (BlockData->Name, Name, StrLen (Name)) == 0) {
1017         FreePool (Name);
1018         return TRUE;
1019       }
1020       FreePool (Name);
1021     } else {
1022       if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
1023         return TRUE;
1024       }
1025     }
1026   }
1027 
1028   return FALSE;
1029 }
1030 
1031 /**
1032   Get form package data from data base.
1033 
1034   @param  DataBaseRecord         The DataBaseRecord instance contains the found Hii handle and package.
1035   @param  HiiFormPackage         The buffer saves the package data.
1036   @param  PackageSize            The buffer size of the package data.
1037 
1038 **/
1039 EFI_STATUS
GetFormPackageData(IN HII_DATABASE_RECORD * DataBaseRecord,IN OUT UINT8 ** HiiFormPackage,OUT UINTN * PackageSize)1040 GetFormPackageData (
1041   IN     HII_DATABASE_RECORD        *DataBaseRecord,
1042   IN OUT UINT8                      **HiiFormPackage,
1043   OUT    UINTN                      *PackageSize
1044   )
1045 {
1046   EFI_STATUS                   Status;
1047   UINTN                        Size;
1048   UINTN                        ResultSize;
1049 
1050   if (DataBaseRecord == NULL || HiiFormPackage == NULL || PackageSize == NULL) {
1051     return EFI_INVALID_PARAMETER;
1052   }
1053 
1054   Size       = 0;
1055   ResultSize = 0;
1056   //
1057   // 0. Get Hii Form Package by HiiHandle
1058   //
1059   Status = ExportFormPackages (
1060              &mPrivate,
1061              DataBaseRecord->Handle,
1062              DataBaseRecord->PackageList,
1063              0,
1064              Size,
1065              HiiFormPackage,
1066              &ResultSize
1067            );
1068   if (EFI_ERROR (Status)) {
1069     return Status;
1070   }
1071 
1072   (*HiiFormPackage) = AllocatePool (ResultSize);
1073   if (*HiiFormPackage == NULL) {
1074     Status = EFI_OUT_OF_RESOURCES;
1075     return Status;
1076   }
1077 
1078   //
1079   // Get HiiFormPackage by HiiHandle
1080   //
1081   Size   = ResultSize;
1082   ResultSize    = 0;
1083   Status = ExportFormPackages (
1084              &mPrivate,
1085              DataBaseRecord->Handle,
1086              DataBaseRecord->PackageList,
1087              0,
1088              Size,
1089              *HiiFormPackage,
1090              &ResultSize
1091            );
1092   if (EFI_ERROR (Status)) {
1093     FreePool (*HiiFormPackage);
1094   }
1095 
1096   *PackageSize = Size;
1097 
1098   return Status;
1099 }
1100 
1101 
1102 /**
1103   This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
1104 
1105   @param  DataBaseRecord        The DataBaseRecord instance contains the found Hii handle and package.
1106   @param  ConfigHdr             Request string ConfigHdr. If it is NULL,
1107                                 the first found varstore will be as ConfigHdr.
1108   @param  IsEfiVarstore         Whether the request storage type is efi varstore type.
1109   @param  EfiVarStore           The efi varstore info which will return.
1110 **/
1111 EFI_STATUS
GetVarStoreType(IN HII_DATABASE_RECORD * DataBaseRecord,IN EFI_STRING ConfigHdr,OUT BOOLEAN * IsEfiVarstore,OUT EFI_IFR_VARSTORE_EFI ** EfiVarStore)1112 GetVarStoreType (
1113   IN     HII_DATABASE_RECORD        *DataBaseRecord,
1114   IN     EFI_STRING                 ConfigHdr,
1115   OUT    BOOLEAN                    *IsEfiVarstore,
1116   OUT    EFI_IFR_VARSTORE_EFI       **EfiVarStore
1117   )
1118 {
1119   EFI_STATUS               Status;
1120   UINTN                    IfrOffset;
1121   UINTN                    PackageOffset;
1122   EFI_IFR_OP_HEADER        *IfrOpHdr;
1123   CHAR16                   *VarStoreName;
1124   EFI_STRING               GuidStr;
1125   EFI_STRING               NameStr;
1126   EFI_STRING               TempStr;
1127   UINTN                    LengthString;
1128   UINT8                    *HiiFormPackage;
1129   UINTN                    PackageSize;
1130   EFI_IFR_VARSTORE_EFI     *IfrEfiVarStore;
1131   EFI_HII_PACKAGE_HEADER   *PackageHeader;
1132 
1133   HiiFormPackage = NULL;
1134   LengthString     = 0;
1135   Status           = EFI_SUCCESS;
1136   GuidStr          = NULL;
1137   NameStr          = NULL;
1138   TempStr          = NULL;
1139   *IsEfiVarstore   = FALSE;
1140 
1141   Status = GetFormPackageData(DataBaseRecord, &HiiFormPackage, &PackageSize);
1142   if (EFI_ERROR (Status)) {
1143     return Status;
1144   }
1145 
1146   IfrOffset     = sizeof (EFI_HII_PACKAGE_HEADER);
1147   PackageOffset = IfrOffset;
1148   PackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiFormPackage;
1149 
1150   while (IfrOffset < PackageSize) {
1151     //
1152     // More than one form packages exist.
1153     //
1154     if (PackageOffset >= PackageHeader->Length) {
1155         //
1156         // Process the new form package.
1157         //
1158         PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1159         IfrOffset    += PackageOffset;
1160         PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiFormPackage + IfrOffset);
1161     }
1162 
1163     IfrOpHdr  = (EFI_IFR_OP_HEADER *) (HiiFormPackage + IfrOffset);
1164     IfrOffset += IfrOpHdr->Length;
1165     PackageOffset += IfrOpHdr->Length;
1166 
1167     if (IfrOpHdr->OpCode == EFI_IFR_VARSTORE_EFI_OP ) {
1168       IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1169       //
1170       // If the length is small than the structure, this is from old efi
1171       // varstore definition. Old efi varstore get config directly from
1172       // GetVariable function.
1173       //
1174       if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
1175         continue;
1176       }
1177 
1178       VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
1179       if (VarStoreName == NULL) {
1180         Status = EFI_OUT_OF_RESOURCES;
1181         goto Done;
1182       }
1183       AsciiStrToUnicodeStr ((CHAR8 *) IfrEfiVarStore->Name, VarStoreName);
1184 
1185       GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrEfiVarStore->Guid, 1, &GuidStr);
1186       GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);
1187       LengthString = StrLen (GuidStr);
1188       LengthString = LengthString + StrLen (NameStr) + 1;
1189       TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
1190       if (TempStr == NULL) {
1191         FreePool (GuidStr);
1192         FreePool (NameStr);
1193         FreePool (VarStoreName);
1194         Status = EFI_OUT_OF_RESOURCES;
1195         goto Done;
1196       }
1197       StrCpyS (TempStr, LengthString, GuidStr);
1198       StrCatS (TempStr, LengthString, NameStr);
1199       if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
1200         *EfiVarStore = (EFI_IFR_VARSTORE_EFI *) AllocateZeroPool (IfrOpHdr->Length);
1201         if (*EfiVarStore == NULL) {
1202           FreePool (VarStoreName);
1203           FreePool (GuidStr);
1204           FreePool (NameStr);
1205           FreePool (TempStr);
1206           Status = EFI_OUT_OF_RESOURCES;
1207           goto Done;
1208         }
1209         *IsEfiVarstore = TRUE;
1210         CopyMem (*EfiVarStore, IfrEfiVarStore, IfrOpHdr->Length);
1211       }
1212 
1213       //
1214       // Free alllocated temp string.
1215       //
1216       FreePool (VarStoreName);
1217       FreePool (GuidStr);
1218       FreePool (NameStr);
1219       FreePool (TempStr);
1220 
1221       //
1222       // Already found the varstore, break;
1223       //
1224       if (*IsEfiVarstore) {
1225         break;
1226       }
1227     }
1228   }
1229 Done:
1230   if (HiiFormPackage != NULL) {
1231     FreePool (HiiFormPackage);
1232   }
1233 
1234   return Status;
1235 }
1236 
1237 /**
1238   Check whether the ConfigRequest string has the request elements.
1239   For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
1240   For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
1241 
1242   @param  ConfigRequest      The input config request string.
1243 
1244   @retval  TRUE              The input include config request elements.
1245   @retval  FALSE             The input string not includes.
1246 
1247 **/
1248 BOOLEAN
GetElementsFromRequest(IN EFI_STRING ConfigRequest)1249 GetElementsFromRequest (
1250   IN EFI_STRING    ConfigRequest
1251   )
1252 {
1253   EFI_STRING   TmpRequest;
1254 
1255   TmpRequest = StrStr (ConfigRequest, L"PATH=");
1256   ASSERT (TmpRequest != NULL);
1257 
1258   if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
1259     return TRUE;
1260   }
1261 
1262   return FALSE;
1263 }
1264 
1265 /**
1266   Check whether the this varstore is the request varstore.
1267 
1268   @param  VarstoreGuid      Varstore guid.
1269   @param  Name              Varstore name.
1270   @param  ConfigHdr         Current configRequest info.
1271 
1272   @retval  TRUE              This varstore is the requst one.
1273   @retval  FALSE             This varstore is not the requst one.
1274 
1275 **/
1276 BOOLEAN
IsThisVarstore(IN EFI_GUID * VarstoreGuid,IN CHAR16 * Name,IN CHAR16 * ConfigHdr)1277 IsThisVarstore (
1278   IN EFI_GUID    *VarstoreGuid,
1279   IN CHAR16      *Name,
1280   IN CHAR16      *ConfigHdr
1281   )
1282 {
1283   EFI_STRING               GuidStr;
1284   EFI_STRING               NameStr;
1285   EFI_STRING               TempStr;
1286   UINTN                    LengthString;
1287   BOOLEAN                  RetVal;
1288 
1289   RetVal       = FALSE;
1290   GuidStr      = NULL;
1291   TempStr      = NULL;
1292 
1293   //
1294   // If ConfigHdr has name field and varstore not has name, return FALSE.
1295   //
1296   if (Name == NULL && ConfigHdr != NULL && StrStr (ConfigHdr, L"NAME=&") == NULL) {
1297     return FALSE;
1298   }
1299 
1300   GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)VarstoreGuid, 1, &GuidStr);
1301   if (Name != NULL) {
1302     GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
1303   } else {
1304     GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1305   }
1306   LengthString = StrLen (GuidStr);
1307   LengthString = LengthString + StrLen (NameStr) + 1;
1308   TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
1309   if (TempStr == NULL) {
1310     goto Done;
1311   }
1312 
1313   StrCpyS (TempStr, LengthString, GuidStr);
1314   StrCatS (TempStr, LengthString, NameStr);
1315 
1316   if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
1317     RetVal = TRUE;
1318   }
1319 
1320 Done:
1321   if (GuidStr != NULL) {
1322     FreePool (GuidStr);
1323   }
1324 
1325   if (NameStr != NULL) {
1326     FreePool (NameStr);
1327   }
1328 
1329   if (TempStr != NULL) {
1330     FreePool (TempStr);
1331   }
1332 
1333   return RetVal;
1334 }
1335 
1336 /**
1337   This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
1338 
1339   @param  DataBaseRecord        The DataBaseRecord instance contains the found Hii handle and package.
1340   @param  ConfigHdr             Request string ConfigHdr. If it is NULL,
1341                                 the first found varstore will be as ConfigHdr.
1342   @retval  TRUE                 This hii package is the reqeust one.
1343   @retval  FALSE                This hii package is not the reqeust one.
1344 **/
1345 BOOLEAN
IsThisPackageList(IN HII_DATABASE_RECORD * DataBaseRecord,IN EFI_STRING ConfigHdr)1346 IsThisPackageList (
1347   IN     HII_DATABASE_RECORD        *DataBaseRecord,
1348   IN     EFI_STRING                 ConfigHdr
1349   )
1350 {
1351   EFI_STATUS               Status;
1352   UINTN                    IfrOffset;
1353   UINTN                    PackageOffset;
1354   EFI_IFR_OP_HEADER        *IfrOpHdr;
1355   CHAR16                   *VarStoreName;
1356   UINT8                    *HiiFormPackage;
1357   UINTN                    PackageSize;
1358   EFI_IFR_VARSTORE_EFI     *IfrEfiVarStore;
1359   EFI_HII_PACKAGE_HEADER   *PackageHeader;
1360   EFI_IFR_VARSTORE         *IfrVarStore;
1361   EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
1362   BOOLEAN                  FindVarstore;
1363 
1364   HiiFormPackage   = NULL;
1365   VarStoreName     = NULL;
1366   Status           = EFI_SUCCESS;
1367   FindVarstore     = FALSE;
1368 
1369   Status = GetFormPackageData(DataBaseRecord, &HiiFormPackage, &PackageSize);
1370   if (EFI_ERROR (Status)) {
1371     return FALSE;
1372   }
1373 
1374   IfrOffset     = sizeof (EFI_HII_PACKAGE_HEADER);
1375   PackageOffset = IfrOffset;
1376   PackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiFormPackage;
1377 
1378   while (IfrOffset < PackageSize) {
1379     //
1380     // More than one form packages exist.
1381     //
1382     if (PackageOffset >= PackageHeader->Length) {
1383         //
1384         // Process the new form package.
1385         //
1386         PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1387         IfrOffset    += PackageOffset;
1388         PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiFormPackage + IfrOffset);
1389     }
1390 
1391     IfrOpHdr  = (EFI_IFR_OP_HEADER *) (HiiFormPackage + IfrOffset);
1392     IfrOffset += IfrOpHdr->Length;
1393     PackageOffset += IfrOpHdr->Length;
1394 
1395     switch (IfrOpHdr->OpCode) {
1396 
1397     case EFI_IFR_VARSTORE_OP:
1398       IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
1399 
1400       VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
1401       if (VarStoreName == NULL) {
1402         goto Done;
1403       }
1404       AsciiStrToUnicodeStr ((CHAR8 *)IfrVarStore->Name, VarStoreName);
1405 
1406       if (IsThisVarstore((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
1407         FindVarstore = TRUE;
1408         goto Done;
1409       }
1410       break;
1411 
1412     case EFI_IFR_VARSTORE_EFI_OP:
1413       IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1414       VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
1415       if (VarStoreName == NULL) {
1416         goto Done;
1417       }
1418       AsciiStrToUnicodeStr ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName);
1419 
1420       if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
1421         FindVarstore = TRUE;
1422         goto Done;
1423       }
1424       break;
1425 
1426     case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1427       IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
1428 
1429       if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
1430         FindVarstore = TRUE;
1431         goto Done;
1432       }
1433       break;
1434 
1435     case EFI_IFR_FORM_OP:
1436     case EFI_IFR_FORM_MAP_OP:
1437       //
1438       // No matched varstore is found and directly return.
1439       //
1440       goto Done;
1441 
1442     default:
1443       break;
1444     }
1445   }
1446 Done:
1447   if (HiiFormPackage != NULL) {
1448     FreePool (HiiFormPackage);
1449   }
1450 
1451   if (VarStoreName != NULL) {
1452     FreePool (VarStoreName);
1453   }
1454 
1455   return FindVarstore;
1456 }
1457 
1458 /**
1459   Check whether the this op code is required.
1460 
1461   @param  RequestBlockArray      The array includes all the request info or NULL.
1462   @param  HiiHandle              The hii handle for this form package.
1463   @param  VarStorageData         The varstore data strucure.
1464   @param  IfrOpHdr               Ifr opcode header for this opcode.
1465   @param  VarWidth               The buffer width for this opcode.
1466   @param  ReturnData             The data block added for this opcode.
1467 
1468   @retval  EFI_SUCCESS           This opcode is required.
1469   @retval  Others                This opcode is not required or error occur.
1470 
1471 **/
1472 EFI_STATUS
IsThisOpcodeRequired(IN IFR_BLOCK_DATA * RequestBlockArray,IN EFI_HII_HANDLE HiiHandle,IN OUT IFR_VARSTORAGE_DATA * VarStorageData,IN EFI_IFR_OP_HEADER * IfrOpHdr,IN UINT16 VarWidth,OUT IFR_BLOCK_DATA ** ReturnData)1473 IsThisOpcodeRequired (
1474   IN     IFR_BLOCK_DATA           *RequestBlockArray,
1475   IN     EFI_HII_HANDLE           HiiHandle,
1476   IN OUT IFR_VARSTORAGE_DATA      *VarStorageData,
1477   IN     EFI_IFR_OP_HEADER        *IfrOpHdr,
1478   IN     UINT16                   VarWidth,
1479   OUT    IFR_BLOCK_DATA           **ReturnData
1480   )
1481 {
1482   IFR_BLOCK_DATA           *BlockData;
1483   UINT16                   VarOffset;
1484   EFI_STRING_ID            NameId;
1485   EFI_IFR_QUESTION_HEADER  *IfrQuestionHdr;
1486 
1487   NameId    = 0;
1488   VarOffset = 0;
1489   IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER  *)((CHAR8 *) IfrOpHdr + sizeof (EFI_IFR_OP_HEADER));
1490 
1491   if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
1492     NameId = IfrQuestionHdr->VarStoreInfo.VarName;
1493 
1494     //
1495     // Check whether this question is in requested block array.
1496     //
1497     if (!BlockArrayCheck (RequestBlockArray, NameId, 0, TRUE, HiiHandle)) {
1498       //
1499       // This question is not in the requested string. Skip it.
1500       //
1501       return EFI_SUCCESS;
1502     }
1503   } else {
1504     VarOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
1505 
1506     //
1507     // Check whether this question is in requested block array.
1508     //
1509     if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth, FALSE, HiiHandle)) {
1510       //
1511       // This question is not in the requested string. Skip it.
1512       //
1513       return EFI_SUCCESS;
1514     }
1515 
1516     //
1517     // Check this var question is in the var storage
1518     //
1519     if (((VarOffset + VarWidth) > VarStorageData->Size)) {
1520       return EFI_INVALID_PARAMETER;
1521     }
1522   }
1523 
1524   BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1525   if (BlockData == NULL) {
1526     return EFI_OUT_OF_RESOURCES;
1527   }
1528 
1529   if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
1530     BlockData->Name   = InternalGetString(HiiHandle, NameId);
1531   } else {
1532     BlockData->Offset = VarOffset;
1533   }
1534 
1535   BlockData->Width      = VarWidth;
1536   BlockData->QuestionId = IfrQuestionHdr->QuestionId;
1537   BlockData->OpCode     = IfrOpHdr->OpCode;
1538   BlockData->Scope      = IfrOpHdr->Scope;
1539   InitializeListHead (&BlockData->DefaultValueEntry);
1540   //
1541   // Add Block Data into VarStorageData BlockEntry
1542   //
1543   InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1544   *ReturnData = BlockData;
1545 
1546   return EFI_SUCCESS;
1547 }
1548 
1549 /**
1550   This function parses Form Package to get the block array and the default
1551   value array according to the request ConfigHdr.
1552 
1553   @param  HiiHandle             Hii Handle for this hii package.
1554   @param  Package               Pointer to the form package data.
1555   @param  PackageLength         Length of the pacakge.
1556   @param  ConfigHdr             Request string ConfigHdr. If it is NULL,
1557                                 the first found varstore will be as ConfigHdr.
1558   @param  RequestBlockArray     The block array is retrieved from the request string.
1559   @param  VarStorageData        VarStorage structure contains the got block and default value.
1560   @param  DefaultIdArray        Point to the got default id and default name array.
1561 
1562   @retval EFI_SUCCESS           The block array and the default value array are got.
1563   @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges
1564                                 are conflicted.
1565   @retval EFI_OUT_OF_RESOURCES  No enough memory.
1566 **/
1567 EFI_STATUS
1568 EFIAPI
ParseIfrData(IN EFI_HII_HANDLE HiiHandle,IN UINT8 * Package,IN UINT32 PackageLength,IN EFI_STRING ConfigHdr,IN IFR_BLOCK_DATA * RequestBlockArray,IN OUT IFR_VARSTORAGE_DATA * VarStorageData,OUT IFR_DEFAULT_DATA * DefaultIdArray)1569 ParseIfrData (
1570   IN     EFI_HII_HANDLE      HiiHandle,
1571   IN     UINT8               *Package,
1572   IN     UINT32              PackageLength,
1573   IN     EFI_STRING          ConfigHdr,
1574   IN     IFR_BLOCK_DATA      *RequestBlockArray,
1575   IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
1576   OUT    IFR_DEFAULT_DATA    *DefaultIdArray
1577   )
1578 {
1579   EFI_STATUS               Status;
1580   UINTN                    IfrOffset;
1581   UINTN                    PackageOffset;
1582   EFI_IFR_VARSTORE         *IfrVarStore;
1583   EFI_IFR_VARSTORE_EFI     *IfrEfiVarStore;
1584   EFI_IFR_OP_HEADER        *IfrOpHdr;
1585   EFI_IFR_ONE_OF           *IfrOneOf;
1586   EFI_IFR_REF4             *IfrRef;
1587   EFI_IFR_ONE_OF_OPTION    *IfrOneOfOption;
1588   EFI_IFR_DEFAULT          *IfrDefault;
1589   EFI_IFR_ORDERED_LIST     *IfrOrderedList;
1590   EFI_IFR_CHECKBOX         *IfrCheckBox;
1591   EFI_IFR_PASSWORD         *IfrPassword;
1592   EFI_IFR_STRING           *IfrString;
1593   EFI_IFR_DATE             *IfrDate;
1594   EFI_IFR_TIME             *IfrTime;
1595   IFR_DEFAULT_DATA         DefaultData;
1596   IFR_DEFAULT_DATA         *DefaultDataPtr;
1597   IFR_BLOCK_DATA           *BlockData;
1598   CHAR16                   *VarStoreName;
1599   UINT16                   VarWidth;
1600   UINT16                   VarDefaultId;
1601   BOOLEAN                  FirstOneOfOption;
1602   BOOLEAN                  FirstOrderedList;
1603   LIST_ENTRY               *LinkData;
1604   LIST_ENTRY               *LinkDefault;
1605   EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
1606   EFI_HII_PACKAGE_HEADER   *PackageHeader;
1607   EFI_VARSTORE_ID          VarStoreId;
1608 
1609   Status           = EFI_SUCCESS;
1610   BlockData        = NULL;
1611   DefaultDataPtr   = NULL;
1612   FirstOneOfOption = FALSE;
1613   VarStoreId       = 0;
1614   FirstOrderedList = FALSE;
1615   ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA));
1616 
1617   //
1618   // Go through the form package to parse OpCode one by one.
1619   //
1620   PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1621   PackageHeader = (EFI_HII_PACKAGE_HEADER *) Package;
1622   IfrOffset     = PackageOffset;
1623   while (IfrOffset < PackageLength) {
1624 
1625     //
1626     // More than one form package found.
1627     //
1628     if (PackageOffset >= PackageHeader->Length) {
1629         //
1630         // Already found varstore for this request, break;
1631         //
1632         if (VarStoreId != 0) {
1633           VarStoreId = 0;
1634         }
1635 
1636         //
1637         // Get next package header info.
1638         //
1639         IfrOffset    += sizeof (EFI_HII_PACKAGE_HEADER);
1640         PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1641         PackageHeader = (EFI_HII_PACKAGE_HEADER *) (Package + IfrOffset);
1642     }
1643 
1644     IfrOpHdr  = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);
1645     switch (IfrOpHdr->OpCode) {
1646     case EFI_IFR_VARSTORE_OP:
1647       //
1648       // VarStore is found. Don't need to search any more.
1649       //
1650       if (VarStoreId != 0) {
1651         break;
1652       }
1653 
1654       IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
1655 
1656       VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
1657       if (VarStoreName == NULL) {
1658         Status = EFI_OUT_OF_RESOURCES;
1659         goto Done;
1660       }
1661       AsciiStrToUnicodeStr ((CHAR8 *)IfrVarStore->Name, VarStoreName);
1662 
1663       if (IsThisVarstore((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
1664         //
1665         // Find the matched VarStore
1666         //
1667         CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);
1668         VarStorageData->Size       = IfrVarStore->Size;
1669         VarStorageData->Name       = VarStoreName;
1670         VarStorageData->Type       = EFI_HII_VARSTORE_BUFFER;
1671         VarStoreId                 = IfrVarStore->VarStoreId;
1672       }
1673       break;
1674 
1675     case EFI_IFR_VARSTORE_EFI_OP:
1676       //
1677       // VarStore is found. Don't need to search any more.
1678       //
1679       if (VarStoreId != 0) {
1680         break;
1681       }
1682 
1683       IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1684 
1685       //
1686       // If the length is small than the structure, this is from old efi
1687       // varstore definition. Old efi varstore get config directly from
1688       // GetVariable function.
1689       //
1690       if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
1691         break;
1692       }
1693 
1694       VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
1695       if (VarStoreName == NULL) {
1696         Status = EFI_OUT_OF_RESOURCES;
1697         goto Done;
1698       }
1699       AsciiStrToUnicodeStr ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName);
1700 
1701       if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
1702         //
1703         // Find the matched VarStore
1704         //
1705         CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid);
1706         VarStorageData->Size       = IfrEfiVarStore->Size;
1707         VarStorageData->Name       = VarStoreName;
1708         VarStorageData->Type       = EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER;
1709         VarStoreId                 = IfrEfiVarStore->VarStoreId;
1710       }
1711       break;
1712 
1713     case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1714       //
1715       // VarStore is found. Don't need to search any more.
1716       //
1717       if (VarStoreId != 0) {
1718         break;
1719       }
1720 
1721       IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
1722 
1723       if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
1724         //
1725         // Find the matched VarStore
1726         //
1727         CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrNameValueVarStore->Guid);
1728         VarStorageData->Type       = EFI_HII_VARSTORE_NAME_VALUE;
1729         VarStoreId                 = IfrNameValueVarStore->VarStoreId;
1730       }
1731       break;
1732 
1733     case EFI_IFR_DEFAULTSTORE_OP:
1734       //
1735       // Add new the map between default id and default name.
1736       //
1737       DefaultDataPtr = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1738       if (DefaultDataPtr == NULL) {
1739         Status = EFI_OUT_OF_RESOURCES;
1740         goto Done;
1741       }
1742       DefaultDataPtr->DefaultId   = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
1743       InsertTailList (&DefaultIdArray->Entry, &DefaultDataPtr->Entry);
1744       DefaultDataPtr = NULL;
1745       break;
1746 
1747     case EFI_IFR_FORM_OP:
1748     case EFI_IFR_FORM_MAP_OP:
1749       //
1750       // No matched varstore is found and directly return.
1751       //
1752       if ( VarStoreId == 0) {
1753         Status = EFI_SUCCESS;
1754         goto Done;
1755       }
1756       break;
1757 
1758     case EFI_IFR_REF_OP:
1759       //
1760       // Ref question is not in IFR Form. This IFR form is not valid.
1761       //
1762       if ( VarStoreId == 0) {
1763         Status = EFI_INVALID_PARAMETER;
1764         goto Done;
1765       }
1766       //
1767       // Check whether this question is for the requested varstore.
1768       //
1769       IfrRef = (EFI_IFR_REF4 *) IfrOpHdr;
1770       if (IfrRef->Question.VarStoreId != VarStoreId) {
1771         break;
1772       }
1773       VarWidth  = (UINT16) (sizeof (EFI_HII_REF));
1774 
1775       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1776       if (EFI_ERROR (Status)) {
1777         goto Done;
1778       }
1779       break;
1780 
1781     case EFI_IFR_ONE_OF_OP:
1782     case EFI_IFR_NUMERIC_OP:
1783       //
1784       // Numeric and OneOf has the same opcode structure.
1785       //
1786 
1787       //
1788       // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
1789       //
1790       if (VarStoreId == 0) {
1791         Status = EFI_INVALID_PARAMETER;
1792         goto Done;
1793       }
1794       //
1795       // Check whether this question is for the requested varstore.
1796       //
1797       IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
1798       if (IfrOneOf->Question.VarStoreId != VarStoreId) {
1799         break;
1800       }
1801       VarWidth  = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
1802 
1803       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1804       if (EFI_ERROR (Status)) {
1805         goto Done;
1806       }
1807 
1808       if (BlockData == NULL) {
1809         //
1810         // BlockData == NULL means this opcode is not in the requst array.
1811         //
1812         break;
1813       }
1814 
1815       if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
1816         //
1817         // Set this flag to TRUE for the first oneof option.
1818         //
1819         FirstOneOfOption = TRUE;
1820       } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
1821         //
1822         // Numeric minimum value will be used as default value when no default is specified.
1823         //
1824         DefaultData.Type        = DefaultValueFromDefault;
1825         switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
1826         case EFI_IFR_NUMERIC_SIZE_1:
1827           DefaultData.Value.u8 = IfrOneOf->data.u8.MinValue;
1828           break;
1829 
1830         case EFI_IFR_NUMERIC_SIZE_2:
1831           CopyMem (&DefaultData.Value.u16, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
1832           break;
1833 
1834         case EFI_IFR_NUMERIC_SIZE_4:
1835           CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
1836           break;
1837 
1838         case EFI_IFR_NUMERIC_SIZE_8:
1839           CopyMem (&DefaultData.Value.u64, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
1840           break;
1841 
1842         default:
1843           Status = EFI_INVALID_PARAMETER;
1844           goto Done;
1845         }
1846         //
1847         // Set default value base on the DefaultId list get from IFR data.
1848         //
1849         for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
1850           DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
1851           DefaultData.DefaultId   = DefaultDataPtr->DefaultId;
1852           InsertDefaultValue (BlockData, &DefaultData);
1853         }
1854       }
1855       break;
1856 
1857     case EFI_IFR_ORDERED_LIST_OP:
1858       //
1859       // offset by question header
1860       // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
1861       //
1862 
1863       FirstOrderedList = TRUE;
1864       //
1865       // OrderedList question is not in IFR Form. This IFR form is not valid.
1866       //
1867       if (VarStoreId == 0) {
1868         Status = EFI_INVALID_PARAMETER;
1869         goto Done;
1870       }
1871       //
1872       // Check whether this question is for the requested varstore.
1873       //
1874       IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;
1875       if (IfrOrderedList->Question.VarStoreId != VarStoreId) {
1876         BlockData = NULL;
1877         break;
1878       }
1879       VarWidth  = IfrOrderedList->MaxContainers;
1880       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1881       if (EFI_ERROR (Status)) {
1882         goto Done;
1883       }
1884       break;
1885 
1886     case EFI_IFR_CHECKBOX_OP:
1887       //
1888       // EFI_IFR_DEFAULT_OP
1889       // offset by question header
1890       // width is 1 sizeof (BOOLEAN)
1891       // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
1892       // value by DefaultOption
1893       // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
1894       //
1895 
1896       //
1897       // CheckBox question is not in IFR Form. This IFR form is not valid.
1898       //
1899       if (VarStoreId == 0) {
1900         Status = EFI_INVALID_PARAMETER;
1901         goto Done;
1902       }
1903       //
1904       // Check whether this question is for the requested varstore.
1905       //
1906       IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1907       if (IfrCheckBox->Question.VarStoreId != VarStoreId) {
1908         break;
1909       }
1910       VarWidth  = (UINT16) sizeof (BOOLEAN);
1911       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1912       if (EFI_ERROR (Status)) {
1913         goto Done;
1914       }
1915 
1916       if (BlockData == NULL) {
1917         //
1918         // BlockData == NULL means this opcode is not in the requst array.
1919         //
1920         break;
1921       }
1922 
1923       //
1924       // Add default value for standard ID by CheckBox Flag
1925       //
1926       VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1927       //
1928       // Prepare new DefaultValue
1929       //
1930       DefaultData.DefaultId   = VarDefaultId;
1931       if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
1932         //
1933         // When flag is set, defautl value is TRUE.
1934         //
1935         DefaultData.Type    = DefaultValueFromFlag;
1936         DefaultData.Value.b = TRUE;
1937       } else {
1938         //
1939         // When flag is not set, defautl value is FASLE.
1940         //
1941         DefaultData.Type    = DefaultValueFromDefault;
1942         DefaultData.Value.b = FALSE;
1943       }
1944       //
1945       // Add DefaultValue into current BlockData
1946       //
1947       InsertDefaultValue (BlockData, &DefaultData);
1948 
1949       //
1950       // Add default value for Manufacture ID by CheckBox Flag
1951       //
1952       VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1953       //
1954       // Prepare new DefaultValue
1955       //
1956       DefaultData.DefaultId   = VarDefaultId;
1957       if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
1958         //
1959         // When flag is set, defautl value is TRUE.
1960         //
1961         DefaultData.Type    = DefaultValueFromFlag;
1962         DefaultData.Value.b = TRUE;
1963       } else {
1964         //
1965         // When flag is not set, defautl value is FASLE.
1966         //
1967         DefaultData.Type    = DefaultValueFromDefault;
1968         DefaultData.Value.b = FALSE;
1969       }
1970       //
1971       // Add DefaultValue into current BlockData
1972       //
1973       InsertDefaultValue (BlockData, &DefaultData);
1974       break;
1975 
1976     case EFI_IFR_DATE_OP:
1977       //
1978       // offset by question header
1979       // width MaxSize * sizeof (CHAR16)
1980       // no default value, only block array
1981       //
1982 
1983       //
1984       // Date question is not in IFR Form. This IFR form is not valid.
1985       //
1986       if (VarStoreId == 0) {
1987         Status = EFI_INVALID_PARAMETER;
1988         goto Done;
1989       }
1990       //
1991       // Check whether this question is for the requested varstore.
1992       //
1993       IfrDate = (EFI_IFR_DATE *) IfrOpHdr;
1994       if (IfrDate->Question.VarStoreId != VarStoreId) {
1995         break;
1996       }
1997 
1998       VarWidth  = (UINT16) sizeof (EFI_HII_DATE);
1999       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2000       if (EFI_ERROR (Status)) {
2001         goto Done;
2002       }
2003       break;
2004 
2005     case EFI_IFR_TIME_OP:
2006       //
2007       // offset by question header
2008       // width MaxSize * sizeof (CHAR16)
2009       // no default value, only block array
2010       //
2011 
2012       //
2013       // Time question is not in IFR Form. This IFR form is not valid.
2014       //
2015       if (VarStoreId == 0) {
2016         Status = EFI_INVALID_PARAMETER;
2017         goto Done;
2018       }
2019       //
2020       // Check whether this question is for the requested varstore.
2021       //
2022       IfrTime = (EFI_IFR_TIME *) IfrOpHdr;
2023       if (IfrTime->Question.VarStoreId != VarStoreId) {
2024         break;
2025       }
2026 
2027       VarWidth  = (UINT16) sizeof (EFI_HII_TIME);
2028       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2029       if (EFI_ERROR (Status)) {
2030         goto Done;
2031       }
2032       break;
2033 
2034     case EFI_IFR_STRING_OP:
2035       //
2036       // offset by question header
2037       // width MaxSize * sizeof (CHAR16)
2038       // no default value, only block array
2039       //
2040 
2041       //
2042       // String question is not in IFR Form. This IFR form is not valid.
2043       //
2044       if (VarStoreId == 0) {
2045         Status = EFI_INVALID_PARAMETER;
2046         goto Done;
2047       }
2048       //
2049       // Check whether this question is for the requested varstore.
2050       //
2051       IfrString = (EFI_IFR_STRING *) IfrOpHdr;
2052       if (IfrString->Question.VarStoreId != VarStoreId) {
2053         break;
2054       }
2055 
2056       VarWidth  = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
2057       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2058       if (EFI_ERROR (Status)) {
2059         goto Done;
2060       }
2061       break;
2062 
2063     case EFI_IFR_PASSWORD_OP:
2064       //
2065       // offset by question header
2066       // width MaxSize * sizeof (CHAR16)
2067       // no default value, only block array
2068       //
2069 
2070       //
2071       // Password question is not in IFR Form. This IFR form is not valid.
2072       //
2073       if (VarStoreId == 0) {
2074         Status = EFI_INVALID_PARAMETER;
2075         goto Done;
2076       }
2077       //
2078       // Check whether this question is for the requested varstore.
2079       //
2080       IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
2081       if (IfrPassword->Question.VarStoreId != VarStoreId) {
2082         break;
2083       }
2084 
2085       VarWidth  = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
2086       Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2087       if (EFI_ERROR (Status)) {
2088         goto Done;
2089       }
2090 
2091       //
2092       // No default value for string.
2093       //
2094       BlockData = NULL;
2095       break;
2096 
2097     case EFI_IFR_ONE_OF_OPTION_OP:
2098       //
2099       // No matched block data is ignored.
2100       //
2101       if (BlockData == NULL || BlockData->Scope == 0) {
2102         break;
2103       }
2104 
2105       IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
2106       if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
2107 
2108         if (!FirstOrderedList){
2109           break;
2110         }
2111         //
2112         // Get ordered list option data type.
2113         //
2114         if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
2115           VarWidth = 1;
2116         } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
2117           VarWidth = 2;
2118         } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
2119           VarWidth = 4;
2120         } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
2121           VarWidth = 8;
2122         } else {
2123           //
2124           // Invalid ordered list option data type.
2125           //
2126           Status = EFI_INVALID_PARAMETER;
2127           if (BlockData->Name != NULL) {
2128             FreePool (BlockData->Name);
2129           }
2130           FreePool (BlockData);
2131           goto Done;
2132         }
2133 
2134         //
2135         // Calculate Ordered list QuestionId width.
2136         //
2137         BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
2138         //
2139         // Check whether this question is in requested block array.
2140         //
2141         if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width, (BOOLEAN)(BlockData->Name != NULL), HiiHandle)) {
2142           //
2143           // This question is not in the requested string. Skip it.
2144           //
2145           if (BlockData->Name != NULL) {
2146             FreePool (BlockData->Name);
2147           }
2148           FreePool (BlockData);
2149           BlockData = NULL;
2150           break;
2151         }
2152         //
2153         // Check this var question is in the var storage
2154         //
2155         if ((BlockData->Name == NULL) && ((BlockData->Offset + BlockData->Width) > VarStorageData->Size)) {
2156           Status = EFI_INVALID_PARAMETER;
2157           if (BlockData->Name != NULL) {
2158             FreePool (BlockData->Name);
2159           }
2160           FreePool (BlockData);
2161           goto Done;
2162         }
2163         //
2164         // Add Block Data into VarStorageData BlockEntry
2165         //
2166         InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
2167 
2168         FirstOrderedList = FALSE;
2169 
2170         break;
2171       }
2172 
2173       //
2174       // 1. Set default value for OneOf option when flag field has default attribute.
2175       //
2176       if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
2177           ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG)) {
2178         //
2179         // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
2180         // The first oneof option value will be used as default value when no default value is specified.
2181         //
2182         FirstOneOfOption = FALSE;
2183 
2184         // Prepare new DefaultValue
2185         //
2186         DefaultData.Type     = DefaultValueFromFlag;
2187         CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
2188         if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {
2189           DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
2190           InsertDefaultValue (BlockData, &DefaultData);
2191         }
2192         if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
2193           DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
2194           InsertDefaultValue (BlockData, &DefaultData);
2195         }
2196       }
2197 
2198       //
2199       // 2. Set as the default value when this is the first option.
2200       // The first oneof option value will be used as default value when no default value is specified.
2201       //
2202       if (FirstOneOfOption) {
2203         // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
2204         FirstOneOfOption = FALSE;
2205 
2206         //
2207         // Prepare new DefaultValue
2208         //
2209         DefaultData.Type     = DefaultValueFromDefault;
2210         CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
2211         for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2212           DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2213           DefaultData.DefaultId   = DefaultDataPtr->DefaultId;
2214           InsertDefaultValue (BlockData, &DefaultData);
2215         }
2216       }
2217       break;
2218 
2219     case EFI_IFR_DEFAULT_OP:
2220       //
2221       // Update Current BlockData to the default value.
2222       //
2223       if (BlockData == NULL || BlockData->Scope == 0) {
2224         //
2225         // No matched block data is ignored.
2226         //
2227         break;
2228       }
2229 
2230       //
2231       // Get the DefaultId
2232       //
2233       IfrDefault     = (EFI_IFR_DEFAULT *) IfrOpHdr;
2234       VarDefaultId   = IfrDefault->DefaultId;
2235       //
2236       // Prepare new DefaultValue
2237       //
2238       DefaultData.Type        = DefaultValueFromOpcode;
2239       DefaultData.DefaultId   = VarDefaultId;
2240       CopyMem (&DefaultData.Value, &IfrDefault->Value, IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value));
2241 
2242       // If the value field is expression, set the cleaned flag.
2243       if (IfrDefault->Type ==  EFI_IFR_TYPE_OTHER) {
2244         DefaultData.Cleaned = TRUE;
2245       }
2246       //
2247       // Add DefaultValue into current BlockData
2248       //
2249       InsertDefaultValue (BlockData, &DefaultData);
2250 
2251       //
2252       // After insert the default value, reset the cleaned value for next
2253       // time used. If not set here, need to set the value before everytime
2254       // use it.
2255       //
2256       DefaultData.Cleaned     = FALSE;
2257       break;
2258 
2259     case EFI_IFR_END_OP:
2260       //
2261       // End Opcode is for Var question.
2262       //
2263       if (BlockData != NULL) {
2264         if (BlockData->Scope > 0) {
2265           BlockData->Scope--;
2266         }
2267         if (BlockData->Scope == 0) {
2268           BlockData = NULL;
2269         }
2270       }
2271 
2272       break;
2273 
2274     default:
2275       if (BlockData != NULL) {
2276         if (BlockData->Scope > 0) {
2277           BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);
2278         }
2279 
2280         if (BlockData->Scope == 0) {
2281           BlockData = NULL;
2282         }
2283       }
2284       break;
2285     }
2286 
2287     IfrOffset     += IfrOpHdr->Length;
2288     PackageOffset += IfrOpHdr->Length;
2289   }
2290 
2291 Done:
2292   for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2293     BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2294     for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; ) {
2295       DefaultDataPtr = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2296       LinkDefault = LinkDefault->ForwardLink;
2297       if (DefaultDataPtr->Cleaned == TRUE) {
2298         RemoveEntryList (&DefaultDataPtr->Entry);
2299         FreePool (DefaultDataPtr);
2300       }
2301     }
2302   }
2303 
2304   return Status;
2305 }
2306 
2307 /**
2308   parse the configrequest string, get the elements.
2309 
2310   @param      ConfigRequest         The input configrequest string.
2311   @param      Progress              Return the progress data.
2312 
2313   @retval     Block data pointer.
2314 **/
2315 IFR_BLOCK_DATA *
GetBlockElement(IN EFI_STRING ConfigRequest,OUT EFI_STRING * Progress)2316 GetBlockElement (
2317   IN  EFI_STRING          ConfigRequest,
2318   OUT EFI_STRING          *Progress
2319   )
2320 {
2321   EFI_STRING           StringPtr;
2322   IFR_BLOCK_DATA       *BlockData;
2323   IFR_BLOCK_DATA       *RequestBlockArray;
2324   EFI_STATUS           Status;
2325   UINT8                *TmpBuffer;
2326   UINT16               Offset;
2327   UINT16               Width;
2328   LIST_ENTRY           *Link;
2329   IFR_BLOCK_DATA       *NextBlockData;
2330   UINTN                Length;
2331 
2332   TmpBuffer = NULL;
2333 
2334   //
2335   // Init RequestBlockArray
2336   //
2337   RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2338   if (RequestBlockArray == NULL) {
2339     goto Done;
2340   }
2341   InitializeListHead (&RequestBlockArray->Entry);
2342 
2343   //
2344   // Get the request Block array from the request string
2345   // Offset and Width
2346   //
2347 
2348   //
2349   // Parse each <RequestElement> if exists
2350   // Only <BlockName> format is supported by this help function.
2351   // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
2352   //
2353   StringPtr = ConfigRequest;
2354   while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
2355     //
2356     // Skip the OFFSET string
2357     //
2358     *Progress   = StringPtr;
2359     StringPtr += StrLen (L"&OFFSET=");
2360     //
2361     // Get Offset
2362     //
2363     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
2364     if (EFI_ERROR (Status)) {
2365       goto Done;
2366     }
2367     Offset = 0;
2368     CopyMem (
2369       &Offset,
2370       TmpBuffer,
2371       (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
2372       );
2373     FreePool (TmpBuffer);
2374 
2375     StringPtr += Length;
2376     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
2377       goto Done;
2378     }
2379     StringPtr += StrLen (L"&WIDTH=");
2380 
2381     //
2382     // Get Width
2383     //
2384     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
2385     if (EFI_ERROR (Status)) {
2386       goto Done;
2387     }
2388     Width = 0;
2389     CopyMem (
2390       &Width,
2391       TmpBuffer,
2392       (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
2393       );
2394     FreePool (TmpBuffer);
2395 
2396     StringPtr += Length;
2397     if (*StringPtr != 0 && *StringPtr != L'&') {
2398       goto Done;
2399     }
2400 
2401     //
2402     // Set Block Data
2403     //
2404     BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2405     if (BlockData == NULL) {
2406       goto Done;
2407     }
2408     BlockData->Offset = Offset;
2409     BlockData->Width  = Width;
2410     InsertBlockData (&RequestBlockArray->Entry, &BlockData);
2411 
2412     //
2413     // Skip &VALUE string if &VALUE does exists.
2414     //
2415     if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
2416       StringPtr += StrLen (L"&VALUE=");
2417 
2418       //
2419       // Get Value
2420       //
2421       Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
2422       if (EFI_ERROR (Status)) {
2423         goto Done;
2424       }
2425 
2426       StringPtr += Length;
2427       if (*StringPtr != 0 && *StringPtr != L'&') {
2428         goto Done;
2429       }
2430     }
2431     //
2432     // If '\0', parsing is finished.
2433     //
2434     if (*StringPtr == 0) {
2435       break;
2436     }
2437   }
2438 
2439   //
2440   // Merge the requested block data.
2441   //
2442   Link = RequestBlockArray->Entry.ForwardLink;
2443   while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
2444     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2445     NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
2446     if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
2447       if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
2448         BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
2449       }
2450       RemoveEntryList (Link->ForwardLink);
2451       FreePool (NextBlockData);
2452       continue;
2453     }
2454     Link = Link->ForwardLink;
2455   }
2456 
2457   return RequestBlockArray;
2458 
2459 Done:
2460   if (RequestBlockArray != NULL) {
2461     //
2462     // Free Link Array RequestBlockArray
2463     //
2464     while (!IsListEmpty (&RequestBlockArray->Entry)) {
2465       BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2466       RemoveEntryList (&BlockData->Entry);
2467       FreePool (BlockData);
2468     }
2469 
2470     FreePool (RequestBlockArray);
2471   }
2472 
2473   return NULL;
2474 }
2475 
2476 /**
2477   parse the configrequest string, get the elements.
2478 
2479   @param      ConfigRequest         The input config request string.
2480   @param      Progress              Return the progress data.
2481 
2482   @retval     return data block array.
2483 **/
2484 IFR_BLOCK_DATA *
GetNameElement(IN EFI_STRING ConfigRequest,OUT EFI_STRING * Progress)2485 GetNameElement (
2486   IN  EFI_STRING           ConfigRequest,
2487   OUT EFI_STRING           *Progress
2488   )
2489 {
2490   EFI_STRING           StringPtr;
2491   EFI_STRING           NextTag;
2492   IFR_BLOCK_DATA       *BlockData;
2493   IFR_BLOCK_DATA       *RequestBlockArray;
2494   BOOLEAN              HasValue;
2495 
2496   StringPtr = ConfigRequest;
2497 
2498   //
2499   // Init RequestBlockArray
2500   //
2501   RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2502   if (RequestBlockArray == NULL) {
2503     goto Done;
2504   }
2505   InitializeListHead (&RequestBlockArray->Entry);
2506 
2507   //
2508   // Get the request Block array from the request string
2509   //
2510 
2511   //
2512   // Parse each <RequestElement> if exists
2513   // Only <BlockName> format is supported by this help function.
2514   // <BlockName> ::= &'Name***=***
2515   //
2516   while (StringPtr != NULL && *StringPtr == L'&') {
2517 
2518     *Progress   = StringPtr;
2519     //
2520     // Skip the L"&" string
2521     //
2522     StringPtr += 1;
2523 
2524     HasValue = FALSE;
2525     if ((NextTag = StrStr (StringPtr, L"=")) != NULL) {
2526       *NextTag = L'\0';
2527       HasValue = TRUE;
2528     } else if ((NextTag = StrStr (StringPtr, L"&")) != NULL) {
2529       *NextTag = L'\0';
2530     }
2531 
2532     //
2533     // Set Block Data
2534     //
2535     BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2536     if (BlockData == NULL) {
2537       goto Done;
2538     }
2539 
2540     //
2541     // Get Name
2542     //
2543     BlockData->Name = AllocateCopyPool(StrSize (StringPtr), StringPtr);
2544     InsertBlockData (&RequestBlockArray->Entry, &BlockData);
2545 
2546     if (HasValue) {
2547       //
2548       // If has value, skip the value.
2549       //
2550       StringPtr = NextTag + 1;
2551       *NextTag  = L'=';
2552       StringPtr = StrStr (StringPtr, L"&");
2553     } else if (NextTag != NULL) {
2554       //
2555       // restore the '&' text.
2556       //
2557       StringPtr = NextTag;
2558       *NextTag  = L'&';
2559     }
2560   }
2561 
2562   return RequestBlockArray;
2563 
2564 Done:
2565   if (RequestBlockArray != NULL) {
2566     //
2567     // Free Link Array RequestBlockArray
2568     //
2569     while (!IsListEmpty (&RequestBlockArray->Entry)) {
2570       BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2571       RemoveEntryList (&BlockData->Entry);
2572       if (BlockData->Name != NULL) {
2573         FreePool (BlockData->Name);
2574       }
2575       FreePool (BlockData);
2576     }
2577 
2578     FreePool (RequestBlockArray);
2579   }
2580 
2581   return NULL;
2582 }
2583 
2584 /**
2585   Generate ConfigRequest string base on the varstore info.
2586 
2587   @param      ConfigHdr             The config header for this varstore.
2588   @param      VarStorageData        The varstore info.
2589   @param      Status                Return Status.
2590   @param      ConfigRequest         The ConfigRequest info may be return.
2591 
2592   @retval     TRUE                  Need to continue
2593   @retval     Others                NO need to continue or error occur.
2594 **/
2595 BOOLEAN
GenerateConfigRequest(IN CHAR16 * ConfigHdr,IN IFR_VARSTORAGE_DATA * VarStorageData,OUT EFI_STATUS * Status,IN OUT EFI_STRING * ConfigRequest)2596 GenerateConfigRequest (
2597   IN  CHAR16                       *ConfigHdr,
2598   IN  IFR_VARSTORAGE_DATA          *VarStorageData,
2599   OUT EFI_STATUS                   *Status,
2600   IN OUT EFI_STRING                *ConfigRequest
2601   )
2602 {
2603   BOOLEAN               DataExist;
2604   UINTN                 Length;
2605   LIST_ENTRY            *Link;
2606   CHAR16                *FullConfigRequest;
2607   CHAR16                *StringPtr;
2608   IFR_BLOCK_DATA        *BlockData;
2609 
2610   //
2611   // Append VarStorageData BlockEntry into *Request string
2612   // Now support only one varstore in a form package.
2613   //
2614 
2615   //
2616   // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
2617   // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
2618   //
2619 
2620   //
2621   // Compute the length of the entire request starting with <ConfigHdr> and a
2622   // Null-terminator
2623   //
2624   DataExist = FALSE;
2625   Length    = StrLen (ConfigHdr) + 1;
2626 
2627   for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
2628     DataExist = TRUE;
2629     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2630     if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2631       //
2632       // Add <BlockName> length for each Name
2633       //
2634       // <BlockName> ::= &Name1&Name2&...
2635       //                 |1| StrLen(Name1)
2636       //
2637       Length = Length + (1 + StrLen (BlockData->Name));
2638     } else {
2639       //
2640       // Add <BlockName> length for each Offset/Width pair
2641       //
2642       // <BlockName> ::= &OFFSET=1234&WIDTH=1234
2643       //                 |  8   | 4 |   7  | 4 |
2644       //
2645       Length = Length + (8 + 4 + 7 + 4);
2646     }
2647   }
2648   //
2649   // No any request block data is found. The request string can't be constructed.
2650   //
2651   if (!DataExist) {
2652     *Status = EFI_SUCCESS;
2653     return FALSE;
2654   }
2655 
2656   //
2657   // Allocate buffer for the entire <ConfigRequest>
2658   //
2659   FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
2660   if (FullConfigRequest == NULL) {
2661     *Status = EFI_OUT_OF_RESOURCES;
2662     return FALSE;
2663   }
2664   StringPtr = FullConfigRequest;
2665 
2666   //
2667   // Start with <ConfigHdr>
2668   //
2669   StrCpyS (StringPtr, Length, ConfigHdr);
2670   StringPtr += StrLen (StringPtr);
2671 
2672   //
2673   // Loop through all the Offset/Width pairs and append them to ConfigRequest
2674   //
2675   for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
2676     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2677     if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2678       //
2679       // Append &Name1\0
2680       //
2681       UnicodeSPrint (
2682         StringPtr,
2683         (1 + StrLen (BlockData->Name) + 1) * sizeof (CHAR16),
2684         L"&%s",
2685         BlockData->Name
2686       );
2687     } else {
2688       //
2689       // Append &OFFSET=XXXX&WIDTH=YYYY\0
2690       //
2691       UnicodeSPrint (
2692         StringPtr,
2693         (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
2694         L"&OFFSET=%04X&WIDTH=%04X",
2695         BlockData->Offset,
2696         BlockData->Width
2697       );
2698     }
2699     StringPtr += StrLen (StringPtr);
2700   }
2701   //
2702   // Set to the got full request string.
2703   //
2704   HiiToLower (FullConfigRequest);
2705 
2706   if (*ConfigRequest != NULL) {
2707     FreePool (*ConfigRequest);
2708   }
2709   *ConfigRequest = FullConfigRequest;
2710 
2711   return TRUE;
2712 }
2713 
2714 /**
2715   Generate ConfigRequest Header base on the varstore info.
2716 
2717   @param      VarStorageData        The varstore info.
2718   @param      DevicePath            Device path for this varstore.
2719   @param      ConfigHdr             The config header for this varstore.
2720 
2721   @retval     EFI_SUCCESS           Generate the header success.
2722   @retval     EFI_OUT_OF_RESOURCES  Allocate buffer fail.
2723 **/
2724 EFI_STATUS
GenerateHdr(IN IFR_VARSTORAGE_DATA * VarStorageData,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT EFI_STRING * ConfigHdr)2725 GenerateHdr (
2726   IN   IFR_VARSTORAGE_DATA          *VarStorageData,
2727   IN   EFI_DEVICE_PATH_PROTOCOL     *DevicePath,
2728   OUT  EFI_STRING                   *ConfigHdr
2729   )
2730 {
2731   EFI_STRING                   GuidStr;
2732   EFI_STRING                   NameStr;
2733   EFI_STRING                   PathStr;
2734   UINTN                        Length;
2735   EFI_STATUS                   Status;
2736 
2737   Status  = EFI_SUCCESS;
2738   NameStr = NULL;
2739   GuidStr = NULL;
2740   PathStr = NULL;
2741 
2742   //
2743   // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
2744   //
2745   GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);
2746   if (VarStorageData->Name != NULL) {
2747     GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);
2748   } else {
2749     GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
2750   }
2751   GenerateSubStr (
2752     L"PATH=",
2753     GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
2754     (VOID *) DevicePath,
2755     1,
2756     &PathStr
2757     );
2758   Length = StrLen (GuidStr) + StrLen (NameStr) + StrLen (PathStr) + 1;
2759   if (VarStorageData->Name == NULL) {
2760     Length += 1;
2761   }
2762 
2763   *ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
2764   if (*ConfigHdr == NULL) {
2765     Status = EFI_OUT_OF_RESOURCES;
2766     goto Done;
2767   }
2768   StrCpyS (*ConfigHdr, Length, GuidStr);
2769   StrCatS (*ConfigHdr, Length, NameStr);
2770   if (VarStorageData->Name == NULL) {
2771     StrCatS (*ConfigHdr, Length, L"&");
2772   }
2773   StrCatS (*ConfigHdr, Length, PathStr);
2774 
2775   //
2776   // Remove the last character L'&'
2777   //
2778   *(*ConfigHdr + StrLen (*ConfigHdr) - 1) = L'\0';
2779 
2780 Done:
2781   if (GuidStr != NULL) {
2782     FreePool (GuidStr);
2783   }
2784 
2785   if (NameStr != NULL) {
2786     FreePool (NameStr);
2787   }
2788 
2789   if (PathStr != NULL) {
2790     FreePool (PathStr);
2791   }
2792 
2793   return Status;
2794 }
2795 
2796 /**
2797   Get Data buffer size based on data type.
2798 
2799   @param      ValueType             The input data type.
2800 
2801   @retval     The data buffer size for the input type.
2802 **/
2803 UINT16
GetStorageWidth(IN UINT8 ValueType)2804 GetStorageWidth (
2805   IN UINT8       ValueType
2806   )
2807 {
2808   UINT16         StorageWidth;
2809 
2810   switch (ValueType) {
2811   case EFI_IFR_NUMERIC_SIZE_1:
2812   case EFI_IFR_TYPE_BOOLEAN:
2813     StorageWidth = (UINT16) sizeof (UINT8);
2814     break;
2815 
2816   case EFI_IFR_NUMERIC_SIZE_2:
2817     StorageWidth = (UINT16) sizeof (UINT16);
2818     break;
2819 
2820   case EFI_IFR_NUMERIC_SIZE_4:
2821     StorageWidth = (UINT16) sizeof (UINT32);
2822     break;
2823 
2824   case EFI_IFR_NUMERIC_SIZE_8:
2825     StorageWidth = (UINT16) sizeof (UINT64);
2826     break;
2827 
2828   case EFI_IFR_TYPE_TIME:
2829     StorageWidth = (UINT16) sizeof (EFI_IFR_TIME);
2830     break;
2831 
2832   case EFI_IFR_TYPE_DATE:
2833     StorageWidth = (UINT16) sizeof (EFI_IFR_DATE);
2834     break;
2835 
2836   default:
2837     StorageWidth = 0;
2838     break;
2839   }
2840 
2841   return StorageWidth;
2842 }
2843 
2844 /**
2845   Generate ConfigAltResp string base on the varstore info.
2846 
2847   @param      HiiHandle             Hii Handle for this hii package.
2848   @param      ConfigHdr             The config header for this varstore.
2849   @param      VarStorageData        The varstore info.
2850   @param      DefaultIdArray        The Default id array.
2851   @param      DefaultAltCfgResp     The DefaultAltCfgResp info may be return.
2852 
2853   @retval     TRUE                  Need to continue
2854   @retval     Others                NO need to continue or error occur.
2855 **/
2856 EFI_STATUS
GenerateAltConfigResp(IN EFI_HII_HANDLE HiiHandle,IN CHAR16 * ConfigHdr,IN IFR_VARSTORAGE_DATA * VarStorageData,IN IFR_DEFAULT_DATA * DefaultIdArray,IN OUT EFI_STRING * DefaultAltCfgResp)2857 GenerateAltConfigResp (
2858   IN  EFI_HII_HANDLE               HiiHandle,
2859   IN  CHAR16                       *ConfigHdr,
2860   IN  IFR_VARSTORAGE_DATA          *VarStorageData,
2861   IN  IFR_DEFAULT_DATA             *DefaultIdArray,
2862   IN OUT EFI_STRING                *DefaultAltCfgResp
2863   )
2864 {
2865   BOOLEAN               DataExist;
2866   UINTN                 Length;
2867   LIST_ENTRY            *Link;
2868   LIST_ENTRY            *LinkData;
2869   LIST_ENTRY            *LinkDefault;
2870   LIST_ENTRY            *ListEntry;
2871   CHAR16                *StringPtr;
2872   IFR_BLOCK_DATA        *BlockData;
2873   IFR_DEFAULT_DATA      *DefaultId;
2874   IFR_DEFAULT_DATA      *DefaultValueData;
2875   UINTN                 Width;
2876   UINT8                 *TmpBuffer;
2877   CHAR16                *DefaultString;
2878 
2879   BlockData     = NULL;
2880   DataExist     = FALSE;
2881   DefaultString = NULL;
2882   //
2883   // Add length for <ConfigHdr> + '\0'
2884   //
2885   Length = StrLen (ConfigHdr) + 1;
2886 
2887   for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2888     DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2889     //
2890     // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
2891     //                |1| StrLen (ConfigHdr) | 8 | 4 |
2892     //
2893     Length += (1 + StrLen (ConfigHdr) + 8 + 4);
2894 
2895     for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2896       BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2897       ListEntry     = &BlockData->DefaultValueEntry;
2898       for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
2899         DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2900         if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
2901           continue;
2902         }
2903         if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2904           //
2905           // Add length for "&Name1=zzzzzzzzzzzz"
2906           //                |1|Name|1|Value|
2907           //
2908           Length += (1 + StrLen (BlockData->Name) + 1 + BlockData->Width * 2);
2909         } else {
2910           //
2911           // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
2912           //                |    8  | 4 |   7  | 4 |   7  | Width * 2 |
2913           //
2914           Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
2915         }
2916         DataExist = TRUE;
2917       }
2918     }
2919   }
2920 
2921   //
2922   // No default value is found. The default string doesn't exist.
2923   //
2924   if (!DataExist) {
2925     return EFI_SUCCESS;
2926   }
2927 
2928   //
2929   // Allocate buffer for the entire <DefaultAltCfgResp>
2930   //
2931   *DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
2932   if (*DefaultAltCfgResp == NULL) {
2933     return EFI_OUT_OF_RESOURCES;
2934   }
2935   StringPtr = *DefaultAltCfgResp;
2936 
2937   //
2938   // Start with <ConfigHdr>
2939   //
2940   StrCpyS (StringPtr, Length, ConfigHdr);
2941   StringPtr += StrLen (StringPtr);
2942 
2943   for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2944     DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2945     //
2946     // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
2947     //                                |1| StrLen (ConfigHdr) | 8 | 4 |
2948     //
2949     UnicodeSPrint (
2950       StringPtr,
2951       (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
2952       L"&%s&ALTCFG=%04X",
2953       ConfigHdr,
2954       DefaultId->DefaultId
2955       );
2956     StringPtr += StrLen (StringPtr);
2957 
2958     for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2959       BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2960       ListEntry     = &BlockData->DefaultValueEntry;
2961       for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
2962         DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2963         if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
2964           continue;
2965         }
2966         if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2967           UnicodeSPrint (
2968             StringPtr,
2969             (1 + StrLen (ConfigHdr) + 1) * sizeof (CHAR16),
2970             L"&%s=",
2971             BlockData->Name
2972             );
2973           StringPtr += StrLen (StringPtr);
2974         } else {
2975           //
2976           // Add <BlockConfig>
2977           // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
2978           //
2979           UnicodeSPrint (
2980             StringPtr,
2981             (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
2982             L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
2983             BlockData->Offset,
2984             BlockData->Width
2985             );
2986           StringPtr += StrLen (StringPtr);
2987         }
2988         Width = BlockData->Width;
2989         //
2990         // Convert Value to a hex string in "%x" format
2991         // NOTE: This is in the opposite byte that GUID and PATH use
2992         //
2993         if (BlockData->OpCode == EFI_IFR_STRING_OP){
2994           DefaultString   = InternalGetString(HiiHandle, DefaultValueData->Value.string);
2995           TmpBuffer = (UINT8 *) DefaultString;
2996         } else {
2997           TmpBuffer = (UINT8 *) &(DefaultValueData->Value);
2998         }
2999         for (; Width > 0 && (TmpBuffer != NULL); Width--) {
3000           StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2);
3001         }
3002         if (DefaultString != NULL){
3003           FreePool(DefaultString);
3004           DefaultString = NULL;
3005         }
3006       }
3007     }
3008   }
3009 
3010   HiiToLower (*DefaultAltCfgResp);
3011 
3012   return EFI_SUCCESS;
3013 }
3014 
3015 /**
3016   This function gets the full request string and full default value string by
3017   parsing IFR data in HII form packages.
3018 
3019   When Request points to NULL string, the request string and default value string
3020   for each varstore in form package will return.
3021 
3022   @param  DataBaseRecord         The DataBaseRecord instance contains the found Hii handle and package.
3023   @param  DevicePath             Device Path which Hii Config Access Protocol is registered.
3024   @param  Request                Pointer to a null-terminated Unicode string in
3025                                  <ConfigRequest> format. When it doesn't contain
3026                                  any RequestElement, it will be updated to return
3027                                  the full RequestElement retrieved from IFR data.
3028                                  If it points to NULL, the request string for the first
3029                                  varstore in form package will be merged into a
3030                                  <MultiConfigRequest> format string and return.
3031   @param  AltCfgResp             Pointer to a null-terminated Unicode string in
3032                                  <ConfigAltResp> format. When the pointer is to NULL,
3033                                  the full default value string retrieved from IFR data
3034                                  will return. When the pinter is to a string, the
3035                                  full default value string retrieved from IFR data
3036                                  will be merged into the input string and return.
3037                                  When Request points to NULL, the default value string
3038                                  for each varstore in form package will be merged into
3039                                  a <MultiConfigAltResp> format string and return.
3040   @param  PointerProgress        Optional parameter, it can be be NULL.
3041                                  When it is not NULL, if Request is NULL, it returns NULL.
3042                                  On return, points to a character in the Request
3043                                  string. Points to the string's null terminator if
3044                                  request was successful. Points to the most recent
3045                                  & before the first failing name / value pair (or
3046                                  the beginning of the string if the failure is in
3047                                  the first name / value pair) if the request was
3048                                  not successful.
3049   @retval EFI_SUCCESS            The Results string is set to the full request string.
3050                                  And AltCfgResp contains all default value string.
3051   @retval EFI_OUT_OF_RESOURCES   Not enough memory for the return string.
3052   @retval EFI_NOT_FOUND          The varstore (Guid and Name) in Request string
3053                                  can't be found in Form package.
3054   @retval EFI_NOT_FOUND          HiiPackage can't be got on the input HiiHandle.
3055   @retval EFI_INVALID_PARAMETER  Request points to NULL.
3056 
3057 **/
3058 EFI_STATUS
3059 EFIAPI
GetFullStringFromHiiFormPackages(IN HII_DATABASE_RECORD * DataBaseRecord,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN OUT EFI_STRING * Request,IN OUT EFI_STRING * AltCfgResp,OUT EFI_STRING * PointerProgress OPTIONAL)3060 GetFullStringFromHiiFormPackages (
3061   IN     HII_DATABASE_RECORD        *DataBaseRecord,
3062   IN     EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
3063   IN OUT EFI_STRING                 *Request,
3064   IN OUT EFI_STRING                 *AltCfgResp,
3065   OUT    EFI_STRING                 *PointerProgress OPTIONAL
3066   )
3067 {
3068   EFI_STATUS                   Status;
3069   UINT8                        *HiiFormPackage;
3070   UINTN                        PackageSize;
3071   IFR_BLOCK_DATA               *RequestBlockArray;
3072   IFR_BLOCK_DATA               *BlockData;
3073   IFR_DEFAULT_DATA             *DefaultValueData;
3074   IFR_DEFAULT_DATA             *DefaultId;
3075   IFR_DEFAULT_DATA             *DefaultIdArray;
3076   IFR_VARSTORAGE_DATA          *VarStorageData;
3077   EFI_STRING                   DefaultAltCfgResp;
3078   EFI_STRING                   ConfigHdr;
3079   EFI_STRING                   StringPtr;
3080   EFI_STRING                   Progress;
3081 
3082   if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {
3083     return EFI_INVALID_PARAMETER;
3084   }
3085 
3086   //
3087   // Initialize the local variables.
3088   //
3089   RequestBlockArray = NULL;
3090   DefaultIdArray    = NULL;
3091   VarStorageData    = NULL;
3092   DefaultAltCfgResp = NULL;
3093   ConfigHdr         = NULL;
3094   HiiFormPackage    = NULL;
3095   PackageSize       = 0;
3096   Progress          = *Request;
3097 
3098   Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
3099   if (EFI_ERROR (Status)) {
3100     goto Done;
3101   }
3102 
3103   //
3104   // 1. Get the request block array by Request String when Request string containts the block array.
3105   //
3106   StringPtr = NULL;
3107   if (*Request != NULL) {
3108     StringPtr = *Request;
3109     //
3110     // Jump <ConfigHdr>
3111     //
3112     if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3113       Status   = EFI_INVALID_PARAMETER;
3114       goto Done;
3115     }
3116     StringPtr += StrLen (L"GUID=");
3117     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
3118       StringPtr++;
3119     }
3120     if (*StringPtr == L'\0') {
3121       Status = EFI_INVALID_PARAMETER;
3122       goto Done;
3123     }
3124     StringPtr += StrLen (L"&NAME=");
3125     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
3126       StringPtr++;
3127     }
3128     if (*StringPtr == L'\0') {
3129       Status = EFI_INVALID_PARAMETER;
3130       goto Done;
3131     }
3132     StringPtr += StrLen (L"&PATH=");
3133     while (*StringPtr != L'\0' && *StringPtr != L'&') {
3134       StringPtr ++;
3135     }
3136 
3137     if (*StringPtr == L'\0') {
3138       //
3139       // No request block is found.
3140       //
3141       StringPtr = NULL;
3142     }
3143   }
3144 
3145   //
3146   // If StringPtr != NULL, get the request elements.
3147   //
3148   if (StringPtr != NULL) {
3149     if (StrStr (StringPtr, L"&OFFSET=") != NULL) {
3150       RequestBlockArray = GetBlockElement(StringPtr, &Progress);
3151     } else {
3152       RequestBlockArray = GetNameElement(StringPtr, &Progress);
3153     }
3154 
3155     if (RequestBlockArray == NULL) {
3156       Status = EFI_INVALID_PARAMETER;
3157       goto Done;
3158     }
3159   }
3160 
3161   //
3162   // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
3163   //
3164   DefaultIdArray   = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
3165   if (DefaultIdArray == NULL) {
3166     Status = EFI_OUT_OF_RESOURCES;
3167     goto Done;
3168   }
3169   InitializeListHead (&DefaultIdArray->Entry);
3170 
3171   //
3172   // Initialize VarStorageData to store the var store Block and Default value information.
3173   //
3174   VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
3175   if (VarStorageData == NULL) {
3176     Status = EFI_OUT_OF_RESOURCES;
3177     goto Done;
3178   }
3179   InitializeListHead (&VarStorageData->Entry);
3180   InitializeListHead (&VarStorageData->BlockEntry);
3181 
3182   //
3183   // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
3184   //
3185 
3186   //
3187   // Parse the opcode in form pacakge to get the default setting.
3188   //
3189   Status = ParseIfrData (DataBaseRecord->Handle,
3190                          HiiFormPackage,
3191                          (UINT32) PackageSize,
3192                          *Request,
3193                          RequestBlockArray,
3194                          VarStorageData,
3195                          DefaultIdArray);
3196   if (EFI_ERROR (Status)) {
3197     goto Done;
3198   }
3199 
3200   //
3201   // No requested varstore in IFR data and directly return
3202   //
3203   if (VarStorageData->Type == 0 && VarStorageData->Name == NULL) {
3204     Status = EFI_SUCCESS;
3205     goto Done;
3206   }
3207 
3208   //
3209   // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
3210   //
3211   Status = GenerateHdr (VarStorageData, DevicePath, &ConfigHdr);
3212   if (EFI_ERROR (Status)) {
3213     goto Done;
3214   }
3215 
3216   if (RequestBlockArray == NULL) {
3217     if (!GenerateConfigRequest(ConfigHdr, VarStorageData, &Status, Request)) {
3218       goto Done;
3219     }
3220   }
3221 
3222   //
3223   // 4. Construct Default Value string in AltResp according to request element.
3224   // Go through all VarStorageData Entry and get the DefaultId array for each one
3225   // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
3226   //
3227   Status = GenerateAltConfigResp (DataBaseRecord->Handle,ConfigHdr, VarStorageData, DefaultIdArray, &DefaultAltCfgResp);
3228   if (EFI_ERROR (Status)) {
3229     goto Done;
3230   }
3231 
3232   //
3233   // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL.
3234   //
3235   if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {
3236     Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
3237     FreePool (DefaultAltCfgResp);
3238   } else if (*AltCfgResp == NULL) {
3239     *AltCfgResp = DefaultAltCfgResp;
3240   }
3241 
3242 Done:
3243   if (RequestBlockArray != NULL) {
3244     //
3245     // Free Link Array RequestBlockArray
3246     //
3247     while (!IsListEmpty (&RequestBlockArray->Entry)) {
3248       BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
3249       RemoveEntryList (&BlockData->Entry);
3250       if (BlockData->Name != NULL) {
3251         FreePool (BlockData->Name);
3252       }
3253       FreePool (BlockData);
3254     }
3255 
3256     FreePool (RequestBlockArray);
3257   }
3258 
3259   if (VarStorageData != NULL) {
3260     //
3261     // Free link array VarStorageData
3262     //
3263     while (!IsListEmpty (&VarStorageData->BlockEntry)) {
3264       BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
3265       RemoveEntryList (&BlockData->Entry);
3266       if (BlockData->Name != NULL) {
3267         FreePool (BlockData->Name);
3268       }
3269       //
3270       // Free default value link array
3271       //
3272       while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
3273         DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
3274         RemoveEntryList (&DefaultValueData->Entry);
3275         FreePool (DefaultValueData);
3276       }
3277       FreePool (BlockData);
3278     }
3279     FreePool (VarStorageData);
3280   }
3281 
3282   if (DefaultIdArray != NULL) {
3283     //
3284     // Free DefaultId Array
3285     //
3286     while (!IsListEmpty (&DefaultIdArray->Entry)) {
3287       DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
3288       RemoveEntryList (&DefaultId->Entry);
3289       FreePool (DefaultId);
3290     }
3291     FreePool (DefaultIdArray);
3292   }
3293 
3294   //
3295   // Free the allocated string
3296   //
3297   if (ConfigHdr != NULL) {
3298     FreePool (ConfigHdr);
3299   }
3300 
3301   //
3302   // Free Pacakge data
3303   //
3304   if (HiiFormPackage != NULL) {
3305     FreePool (HiiFormPackage);
3306   }
3307 
3308   if (PointerProgress != NULL) {
3309     if (*Request == NULL) {
3310       *PointerProgress = NULL;
3311     } else if (EFI_ERROR (Status)) {
3312       *PointerProgress = *Request;
3313     } else {
3314       *PointerProgress = *Request + StrLen (*Request);
3315     }
3316   }
3317 
3318   return Status;
3319 }
3320 
3321 /**
3322   This function gets the full request resp string by
3323   parsing IFR data in HII form packages.
3324 
3325   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3326                                  instance.
3327   @param  EfiVarStoreInfo        The efi varstore info which is save in the EFI
3328                                  varstore data structure.
3329   @param  Request                Pointer to a null-terminated Unicode string in
3330                                  <ConfigRequest> format.
3331   @param  RequestResp            Pointer to a null-terminated Unicode string in
3332                                  <ConfigResp> format.
3333   @param  AccessProgress         On return, points to a character in the Request
3334                                  string. Points to the string's null terminator if
3335                                  request was successful. Points to the most recent
3336                                  & before the first failing name / value pair (or
3337                                  the beginning of the string if the failure is in
3338                                  the first name / value pair) if the request was
3339                                  not successful.
3340 
3341   @retval EFI_SUCCESS            The Results string is set to the full request string.
3342                                  And AltCfgResp contains all default value string.
3343   @retval EFI_OUT_OF_RESOURCES   Not enough memory for the return string.
3344   @retval EFI_INVALID_PARAMETER  Request points to NULL.
3345 
3346 **/
3347 EFI_STATUS
GetConfigRespFromEfiVarStore(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN EFI_IFR_VARSTORE_EFI * EfiVarStoreInfo,IN EFI_STRING Request,OUT EFI_STRING * RequestResp,OUT EFI_STRING * AccessProgress)3348 GetConfigRespFromEfiVarStore (
3349   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,
3350   IN  EFI_IFR_VARSTORE_EFI                   *EfiVarStoreInfo,
3351   IN  EFI_STRING                             Request,
3352   OUT EFI_STRING                             *RequestResp,
3353   OUT EFI_STRING                             *AccessProgress
3354   )
3355 {
3356   EFI_STATUS Status;
3357   EFI_STRING VarStoreName;
3358   UINT8      *VarStore;
3359   UINTN      BufferSize;
3360 
3361   Status          = EFI_SUCCESS;
3362   BufferSize      = 0;
3363   VarStore        = NULL;
3364   VarStoreName    = NULL;
3365   *AccessProgress = Request;
3366 
3367   VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name) * sizeof (CHAR16));
3368   if (VarStoreName == NULL) {
3369     Status = EFI_OUT_OF_RESOURCES;
3370     goto Done;
3371   }
3372   AsciiStrToUnicodeStr ((CHAR8 *) EfiVarStoreInfo->Name, VarStoreName);
3373 
3374 
3375   Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
3376   if (Status != EFI_BUFFER_TOO_SMALL) {
3377     goto Done;
3378   }
3379 
3380   VarStore = AllocateZeroPool (BufferSize);
3381   ASSERT (VarStore != NULL);
3382   Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
3383   if (EFI_ERROR (Status)) {
3384     goto Done;
3385   }
3386 
3387   Status = HiiBlockToConfig(This, Request, VarStore, BufferSize, RequestResp, AccessProgress);
3388   if (EFI_ERROR (Status)) {
3389     goto Done;
3390   }
3391 
3392 Done:
3393   if (VarStoreName != NULL) {
3394     FreePool (VarStoreName);
3395   }
3396 
3397   if (VarStore != NULL) {
3398     FreePool (VarStore);
3399   }
3400 
3401   return Status;
3402 }
3403 
3404 
3405 /**
3406   This function route the full request resp string for efi varstore.
3407 
3408   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3409                                  instance.
3410   @param  EfiVarStoreInfo        The efi varstore info which is save in the EFI
3411                                  varstore data structure.
3412   @param  RequestResp            Pointer to a null-terminated Unicode string in
3413                                  <ConfigResp> format.
3414   @param  Result                 Pointer to a null-terminated Unicode string in
3415                                  <ConfigResp> format.
3416 
3417   @retval EFI_SUCCESS            The Results string is set to the full request string.
3418                                  And AltCfgResp contains all default value string.
3419   @retval EFI_OUT_OF_RESOURCES   Not enough memory for the return string.
3420   @retval EFI_INVALID_PARAMETER  Request points to NULL.
3421 
3422 **/
3423 EFI_STATUS
RouteConfigRespForEfiVarStore(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN EFI_IFR_VARSTORE_EFI * EfiVarStoreInfo,IN EFI_STRING RequestResp,OUT EFI_STRING * Result)3424 RouteConfigRespForEfiVarStore (
3425   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,
3426   IN  EFI_IFR_VARSTORE_EFI                   *EfiVarStoreInfo,
3427   IN  EFI_STRING                             RequestResp,
3428   OUT EFI_STRING                             *Result
3429   )
3430 {
3431   EFI_STATUS Status;
3432   EFI_STRING VarStoreName;
3433   UINT8      *VarStore;
3434   UINTN      BufferSize;
3435   UINTN      BlockSize;
3436 
3437   Status       = EFI_SUCCESS;
3438   BufferSize   = 0;
3439   VarStore     = NULL;
3440   VarStoreName = NULL;
3441 
3442   VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name) * sizeof (CHAR16));
3443   if (VarStoreName == NULL) {
3444     Status = EFI_OUT_OF_RESOURCES;
3445     goto Done;
3446   }
3447   AsciiStrToUnicodeStr ((CHAR8 *) EfiVarStoreInfo->Name, VarStoreName);
3448 
3449   Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
3450   if (Status != EFI_BUFFER_TOO_SMALL) {
3451     goto Done;
3452   }
3453 
3454   BlockSize = BufferSize;
3455   VarStore = AllocateZeroPool (BufferSize);
3456   ASSERT (VarStore != NULL);
3457   Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
3458   if (EFI_ERROR (Status)) {
3459     goto Done;
3460   }
3461 
3462   Status = HiiConfigToBlock(This, RequestResp, VarStore, &BlockSize, Result);
3463   if (EFI_ERROR (Status)) {
3464     goto Done;
3465   }
3466 
3467   Status = gRT->SetVariable (VarStoreName, &EfiVarStoreInfo->Guid, EfiVarStoreInfo->Attributes, BufferSize, VarStore);
3468   if (EFI_ERROR (Status)) {
3469     goto Done;
3470   }
3471 
3472 Done:
3473   if (VarStoreName != NULL) {
3474     FreePool (VarStoreName);
3475   }
3476 
3477   if (VarStore != NULL) {
3478     FreePool (VarStore);
3479   }
3480 
3481   return Status;
3482 }
3483 
3484 /**
3485   Validate the config request elements.
3486 
3487   @param  ConfigElements                A null-terminated Unicode string in <ConfigRequest> format,
3488                                         without configHdr field.
3489 
3490   @retval     CHAR16 *    THE first Name/value pair not correct.
3491   @retval     NULL        Success parse the name/value pair
3492 **/
3493 CHAR16 *
OffsetWidthValidate(CHAR16 * ConfigElements)3494 OffsetWidthValidate (
3495   CHAR16          *ConfigElements
3496   )
3497 {
3498   CHAR16    *StringPtr;
3499   CHAR16    *RetVal;
3500 
3501   StringPtr = ConfigElements;
3502 
3503   while (1) {
3504     RetVal    = StringPtr;
3505     if (StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
3506       return RetVal;
3507     }
3508 
3509     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3510       StringPtr++;
3511     }
3512     if (*StringPtr == L'\0') {
3513       return RetVal;
3514     }
3515 
3516     StringPtr += StrLen (L"&WIDTH=");
3517     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
3518       StringPtr ++;
3519     }
3520 
3521     if (*StringPtr == L'\0') {
3522       return NULL;
3523     }
3524   }
3525 }
3526 
3527 /**
3528   Validate the config request elements.
3529 
3530   @param  ConfigElements                A null-terminated Unicode string in <ConfigRequest> format,
3531                                         without configHdr field.
3532 
3533   @retval     CHAR16 *    THE first Name/value pair not correct.
3534   @retval     NULL        Success parse the name/value pair
3535 
3536 **/
3537 CHAR16 *
NameValueValidate(CHAR16 * ConfigElements)3538 NameValueValidate (
3539   CHAR16          *ConfigElements
3540   )
3541 {
3542   CHAR16    *StringPtr;
3543   CHAR16    *RetVal;
3544 
3545   StringPtr = ConfigElements;
3546 
3547   while (1) {
3548     RetVal = StringPtr;
3549     if (*StringPtr != L'&') {
3550       return RetVal;
3551     }
3552     StringPtr += 1;
3553 
3554     StringPtr = StrStr (StringPtr, L"&");
3555 
3556     if (StringPtr == NULL) {
3557       return NULL;
3558     }
3559   }
3560 }
3561 
3562 /**
3563   Validate the config request string.
3564 
3565   @param  ConfigRequest                A null-terminated Unicode string in <ConfigRequest> format.
3566 
3567   @retval     CHAR16 *    THE first element not correct.
3568   @retval     NULL        Success parse the name/value pair
3569 
3570 **/
3571 CHAR16 *
ConfigRequestValidate(CHAR16 * ConfigRequest)3572 ConfigRequestValidate (
3573   CHAR16          *ConfigRequest
3574   )
3575 {
3576   BOOLEAN            HasNameField;
3577   CHAR16             *StringPtr;
3578 
3579   HasNameField = TRUE;
3580   StringPtr    = ConfigRequest;
3581 
3582   //
3583   // Check <ConfigHdr>
3584   //
3585   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3586     return ConfigRequest;
3587   }
3588   StringPtr += StrLen (L"GUID=");
3589   while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
3590     StringPtr++;
3591   }
3592   if (*StringPtr == L'\0') {
3593     return ConfigRequest;
3594   }
3595   StringPtr += StrLen (L"&NAME=");
3596   if (*StringPtr == L'&') {
3597     HasNameField = FALSE;
3598   }
3599   while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
3600     StringPtr++;
3601   }
3602   if (*StringPtr == L'\0') {
3603     return ConfigRequest;
3604   }
3605   StringPtr += StrLen (L"&PATH=");
3606   while (*StringPtr != L'\0' && *StringPtr != L'&') {
3607     StringPtr ++;
3608   }
3609 
3610   if (*StringPtr == L'\0') {
3611     return NULL;
3612   }
3613 
3614   if (HasNameField) {
3615     //
3616     // Should be Buffer varstore, config request should be "OFFSET/Width" pairs.
3617     //
3618     return OffsetWidthValidate(StringPtr);
3619   } else {
3620     //
3621     // Should be Name/Value varstore, config request should be "&name1&name2..." pairs.
3622     //
3623     return NameValueValidate(StringPtr);
3624   }
3625 }
3626 
3627 /**
3628   This function allows a caller to extract the current configuration
3629   for one or more named elements from one or more drivers.
3630 
3631   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3632                                  instance.
3633   @param  Request                A null-terminated Unicode string in
3634                                  <MultiConfigRequest> format.
3635   @param  Progress               On return, points to a character in the Request
3636                                  string. Points to the string's null terminator if
3637                                  request was successful. Points to the most recent
3638                                  & before the first failing name / value pair (or
3639                                  the beginning of the string if the failure is in
3640                                  the first name / value pair) if the request was
3641                                  not successful.
3642   @param  Results                Null-terminated Unicode string in
3643                                  <MultiConfigAltResp> format which has all values
3644                                  filled in for the names in the Request string.
3645                                  String to be allocated by the called function.
3646 
3647   @retval EFI_SUCCESS            The Results string is filled with the values
3648                                  corresponding to all requested names.
3649   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the parts of the
3650                                  results that must be stored awaiting possible
3651                                  future        protocols.
3652   @retval EFI_NOT_FOUND          Routing data doesn't match any known driver.
3653                                    Progress set to the "G" in "GUID" of the routing
3654                                   header that doesn't match. Note: There is no
3655                                     requirement that all routing data be validated
3656                                  before any configuration extraction.
3657   @retval EFI_INVALID_PARAMETER  For example, passing in a NULL for the Request
3658                                  parameter would result in this type of error. The
3659                                  Progress parameter is set to NULL.
3660   @retval EFI_INVALID_PARAMETER  Illegal syntax. Progress set to most recent &
3661                                  before the error or the beginning of the string.
3662   @retval EFI_INVALID_PARAMETER  The ExtractConfig function of the underlying HII
3663                                  Configuration Access Protocol returned
3664                                  EFI_INVALID_PARAMETER. Progress set to most recent
3665                                  & before the error or the beginning of the string.
3666 
3667 **/
3668 EFI_STATUS
3669 EFIAPI
HiiConfigRoutingExtractConfig(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)3670 HiiConfigRoutingExtractConfig (
3671   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,
3672   IN  CONST EFI_STRING                       Request,
3673   OUT EFI_STRING                             *Progress,
3674   OUT EFI_STRING                             *Results
3675   )
3676 {
3677   HII_DATABASE_PRIVATE_DATA           *Private;
3678   EFI_STRING                          StringPtr;
3679   EFI_STRING                          ConfigRequest;
3680   UINTN                               Length;
3681   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
3682   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
3683   EFI_STATUS                          Status;
3684   LIST_ENTRY                          *Link;
3685   HII_DATABASE_RECORD                 *Database;
3686   UINT8                               *DevicePathPkg;
3687   UINT8                               *CurrentDevicePath;
3688   EFI_HANDLE                          DriverHandle;
3689   EFI_HII_HANDLE                      HiiHandle;
3690   EFI_HII_CONFIG_ACCESS_PROTOCOL      *ConfigAccess;
3691   EFI_STRING                          AccessProgress;
3692   EFI_STRING                          AccessResults;
3693   EFI_STRING                          DefaultResults;
3694   BOOLEAN                             FirstElement;
3695   BOOLEAN                             IfrDataParsedFlag;
3696   BOOLEAN                             IsEfiVarStore;
3697   EFI_IFR_VARSTORE_EFI                *EfiVarStoreInfo;
3698   EFI_STRING                          ErrorPtr;
3699   UINTN                               DevicePathSize;
3700 
3701   if (This == NULL || Progress == NULL || Results == NULL) {
3702     return EFI_INVALID_PARAMETER;
3703   }
3704 
3705   if (Request == NULL) {
3706     *Progress = NULL;
3707     return EFI_INVALID_PARAMETER;
3708   }
3709 
3710   Private   = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3711   StringPtr = Request;
3712   *Progress = StringPtr;
3713   DefaultResults = NULL;
3714   ConfigRequest  = NULL;
3715   Status         = EFI_SUCCESS;
3716   AccessResults  = NULL;
3717   AccessProgress = NULL;
3718   DevicePath     = NULL;
3719   IfrDataParsedFlag = FALSE;
3720   IsEfiVarStore     = FALSE;
3721   EfiVarStoreInfo   = NULL;
3722 
3723   //
3724   // The first element of <MultiConfigRequest> should be
3725   // <GuidHdr>, which is in 'GUID='<Guid> syntax.
3726   //
3727   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3728     return EFI_INVALID_PARAMETER;
3729   }
3730 
3731   FirstElement = TRUE;
3732 
3733   //
3734   // Allocate a fix length of memory to store Results. Reallocate memory for
3735   // Results if this fix length is insufficient.
3736   //
3737   *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
3738   if (*Results == NULL) {
3739     return EFI_OUT_OF_RESOURCES;
3740   }
3741 
3742   while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
3743     //
3744     // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
3745     // or most recent & before the error.
3746     //
3747     if (StringPtr == Request) {
3748       *Progress = StringPtr;
3749     } else {
3750       *Progress = StringPtr - 1;
3751     }
3752 
3753     //
3754     // Process each <ConfigRequest> of <MultiConfigRequest>
3755     //
3756     Length = CalculateConfigStringLen (StringPtr);
3757     ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
3758     if (ConfigRequest == NULL) {
3759       Status = EFI_OUT_OF_RESOURCES;
3760       goto Done;
3761     }
3762     *(ConfigRequest + Length) = 0;
3763 
3764     //
3765     // Get the UEFI device path
3766     //
3767     Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
3768     if (EFI_ERROR (Status)) {
3769       goto Done;
3770     }
3771 
3772     //
3773     // Find driver which matches the routing data.
3774     //
3775     DriverHandle     = NULL;
3776     HiiHandle        = NULL;
3777     Database         = NULL;
3778     for (Link = Private->DatabaseList.ForwardLink;
3779          Link != &Private->DatabaseList;
3780          Link = Link->ForwardLink
3781         ) {
3782       Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
3783       if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
3784         CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
3785         DevicePathSize    = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
3786         if ((CompareMem (DevicePath,CurrentDevicePath,DevicePathSize) == 0) && IsThisPackageList(Database, ConfigRequest)) {
3787           DriverHandle = Database->DriverHandle;
3788           HiiHandle    = Database->Handle;
3789           break;
3790         }
3791       }
3792     }
3793 
3794     //
3795     // Try to find driver handle by device path.
3796     //
3797     if (DriverHandle == NULL) {
3798       TempDevicePath = DevicePath;
3799       Status = gBS->LocateDevicePath (
3800                       &gEfiDevicePathProtocolGuid,
3801                       &TempDevicePath,
3802                       &DriverHandle
3803                       );
3804       if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
3805         //
3806         // Routing data does not match any known driver.
3807         // Set Progress to the 'G' in "GUID" of the routing header.
3808         //
3809         *Progress = StringPtr;
3810         Status = EFI_NOT_FOUND;
3811         goto Done;
3812       }
3813     }
3814 
3815     //
3816     // Validate ConfigRequest String.
3817     //
3818     ErrorPtr = ConfigRequestValidate(ConfigRequest);
3819     if (ErrorPtr != NULL) {
3820       *Progress = StrStr (StringPtr, ErrorPtr);
3821       Status = EFI_INVALID_PARAMETER;
3822       goto Done;
3823     }
3824 
3825     //
3826     // Check whether ConfigRequest contains request string.
3827     //
3828     IfrDataParsedFlag = FALSE;
3829     if ((HiiHandle != NULL) && !GetElementsFromRequest(ConfigRequest)) {
3830       //
3831       // Get the full request string from IFR when HiiPackage is registered to HiiHandle
3832       //
3833       IfrDataParsedFlag = TRUE;
3834       Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
3835       if (EFI_ERROR (Status)) {
3836         //
3837         // AccessProgress indicates the parsing progress on <ConfigRequest>.
3838         // Map it to the progress on <MultiConfigRequest> then return it.
3839         //
3840         ASSERT (AccessProgress != NULL);
3841         *Progress = StrStr (StringPtr, AccessProgress);
3842         goto Done;
3843       }
3844       //
3845       // Not any request block is found.
3846       //
3847       if (!GetElementsFromRequest(ConfigRequest)) {
3848         AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
3849         goto NextConfigString;
3850       }
3851     }
3852 
3853     //
3854     // Check whether this ConfigRequest is search from Efi varstore type storage.
3855     //
3856     Status = GetVarStoreType(Database, ConfigRequest, &IsEfiVarStore, &EfiVarStoreInfo);
3857     if (EFI_ERROR (Status)) {
3858       goto Done;
3859     }
3860 
3861     if (IsEfiVarStore) {
3862       //
3863       // Call the GetVariable function to extract settings.
3864       //
3865       Status = GetConfigRespFromEfiVarStore(This, EfiVarStoreInfo, ConfigRequest, &AccessResults, &AccessProgress);
3866       FreePool (EfiVarStoreInfo);
3867     } else {
3868       //
3869       // Call corresponding ConfigAccess protocol to extract settings
3870       //
3871       Status = gBS->HandleProtocol (
3872                       DriverHandle,
3873                       &gEfiHiiConfigAccessProtocolGuid,
3874                       (VOID **) &ConfigAccess
3875                       );
3876       if (EFI_ERROR (Status)) {
3877         goto Done;
3878       }
3879 
3880       Status = ConfigAccess->ExtractConfig (
3881                                ConfigAccess,
3882                                ConfigRequest,
3883                                &AccessProgress,
3884                                &AccessResults
3885                                );
3886     }
3887     if (EFI_ERROR (Status)) {
3888       //
3889       // AccessProgress indicates the parsing progress on <ConfigRequest>.
3890       // Map it to the progress on <MultiConfigRequest> then return it.
3891       //
3892       *Progress = StrStr (StringPtr, AccessProgress);
3893       goto Done;
3894     }
3895 
3896     //
3897     // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
3898     // which seperates the first <ConfigAltResp> and the following ones.
3899     //
3900     ASSERT (*AccessProgress == 0);
3901 
3902     //
3903     // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
3904     //
3905     if (!IfrDataParsedFlag && HiiHandle != NULL) {
3906       Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
3907       ASSERT_EFI_ERROR (Status);
3908     }
3909 
3910     FreePool (DevicePath);
3911     DevicePath = NULL;
3912 
3913     if (DefaultResults != NULL) {
3914       Status = MergeDefaultString (&AccessResults, DefaultResults);
3915       ASSERT_EFI_ERROR (Status);
3916       FreePool (DefaultResults);
3917       DefaultResults = NULL;
3918     }
3919 
3920 NextConfigString:
3921     if (!FirstElement) {
3922       Status = AppendToMultiString (Results, L"&");
3923       ASSERT_EFI_ERROR (Status);
3924     }
3925 
3926     Status = AppendToMultiString (Results, AccessResults);
3927     ASSERT_EFI_ERROR (Status);
3928 
3929     FirstElement = FALSE;
3930 
3931     FreePool (AccessResults);
3932     AccessResults = NULL;
3933     FreePool (ConfigRequest);
3934     ConfigRequest = NULL;
3935 
3936     //
3937     // Go to next <ConfigRequest> (skip '&').
3938     //
3939     StringPtr += Length;
3940     if (*StringPtr == 0) {
3941       *Progress = StringPtr;
3942       break;
3943     }
3944 
3945     StringPtr++;
3946   }
3947 
3948 Done:
3949   if (EFI_ERROR (Status)) {
3950     FreePool (*Results);
3951     *Results = NULL;
3952   }
3953 
3954   if (ConfigRequest != NULL) {
3955     FreePool (ConfigRequest);
3956   }
3957 
3958   if (AccessResults != NULL) {
3959     FreePool (AccessResults);
3960   }
3961 
3962   if (DefaultResults != NULL) {
3963     FreePool (DefaultResults);
3964   }
3965 
3966   if (DevicePath != NULL) {
3967     FreePool (DevicePath);
3968   }
3969 
3970   return Status;
3971 }
3972 
3973 
3974 /**
3975   This function allows the caller to request the current configuration for the
3976   entirety of the current HII database and returns the data in a
3977   null-terminated Unicode string.
3978 
3979   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3980                                  instance.
3981   @param  Results                Null-terminated Unicode string in
3982                                  <MultiConfigAltResp> format which has all values
3983                                  filled in for the entirety of the current HII
3984                                  database. String to be allocated by the  called
3985                                  function. De-allocation is up to the caller.
3986 
3987   @retval EFI_SUCCESS            The Results string is filled with the values
3988                                  corresponding to all requested names.
3989   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the parts of the
3990                                  results that must be stored awaiting possible
3991                                  future        protocols.
3992   @retval EFI_INVALID_PARAMETER  For example, passing in a NULL for the Results
3993                                  parameter would result in this type of error.
3994 
3995 **/
3996 EFI_STATUS
3997 EFIAPI
HiiConfigRoutingExportConfig(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,OUT EFI_STRING * Results)3998 HiiConfigRoutingExportConfig (
3999   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,
4000   OUT EFI_STRING                             *Results
4001   )
4002 {
4003   EFI_STATUS                          Status;
4004   EFI_HII_CONFIG_ACCESS_PROTOCOL      *ConfigAccess;
4005   EFI_STRING                          AccessResults;
4006   EFI_STRING                          Progress;
4007   EFI_STRING                          StringPtr;
4008   EFI_STRING                          ConfigRequest;
4009   UINTN                               Index;
4010   EFI_HANDLE                          *ConfigAccessHandles;
4011   UINTN                               NumberConfigAccessHandles;
4012   BOOLEAN                             FirstElement;
4013   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
4014   EFI_HII_HANDLE                      HiiHandle;
4015   EFI_STRING                          DefaultResults;
4016   HII_DATABASE_PRIVATE_DATA           *Private;
4017   LIST_ENTRY                          *Link;
4018   HII_DATABASE_RECORD                 *Database;
4019   UINT8                               *DevicePathPkg;
4020   UINT8                               *CurrentDevicePath;
4021   BOOLEAN                             IfrDataParsedFlag;
4022 
4023   if (This == NULL || Results == NULL) {
4024     return EFI_INVALID_PARAMETER;
4025   }
4026 
4027   Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4028 
4029   //
4030   // Allocate a fix length of memory to store Results. Reallocate memory for
4031   // Results if this fix length is insufficient.
4032   //
4033   *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
4034   if (*Results == NULL) {
4035     return EFI_OUT_OF_RESOURCES;
4036   }
4037 
4038   NumberConfigAccessHandles = 0;
4039   Status = gBS->LocateHandleBuffer (
4040              ByProtocol,
4041              &gEfiHiiConfigAccessProtocolGuid,
4042              NULL,
4043              &NumberConfigAccessHandles,
4044              &ConfigAccessHandles
4045              );
4046   if (EFI_ERROR (Status)) {
4047     return Status;
4048   }
4049 
4050   FirstElement = TRUE;
4051 
4052   for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
4053     Status = gBS->HandleProtocol (
4054                     ConfigAccessHandles[Index],
4055                     &gEfiHiiConfigAccessProtocolGuid,
4056                     (VOID **) &ConfigAccess
4057                     );
4058     if (EFI_ERROR (Status)) {
4059       continue;
4060     }
4061 
4062     //
4063     // Get DevicePath and HiiHandle for this ConfigAccess driver handle
4064     //
4065     IfrDataParsedFlag = FALSE;
4066     Progress         = NULL;
4067     HiiHandle        = NULL;
4068     DefaultResults   = NULL;
4069     Database         = NULL;
4070     ConfigRequest    = NULL;
4071     DevicePath       = DevicePathFromHandle (ConfigAccessHandles[Index]);
4072     if (DevicePath != NULL) {
4073       for (Link = Private->DatabaseList.ForwardLink;
4074            Link != &Private->DatabaseList;
4075            Link = Link->ForwardLink
4076           ) {
4077         Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
4078         if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
4079           CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
4080           if (CompareMem (
4081                 DevicePath,
4082                 CurrentDevicePath,
4083                 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
4084                 ) == 0) {
4085             HiiHandle = Database->Handle;
4086             break;
4087           }
4088         }
4089       }
4090     }
4091 
4092     Status = ConfigAccess->ExtractConfig (
4093                              ConfigAccess,
4094                              NULL,
4095                              &Progress,
4096                              &AccessResults
4097                              );
4098     if (EFI_ERROR (Status)) {
4099       //
4100       // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
4101       //
4102       if (HiiHandle != NULL && DevicePath != NULL) {
4103         IfrDataParsedFlag = TRUE;
4104         Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
4105         //
4106         // Get the full request string to get the Current setting again.
4107         //
4108         if (!EFI_ERROR (Status) && ConfigRequest != NULL) {
4109           Status = ConfigAccess->ExtractConfig (
4110                                    ConfigAccess,
4111                                    ConfigRequest,
4112                                    &Progress,
4113                                    &AccessResults
4114                                    );
4115           FreePool (ConfigRequest);
4116         } else {
4117           Status = EFI_NOT_FOUND;
4118         }
4119       }
4120     }
4121 
4122     if (!EFI_ERROR (Status)) {
4123       //
4124       // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
4125       //
4126       if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {
4127         StringPtr = StrStr (AccessResults, L"&GUID=");
4128         if (StringPtr != NULL) {
4129           *StringPtr = 0;
4130         }
4131         if (GetElementsFromRequest (AccessResults)) {
4132           Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
4133           ASSERT_EFI_ERROR (Status);
4134         }
4135         if (StringPtr != NULL) {
4136           *StringPtr = L'&';
4137         }
4138       }
4139       //
4140       // Merge the default sting from IFR code into the got setting from driver.
4141       //
4142       if (DefaultResults != NULL) {
4143         Status = MergeDefaultString (&AccessResults, DefaultResults);
4144         ASSERT_EFI_ERROR (Status);
4145         FreePool (DefaultResults);
4146         DefaultResults = NULL;
4147       }
4148 
4149       //
4150       // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
4151       // which seperates the first <ConfigAltResp> and the following ones.
4152       //
4153       if (!FirstElement) {
4154         Status = AppendToMultiString (Results, L"&");
4155         ASSERT_EFI_ERROR (Status);
4156       }
4157 
4158       Status = AppendToMultiString (Results, AccessResults);
4159       ASSERT_EFI_ERROR (Status);
4160 
4161       FirstElement = FALSE;
4162 
4163       FreePool (AccessResults);
4164       AccessResults = NULL;
4165     }
4166   }
4167   FreePool (ConfigAccessHandles);
4168 
4169   return EFI_SUCCESS;
4170 }
4171 
4172 
4173 /**
4174   This function processes the results of processing forms and routes it to the
4175   appropriate handlers or storage.
4176 
4177   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4178                                  instance.
4179   @param  Configuration          A null-terminated Unicode string in
4180                                  <MulltiConfigResp> format.
4181   @param  Progress               A pointer to a string filled in with the offset of
4182                                  the most recent & before the first failing name /
4183                                  value pair (or the beginning of the string if the
4184                                  failure is in the first name / value pair) or the
4185                                  terminating NULL if all was successful.
4186 
4187   @retval EFI_SUCCESS            The results have been distributed or are awaiting
4188                                  distribution.
4189   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the parts of the
4190                                  results that must be stored awaiting possible
4191                                  future        protocols.
4192   @retval EFI_INVALID_PARAMETER  Passing in a NULL for the Configuration parameter
4193                                  would result in this type of error.
4194   @retval EFI_NOT_FOUND          Target for the specified routing data was not
4195                                  found.
4196 
4197 **/
4198 EFI_STATUS
4199 EFIAPI
HiiConfigRoutingRouteConfig(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)4200 HiiConfigRoutingRouteConfig (
4201   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,
4202   IN  CONST EFI_STRING                       Configuration,
4203   OUT EFI_STRING                             *Progress
4204   )
4205 {
4206   HII_DATABASE_PRIVATE_DATA           *Private;
4207   EFI_STRING                          StringPtr;
4208   EFI_STRING                          ConfigResp;
4209   UINTN                               Length;
4210   EFI_STATUS                          Status;
4211   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
4212   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
4213   LIST_ENTRY                          *Link;
4214   HII_DATABASE_RECORD                 *Database;
4215   UINT8                               *DevicePathPkg;
4216   UINT8                               *CurrentDevicePath;
4217   EFI_HANDLE                          DriverHandle;
4218   EFI_HII_CONFIG_ACCESS_PROTOCOL      *ConfigAccess;
4219   EFI_STRING                          AccessProgress;
4220   EFI_IFR_VARSTORE_EFI                *EfiVarStoreInfo;
4221   BOOLEAN                             IsEfiVarstore;
4222   UINTN                               DevicePathSize;
4223 
4224   if (This == NULL || Progress == NULL) {
4225     return EFI_INVALID_PARAMETER;
4226   }
4227 
4228   if (Configuration == NULL) {
4229     *Progress = NULL;
4230     return EFI_INVALID_PARAMETER;
4231   }
4232 
4233   Private   = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4234   StringPtr = Configuration;
4235   *Progress = StringPtr;
4236   Database       = NULL;
4237   AccessProgress = NULL;
4238   EfiVarStoreInfo= NULL;
4239   IsEfiVarstore  = FALSE;
4240 
4241   //
4242   // The first element of <MultiConfigResp> should be
4243   // <GuidHdr>, which is in 'GUID='<Guid> syntax.
4244   //
4245   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4246     return EFI_INVALID_PARAMETER;
4247   }
4248 
4249   while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
4250     //
4251     // If parsing error, set Progress to the beginning of the <MultiConfigResp>
4252     // or most recent & before the error.
4253     //
4254     if (StringPtr == Configuration) {
4255       *Progress = StringPtr;
4256     } else {
4257       *Progress = StringPtr - 1;
4258     }
4259 
4260     //
4261     // Process each <ConfigResp> of <MultiConfigResp>
4262     //
4263     Length = CalculateConfigStringLen (StringPtr);
4264     ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
4265     if (ConfigResp == NULL) {
4266       return EFI_OUT_OF_RESOURCES;
4267     }
4268     //
4269     // Append '\0' to the end of ConfigRequest
4270     //
4271     *(ConfigResp + Length) = 0;
4272 
4273     //
4274     // Get the UEFI device path
4275     //
4276     Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
4277     if (EFI_ERROR (Status)) {
4278       FreePool (ConfigResp);
4279       return Status;
4280     }
4281 
4282     //
4283     // Find driver which matches the routing data.
4284     //
4285     DriverHandle     = NULL;
4286     for (Link = Private->DatabaseList.ForwardLink;
4287          Link != &Private->DatabaseList;
4288          Link = Link->ForwardLink
4289         ) {
4290       Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
4291 
4292       if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
4293         CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
4294         DevicePathSize    = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
4295         if ((CompareMem (DevicePath,CurrentDevicePath,DevicePathSize) == 0) && IsThisPackageList(Database, ConfigResp)) {
4296           DriverHandle = Database->DriverHandle;
4297           break;
4298         }
4299       }
4300     }
4301 
4302     //
4303     // Try to find driver handle by device path.
4304     //
4305     if (DriverHandle == NULL) {
4306       TempDevicePath = DevicePath;
4307       Status = gBS->LocateDevicePath (
4308                       &gEfiDevicePathProtocolGuid,
4309                       &TempDevicePath,
4310                       &DriverHandle
4311                       );
4312       if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
4313         //
4314         // Routing data does not match any known driver.
4315         // Set Progress to the 'G' in "GUID" of the routing header.
4316         //
4317         FreePool (DevicePath);
4318         *Progress = StringPtr;
4319         FreePool (ConfigResp);
4320         return EFI_NOT_FOUND;
4321       }
4322     }
4323 
4324     FreePool (DevicePath);
4325 
4326     //
4327     // Check whether this ConfigRequest is search from Efi varstore type storage.
4328     //
4329     Status = GetVarStoreType(Database, ConfigResp, &IsEfiVarstore, &EfiVarStoreInfo);
4330     if (EFI_ERROR (Status)) {
4331       return Status;
4332     }
4333 
4334     if (IsEfiVarstore) {
4335       //
4336       // Call the SetVariable function to route settings.
4337       //
4338       Status = RouteConfigRespForEfiVarStore(This, EfiVarStoreInfo, ConfigResp, &AccessProgress);
4339       FreePool (EfiVarStoreInfo);
4340     } else {
4341       //
4342       // Call corresponding ConfigAccess protocol to route settings
4343       //
4344       Status = gBS->HandleProtocol (
4345                       DriverHandle,
4346                       &gEfiHiiConfigAccessProtocolGuid,
4347                       (VOID **)  &ConfigAccess
4348                       );
4349       if (EFI_ERROR (Status)) {
4350         *Progress = StringPtr;
4351         FreePool (ConfigResp);
4352         return EFI_NOT_FOUND;
4353       }
4354 
4355       Status = ConfigAccess->RouteConfig (
4356                                ConfigAccess,
4357                                ConfigResp,
4358                                &AccessProgress
4359                                );
4360     }
4361     if (EFI_ERROR (Status)) {
4362       ASSERT (AccessProgress != NULL);
4363       //
4364       // AccessProgress indicates the parsing progress on <ConfigResp>.
4365       // Map it to the progress on <MultiConfigResp> then return it.
4366       //
4367       *Progress = StrStr (StringPtr, AccessProgress);
4368 
4369       FreePool (ConfigResp);
4370       return Status;
4371     }
4372 
4373     FreePool (ConfigResp);
4374     ConfigResp = NULL;
4375 
4376     //
4377     // Go to next <ConfigResp> (skip '&').
4378     //
4379     StringPtr += Length;
4380     if (*StringPtr == 0) {
4381       *Progress = StringPtr;
4382       break;
4383     }
4384 
4385     StringPtr++;
4386 
4387   }
4388 
4389   return EFI_SUCCESS;
4390 }
4391 
4392 
4393 /**
4394   This helper function is to be called by drivers to map configuration data
4395   stored in byte array ("block") formats such as UEFI Variables into current
4396   configuration strings.
4397 
4398   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4399                                  instance.
4400   @param  ConfigRequest          A null-terminated Unicode string in
4401                                  <ConfigRequest> format.
4402   @param  Block                  Array of bytes defining the block's configuration.
4403   @param  BlockSize              Length in bytes of Block.
4404   @param  Config                 Filled-in configuration string. String allocated
4405                                  by  the function. Returned only if call is
4406                                  successful. It is <ConfigResp> string format.
4407   @param  Progress               A pointer to a string filled in with the offset of
4408                                   the most recent & before the first failing
4409                                  name/value pair (or the beginning of the string if
4410                                  the failure is in the first name / value pair) or
4411                                  the terminating NULL if all was successful.
4412 
4413   @retval EFI_SUCCESS            The request succeeded. Progress points to the null
4414                                  terminator at the end of the ConfigRequest
4415                                  string.
4416   @retval EFI_OUT_OF_RESOURCES   Not enough memory to allocate Config.     Progress
4417                                  points to the first character of ConfigRequest.
4418   @retval EFI_INVALID_PARAMETER  Passing in a NULL for the ConfigRequest or
4419                                  Block parameter would result in this type of
4420                                  error. Progress points to the first character of
4421                                  ConfigRequest.
4422   @retval EFI_DEVICE_ERROR       Block not large enough. Progress undefined.
4423   @retval EFI_INVALID_PARAMETER  Encountered non <BlockName> formatted string.
4424                                      Block is left updated and Progress points at
4425                                  the "&" preceding the first non-<BlockName>.
4426 
4427 **/
4428 EFI_STATUS
4429 EFIAPI
HiiBlockToConfig(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN CONST EFI_STRING ConfigRequest,IN CONST UINT8 * Block,IN CONST UINTN BlockSize,OUT EFI_STRING * Config,OUT EFI_STRING * Progress)4430 HiiBlockToConfig (
4431   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL  *This,
4432   IN  CONST EFI_STRING                       ConfigRequest,
4433   IN  CONST UINT8                            *Block,
4434   IN  CONST UINTN                            BlockSize,
4435   OUT EFI_STRING                             *Config,
4436   OUT EFI_STRING                             *Progress
4437   )
4438 {
4439   HII_DATABASE_PRIVATE_DATA           *Private;
4440   EFI_STRING                          StringPtr;
4441   UINTN                               Length;
4442   EFI_STATUS                          Status;
4443   EFI_STRING                          TmpPtr;
4444   UINT8                               *TmpBuffer;
4445   UINTN                               Offset;
4446   UINTN                               Width;
4447   UINT8                               *Value;
4448   EFI_STRING                          ValueStr;
4449   EFI_STRING                          ConfigElement;
4450   UINTN                               Index;
4451   UINT8                               *TemBuffer;
4452   CHAR16                              *TemString;
4453   CHAR16                              TemChar;
4454 
4455   TmpBuffer = NULL;
4456 
4457   if (This == NULL || Progress == NULL || Config == NULL) {
4458     return EFI_INVALID_PARAMETER;
4459   }
4460 
4461   if (Block == NULL || ConfigRequest == NULL) {
4462     *Progress = ConfigRequest;
4463     return EFI_INVALID_PARAMETER;
4464   }
4465 
4466 
4467   Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4468   ASSERT (Private != NULL);
4469 
4470   StringPtr     = ConfigRequest;
4471   ValueStr      = NULL;
4472   Value         = NULL;
4473   ConfigElement = NULL;
4474 
4475   //
4476   // Allocate a fix length of memory to store Results. Reallocate memory for
4477   // Results if this fix length is insufficient.
4478   //
4479   *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
4480   if (*Config == NULL) {
4481     return EFI_OUT_OF_RESOURCES;
4482   }
4483 
4484   //
4485   // Jump <ConfigHdr>
4486   //
4487   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4488     *Progress = StringPtr;
4489     Status = EFI_INVALID_PARAMETER;
4490     goto Exit;
4491   }
4492   while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
4493     StringPtr++;
4494   }
4495   if (*StringPtr == 0) {
4496     *Progress = StringPtr - 1;
4497     Status = EFI_INVALID_PARAMETER;
4498     goto Exit;
4499   }
4500 
4501   while (*StringPtr != L'&' && *StringPtr != 0) {
4502     StringPtr++;
4503   }
4504   if (*StringPtr == 0) {
4505     *Progress = StringPtr;
4506 
4507     AppendToMultiString(Config, ConfigRequest);
4508     HiiToLower (*Config);
4509 
4510     return EFI_SUCCESS;
4511   }
4512   //
4513   // Skip '&'
4514   //
4515   StringPtr++;
4516 
4517   //
4518   // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
4519   //
4520   TemChar = *StringPtr;
4521   *StringPtr = '\0';
4522   AppendToMultiString(Config, ConfigRequest);
4523   *StringPtr = TemChar;
4524 
4525   //
4526   // Parse each <RequestElement> if exists
4527   // Only <BlockName> format is supported by this help function.
4528   // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
4529   //
4530   while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
4531     //
4532     // Back up the header of one <BlockName>
4533     //
4534     TmpPtr = StringPtr;
4535 
4536     StringPtr += StrLen (L"OFFSET=");
4537     //
4538     // Get Offset
4539     //
4540     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4541     if (EFI_ERROR (Status)) {
4542       *Progress = TmpPtr - 1;
4543       goto Exit;
4544     }
4545     Offset = 0;
4546     CopyMem (
4547       &Offset,
4548       TmpBuffer,
4549       (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4550       );
4551     FreePool (TmpBuffer);
4552 
4553     StringPtr += Length;
4554     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
4555       *Progress = TmpPtr - 1;
4556       Status = EFI_INVALID_PARAMETER;
4557       goto Exit;
4558     }
4559     StringPtr += StrLen (L"&WIDTH=");
4560 
4561     //
4562     // Get Width
4563     //
4564     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4565     if (EFI_ERROR (Status)) {
4566       *Progress =  TmpPtr - 1;
4567       goto Exit;
4568     }
4569     Width = 0;
4570     CopyMem (
4571       &Width,
4572       TmpBuffer,
4573       (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4574       );
4575     FreePool (TmpBuffer);
4576 
4577     StringPtr += Length;
4578     if (*StringPtr != 0 && *StringPtr != L'&') {
4579       *Progress =  TmpPtr - 1;
4580       Status = EFI_INVALID_PARAMETER;
4581       goto Exit;
4582     }
4583 
4584     //
4585     // Calculate Value and convert it to hex string.
4586     //
4587     if (Offset + Width > BlockSize) {
4588       *Progress = StringPtr;
4589       Status = EFI_DEVICE_ERROR;
4590       goto Exit;
4591     }
4592 
4593     Value = (UINT8 *) AllocateZeroPool (Width);
4594     if (Value == NULL) {
4595       *Progress = ConfigRequest;
4596       Status = EFI_OUT_OF_RESOURCES;
4597       goto Exit;
4598     }
4599 
4600     CopyMem (Value, (UINT8 *) Block + Offset, Width);
4601 
4602     Length = Width * 2 + 1;
4603     ValueStr = (EFI_STRING) AllocateZeroPool (Length  * sizeof (CHAR16));
4604     if (ValueStr == NULL) {
4605       *Progress = ConfigRequest;
4606       Status = EFI_OUT_OF_RESOURCES;
4607       goto Exit;
4608     }
4609 
4610     TemString = ValueStr;
4611     TemBuffer = Value + Width - 1;
4612     for (Index = 0; Index < Width; Index ++, TemBuffer --) {
4613       TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
4614     }
4615 
4616     FreePool (Value);
4617     Value = NULL;
4618 
4619     //
4620     // Build a ConfigElement
4621     //
4622     Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
4623     ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
4624     if (ConfigElement == NULL) {
4625       Status = EFI_OUT_OF_RESOURCES;
4626       goto Exit;
4627     }
4628     CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
4629     if (*StringPtr == 0) {
4630       *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
4631     }
4632     *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
4633     StrCatS (ConfigElement, Length, L"VALUE=");
4634     StrCatS (ConfigElement, Length, ValueStr);
4635 
4636     AppendToMultiString (Config, ConfigElement);
4637 
4638     FreePool (ConfigElement);
4639     FreePool (ValueStr);
4640     ConfigElement = NULL;
4641     ValueStr = NULL;
4642 
4643     //
4644     // If '\0', parsing is finished. Otherwise skip '&' to continue
4645     //
4646     if (*StringPtr == 0) {
4647       break;
4648     }
4649     AppendToMultiString (Config, L"&");
4650     StringPtr++;
4651 
4652   }
4653 
4654   if (*StringPtr != 0) {
4655     *Progress = StringPtr - 1;
4656     Status = EFI_INVALID_PARAMETER;
4657     goto Exit;
4658   }
4659 
4660   HiiToLower (*Config);
4661   *Progress = StringPtr;
4662   return EFI_SUCCESS;
4663 
4664 Exit:
4665   if (*Config != NULL) {
4666   FreePool (*Config);
4667   *Config = NULL;
4668   }
4669   if (ValueStr != NULL) {
4670     FreePool (ValueStr);
4671   }
4672   if (Value != NULL) {
4673     FreePool (Value);
4674   }
4675   if (ConfigElement != NULL) {
4676     FreePool (ConfigElement);
4677   }
4678 
4679   return Status;
4680 
4681 }
4682 
4683 
4684 /**
4685   This helper function is to be called by drivers to map configuration strings
4686   to configurations stored in byte array ("block") formats such as UEFI Variables.
4687 
4688   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4689                                  instance.
4690   @param  ConfigResp             A null-terminated Unicode string in <ConfigResp>
4691                                  format.
4692   @param  Block                  A possibly null array of bytes representing the
4693                                  current  block. Only bytes referenced in the
4694                                  ConfigResp string  in the block are modified. If
4695                                  this parameter is null or if the *BlockSize
4696                                  parameter is (on input) shorter than required by
4697                                  the Configuration string, only the BlockSize
4698                                  parameter is updated and an appropriate status
4699                                  (see below)  is returned.
4700   @param  BlockSize              The length of the Block in units of UINT8.  On
4701                                  input, this is the size of the Block. On output,
4702                                  if successful, contains the largest index of the
4703                                  modified byte in the Block, or the required buffer
4704                                  size if the Block is not large enough.
4705   @param  Progress               On return, points to an element of the ConfigResp
4706                                  string filled in with the offset of the most
4707                                  recent '&' before the first failing name / value
4708                                  pair (or  the beginning of the string if the
4709                                  failure is in the  first name / value pair) or the
4710                                  terminating NULL if all was successful.
4711 
4712   @retval EFI_SUCCESS            The request succeeded. Progress points to the null
4713                                  terminator at the end of the ConfigResp string.
4714   @retval EFI_OUT_OF_RESOURCES   Not enough memory to allocate Config.     Progress
4715                                  points to the first character of ConfigResp.
4716   @retval EFI_INVALID_PARAMETER  Passing in a NULL for the ConfigResp or
4717                                  Block parameter would result in this type of
4718                                  error. Progress points to the first character of
4719                                          ConfigResp.
4720   @retval EFI_INVALID_PARAMETER  Encountered non <BlockName> formatted name /
4721                                  value pair. Block is left updated and
4722                                  Progress points at the '&' preceding the first
4723                                  non-<BlockName>.
4724   @retval EFI_BUFFER_TOO_SMALL   Block not large enough. Progress undefined.
4725                                  BlockSize is updated with the required buffer size.
4726   @retval EFI_NOT_FOUND          Target for the specified routing data was not found.
4727                                  Progress points to the "G" in "GUID" of the errant
4728                                  routing data.
4729 
4730 **/
4731 EFI_STATUS
4732 EFIAPI
HiiConfigToBlock(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN CONST EFI_STRING ConfigResp,IN OUT UINT8 * Block,IN OUT UINTN * BlockSize,OUT EFI_STRING * Progress)4733 HiiConfigToBlock (
4734   IN     CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4735   IN     CONST EFI_STRING                      ConfigResp,
4736   IN OUT UINT8                                 *Block,
4737   IN OUT UINTN                                 *BlockSize,
4738   OUT    EFI_STRING                            *Progress
4739   )
4740 {
4741   HII_DATABASE_PRIVATE_DATA           *Private;
4742   EFI_STRING                          StringPtr;
4743   EFI_STRING                          TmpPtr;
4744   UINTN                               Length;
4745   EFI_STATUS                          Status;
4746   UINT8                               *TmpBuffer;
4747   UINTN                               Offset;
4748   UINTN                               Width;
4749   UINT8                               *Value;
4750   UINTN                               BufferSize;
4751   UINTN                               MaxBlockSize;
4752 
4753   TmpBuffer = NULL;
4754 
4755   if (This == NULL || BlockSize == NULL || Progress == NULL) {
4756     return EFI_INVALID_PARAMETER;
4757   }
4758 
4759   *Progress = ConfigResp;
4760   if (ConfigResp == NULL) {
4761     return EFI_INVALID_PARAMETER;
4762   }
4763 
4764   Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4765   ASSERT (Private != NULL);
4766 
4767   StringPtr  = ConfigResp;
4768   BufferSize = *BlockSize;
4769   Value      = NULL;
4770   MaxBlockSize = 0;
4771 
4772   //
4773   // Jump <ConfigHdr>
4774   //
4775   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4776     *Progress = StringPtr;
4777     Status = EFI_INVALID_PARAMETER;
4778     goto Exit;
4779   }
4780   while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
4781     StringPtr++;
4782   }
4783   if (*StringPtr == 0) {
4784     *Progress = StringPtr;
4785     Status = EFI_INVALID_PARAMETER;
4786     goto Exit;
4787   }
4788 
4789   while (*StringPtr != L'&' && *StringPtr != 0) {
4790     StringPtr++;
4791   }
4792   if (*StringPtr == 0) {
4793     *Progress = StringPtr;
4794     Status = EFI_INVALID_PARAMETER;
4795     goto Exit;
4796   }
4797 
4798   //
4799   // Parse each <ConfigElement> if exists
4800   // Only '&'<BlockConfig> format is supported by this help function.
4801   // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
4802   //
4803   while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
4804     TmpPtr     = StringPtr;
4805     StringPtr += StrLen (L"&OFFSET=");
4806     //
4807     // Get Offset
4808     //
4809     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4810     if (EFI_ERROR (Status)) {
4811       *Progress = TmpPtr;
4812       goto Exit;
4813     }
4814     Offset = 0;
4815     CopyMem (
4816       &Offset,
4817       TmpBuffer,
4818       (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4819       );
4820     FreePool (TmpBuffer);
4821 
4822     StringPtr += Length;
4823     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
4824       *Progress = TmpPtr;
4825       Status = EFI_INVALID_PARAMETER;
4826       goto Exit;
4827     }
4828     StringPtr += StrLen (L"&WIDTH=");
4829 
4830     //
4831     // Get Width
4832     //
4833     Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4834     if (EFI_ERROR (Status)) {
4835       *Progress = TmpPtr;
4836       goto Exit;
4837     }
4838     Width = 0;
4839     CopyMem (
4840       &Width,
4841       TmpBuffer,
4842       (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4843       );
4844     FreePool (TmpBuffer);
4845 
4846     StringPtr += Length;
4847     if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
4848       *Progress = TmpPtr;
4849       Status = EFI_INVALID_PARAMETER;
4850       goto Exit;
4851     }
4852     StringPtr += StrLen (L"&VALUE=");
4853 
4854     //
4855     // Get Value
4856     //
4857     Status = GetValueOfNumber (StringPtr, &Value, &Length);
4858     if (EFI_ERROR (Status)) {
4859       *Progress = TmpPtr;
4860       goto Exit;
4861     }
4862 
4863     StringPtr += Length;
4864     if (*StringPtr != 0 && *StringPtr != L'&') {
4865       *Progress = TmpPtr;
4866       Status = EFI_INVALID_PARAMETER;
4867       goto Exit;
4868     }
4869 
4870     //
4871     // Update the Block with configuration info
4872     //
4873     if ((Block != NULL) && (Offset + Width <= BufferSize)) {
4874       CopyMem (Block + Offset, Value, Width);
4875     }
4876     if (Offset + Width > MaxBlockSize) {
4877       MaxBlockSize = Offset + Width;
4878     }
4879 
4880     FreePool (Value);
4881     Value = NULL;
4882 
4883     //
4884     // If '\0', parsing is finished.
4885     //
4886     if (*StringPtr == 0) {
4887       break;
4888     }
4889   }
4890 
4891   //
4892   // The input string is not ConfigResp format, return error.
4893   //
4894   if (*StringPtr != 0) {
4895     *Progress = StringPtr;
4896     Status = EFI_INVALID_PARAMETER;
4897     goto Exit;
4898   }
4899 
4900   *Progress = StringPtr + StrLen (StringPtr);
4901   *BlockSize = MaxBlockSize - 1;
4902 
4903   if (MaxBlockSize > BufferSize) {
4904     *BlockSize = MaxBlockSize;
4905     if (Block != NULL) {
4906       return EFI_BUFFER_TOO_SMALL;
4907     }
4908   }
4909 
4910   if (Block == NULL) {
4911     *Progress = ConfigResp;
4912     return EFI_INVALID_PARAMETER;
4913   }
4914 
4915   return EFI_SUCCESS;
4916 
4917 Exit:
4918 
4919   if (Value != NULL) {
4920     FreePool (Value);
4921   }
4922   return Status;
4923 }
4924 
4925 
4926 /**
4927   This helper function is to be called by drivers to extract portions of
4928   a larger configuration string.
4929 
4930   @param  This                   A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4931                                  instance.
4932   @param  Configuration          A null-terminated Unicode string in
4933                                  <MultiConfigAltResp> format.
4934   @param  Guid                   A pointer to the GUID value to search for in the
4935                                  routing portion of the ConfigResp string when
4936                                  retrieving  the requested data. If Guid is NULL,
4937                                  then all GUID  values will be searched for.
4938   @param  Name                   A pointer to the NAME value to search for in the
4939                                  routing portion of the ConfigResp string when
4940                                  retrieving  the requested data. If Name is NULL,
4941                                  then all Name  values will be searched for.
4942   @param  DevicePath             A pointer to the PATH value to search for in the
4943                                  routing portion of the ConfigResp string when
4944                                  retrieving  the requested data. If DevicePath is
4945                                  NULL, then all  DevicePath values will be searched
4946                                  for.
4947   @param  AltCfgId               A pointer to the ALTCFG value to search for in the
4948                                   routing portion of the ConfigResp string when
4949                                  retrieving  the requested data.  If this parameter
4950                                  is NULL,  then the current setting will be
4951                                  retrieved.
4952   @param  AltCfgResp             A pointer to a buffer which will be allocated by
4953                                  the  function which contains the retrieved string
4954                                  as requested.   This buffer is only allocated if
4955                                  the call was successful. It is <ConfigResp> format.
4956 
4957   @retval EFI_SUCCESS            The request succeeded. The requested data was
4958                                  extracted  and placed in the newly allocated
4959                                  AltCfgResp buffer.
4960   @retval EFI_OUT_OF_RESOURCES   Not enough memory to allocate AltCfgResp.
4961   @retval EFI_INVALID_PARAMETER  Any parameter is invalid.
4962   @retval EFI_NOT_FOUND          Target for the specified routing data was not
4963                                  found.
4964 
4965 **/
4966 EFI_STATUS
4967 EFIAPI
HiiGetAltCfg(IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL * This,IN CONST EFI_STRING Configuration,IN CONST EFI_GUID * Guid,IN CONST EFI_STRING Name,IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN CONST UINT16 * AltCfgId,OUT EFI_STRING * AltCfgResp)4968 HiiGetAltCfg (
4969   IN  CONST EFI_HII_CONFIG_ROUTING_PROTOCOL    *This,
4970   IN  CONST EFI_STRING                         Configuration,
4971   IN  CONST EFI_GUID                           *Guid,
4972   IN  CONST EFI_STRING                         Name,
4973   IN  CONST EFI_DEVICE_PATH_PROTOCOL           *DevicePath,
4974   IN  CONST UINT16                             *AltCfgId,
4975   OUT EFI_STRING                               *AltCfgResp
4976   )
4977 {
4978   EFI_STATUS                          Status;
4979   EFI_STRING                          StringPtr;
4980   EFI_STRING                          HdrStart;
4981   EFI_STRING                          HdrEnd;
4982   EFI_STRING                          TmpPtr;
4983   UINTN                               Length;
4984   EFI_STRING                          GuidStr;
4985   EFI_STRING                          NameStr;
4986   EFI_STRING                          PathStr;
4987   EFI_STRING                          AltIdStr;
4988   EFI_STRING                          Result;
4989   BOOLEAN                             GuidFlag;
4990   BOOLEAN                             NameFlag;
4991   BOOLEAN                             PathFlag;
4992 
4993   HdrStart = NULL;
4994   HdrEnd   = NULL;
4995   GuidStr  = NULL;
4996   NameStr  = NULL;
4997   PathStr  = NULL;
4998   AltIdStr = NULL;
4999   Result   = NULL;
5000   GuidFlag = FALSE;
5001   NameFlag = FALSE;
5002   PathFlag = FALSE;
5003 
5004   if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
5005     return EFI_INVALID_PARAMETER;
5006   }
5007 
5008   StringPtr = Configuration;
5009   if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
5010     return EFI_INVALID_PARAMETER;
5011   }
5012 
5013   //
5014   // Generate the sub string for later matching.
5015   //
5016   GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
5017   GenerateSubStr (
5018     L"PATH=",
5019     GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
5020     (VOID *) DevicePath,
5021     1,
5022     &PathStr
5023     );
5024   if (AltCfgId != NULL) {
5025     GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
5026   }
5027   if (Name != NULL) {
5028     GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
5029   } else {
5030     GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
5031   }
5032 
5033   while (*StringPtr != 0) {
5034     //
5035     // Try to match the GUID
5036     //
5037     if (!GuidFlag) {
5038       TmpPtr = StrStr (StringPtr, GuidStr);
5039       if (TmpPtr == NULL) {
5040         Status = EFI_NOT_FOUND;
5041         goto Exit;
5042       }
5043       HdrStart = TmpPtr;
5044 
5045       //
5046       // Jump to <NameHdr>
5047       //
5048       if (Guid != NULL) {
5049         StringPtr = TmpPtr + StrLen (GuidStr);
5050       } else {
5051         StringPtr = StrStr (TmpPtr, L"NAME=");
5052         if (StringPtr == NULL) {
5053           Status = EFI_NOT_FOUND;
5054           goto Exit;
5055         }
5056       }
5057       GuidFlag = TRUE;
5058     }
5059 
5060     //
5061     // Try to match the NAME
5062     //
5063     if (GuidFlag && !NameFlag) {
5064       if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
5065         GuidFlag = FALSE;
5066       } else {
5067         //
5068         // Jump to <PathHdr>
5069         //
5070         if (Name != NULL) {
5071           StringPtr += StrLen (NameStr);
5072         } else {
5073           StringPtr = StrStr (StringPtr, L"PATH=");
5074           if (StringPtr == NULL) {
5075             Status = EFI_NOT_FOUND;
5076             goto Exit;
5077           }
5078         }
5079         NameFlag = TRUE;
5080       }
5081     }
5082 
5083     //
5084     // Try to match the DevicePath
5085     //
5086     if (GuidFlag && NameFlag && !PathFlag) {
5087       if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
5088         GuidFlag = FALSE;
5089         NameFlag = FALSE;
5090       } else {
5091         //
5092         // Jump to '&' before <DescHdr> or <ConfigBody>
5093         //
5094         if (DevicePath != NULL) {
5095           StringPtr += StrLen (PathStr);
5096         } else {
5097           StringPtr = StrStr (StringPtr, L"&");
5098           if (StringPtr == NULL) {
5099             Status = EFI_NOT_FOUND;
5100             goto Exit;
5101           }
5102           StringPtr ++;
5103         }
5104         PathFlag = TRUE;
5105         HdrEnd   = StringPtr;
5106       }
5107     }
5108 
5109     //
5110     // Try to match the AltCfgId
5111     //
5112     if (GuidFlag && NameFlag && PathFlag) {
5113       if (AltCfgId == NULL) {
5114         //
5115         // Return Current Setting when AltCfgId is NULL.
5116         //
5117         Status = OutputConfigBody (StringPtr, &Result);
5118         goto Exit;
5119       }
5120       //
5121       // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
5122       //
5123       if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
5124         GuidFlag = FALSE;
5125         NameFlag = FALSE;
5126         PathFlag = FALSE;
5127       } else {
5128         //
5129         // Skip AltIdStr and &
5130         //
5131         StringPtr = StringPtr + StrLen (AltIdStr);
5132         Status    = OutputConfigBody (StringPtr, &Result);
5133         goto Exit;
5134       }
5135     }
5136   }
5137 
5138   Status = EFI_NOT_FOUND;
5139 
5140 Exit:
5141   *AltCfgResp = NULL;
5142   if (!EFI_ERROR (Status) && (Result != NULL)) {
5143     //
5144     // Copy the <ConfigHdr> and <ConfigBody>
5145     //
5146     Length = HdrEnd - HdrStart + StrLen (Result) + 1;
5147     *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
5148     if (*AltCfgResp == NULL) {
5149       Status = EFI_OUT_OF_RESOURCES;
5150     } else {
5151       StrnCpyS (*AltCfgResp, Length, HdrStart, HdrEnd - HdrStart);
5152       StrCatS (*AltCfgResp, Length, Result);
5153       Status = EFI_SUCCESS;
5154     }
5155   }
5156 
5157   if (GuidStr != NULL) {
5158     FreePool (GuidStr);
5159   }
5160   if (NameStr != NULL) {
5161     FreePool (NameStr);
5162   }
5163   if (PathStr != NULL) {
5164     FreePool (PathStr);
5165   }
5166   if (AltIdStr != NULL) {
5167     FreePool (AltIdStr);
5168   }
5169   if (Result != NULL) {
5170     FreePool (Result);
5171   }
5172 
5173   return Status;
5174 
5175 }
5176 
5177 
5178