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