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