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