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