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