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