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