]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c
MdeModulePkg: remove unused variable DevicePathSize
[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
1325 ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL);
1326
1327 PackageListNode = DatabaseRecord->PackageList;
1328
1329 if (*NameSpace != NULL) {
1330 Name = *NameSpace;
1331 } else {
1332 Name = UEFI_CONFIG_LANG;
1333 }
1334
1335 for (Link = PackageListNode->StringPkgHdr.ForwardLink; Link != &PackageListNode->StringPkgHdr; Link = Link->ForwardLink) {
1336 StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
1337
1338 if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) {
1339 Status = GetStringIdFromString (StringPackage, KeywordValue, StringId);
1340 if (EFI_ERROR (Status)) {
1341 return KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
1342 } else {
1343 if (*NameSpace == NULL) {
1344 *NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
1345 if (*NameSpace == NULL) {
1346 return KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
1347 }
1348 }
1349 return KEYWORD_HANDLER_NO_ERROR;
1350 }
1351 }
1352 }
1353
1354 return KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
1355 }
1356
1357 /**
1358 Tell whether this Operand is an Statement OpCode.
1359
1360 @param Operand Operand of an IFR OpCode.
1361
1362 @retval TRUE This is an Statement OpCode.
1363 @retval FALSE Not an Statement OpCode.
1364
1365 **/
1366 BOOLEAN
1367 IsStatementOpCode (
1368 IN UINT8 Operand
1369 )
1370 {
1371 if ((Operand == EFI_IFR_SUBTITLE_OP) ||
1372 (Operand == EFI_IFR_TEXT_OP) ||
1373 (Operand == EFI_IFR_RESET_BUTTON_OP) ||
1374 (Operand == EFI_IFR_REF_OP) ||
1375 (Operand == EFI_IFR_ACTION_OP) ||
1376 (Operand == EFI_IFR_NUMERIC_OP) ||
1377 (Operand == EFI_IFR_ORDERED_LIST_OP) ||
1378 (Operand == EFI_IFR_CHECKBOX_OP) ||
1379 (Operand == EFI_IFR_STRING_OP) ||
1380 (Operand == EFI_IFR_PASSWORD_OP) ||
1381 (Operand == EFI_IFR_DATE_OP) ||
1382 (Operand == EFI_IFR_TIME_OP) ||
1383 (Operand == EFI_IFR_GUID_OP) ||
1384 (Operand == EFI_IFR_ONE_OF_OP)) {
1385 return TRUE;
1386 }
1387
1388 return FALSE;
1389 }
1390
1391 /**
1392 Tell whether this Operand is an Statement OpCode.
1393
1394 @param Operand Operand of an IFR OpCode.
1395
1396 @retval TRUE This is an Statement OpCode.
1397 @retval FALSE Not an Statement OpCode.
1398
1399 **/
1400 BOOLEAN
1401 IsStorageOpCode (
1402 IN UINT8 Operand
1403 )
1404 {
1405 if ((Operand == EFI_IFR_VARSTORE_OP) ||
1406 (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
1407 (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
1408 return TRUE;
1409 }
1410
1411 return FALSE;
1412 }
1413
1414 /**
1415 Base on the prompt string id to find the question.
1416
1417 @param FormPackage The input form package.
1418 @param KeywordStrId The input prompt string id for one question.
1419
1420 @retval the opcode for the question.
1421
1422 **/
1423 UINT8 *
1424 FindQuestionFromStringId (
1425 IN HII_IFR_PACKAGE_INSTANCE *FormPackage,
1426 IN EFI_STRING_ID KeywordStrId
1427 )
1428 {
1429 UINT8 *OpCodeData;
1430 UINT32 Offset;
1431 EFI_IFR_STATEMENT_HEADER *StatementHeader;
1432 EFI_IFR_OP_HEADER *OpCodeHeader;
1433 UINT32 FormDataLen;
1434
1435 ASSERT (FormPackage != NULL);
1436
1437 FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
1438 Offset = 0;
1439 while (Offset < FormDataLen) {
1440 OpCodeData = FormPackage->IfrData + Offset;
1441 OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
1442
1443 if (IsStatementOpCode(OpCodeHeader->OpCode)) {
1444 StatementHeader = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
1445 if (StatementHeader->Prompt == KeywordStrId) {
1446 return OpCodeData;
1447 }
1448 }
1449
1450 Offset += OpCodeHeader->Length;
1451 }
1452
1453 return NULL;
1454 }
1455
1456 /**
1457 Base on the varstore id to find the storage info.
1458
1459 @param FormPackage The input form package.
1460 @param VarStoreId The input storage id.
1461
1462 @retval the opcode for the storage.
1463
1464 **/
1465 UINT8 *
1466 FindStorageFromVarId (
1467 IN HII_IFR_PACKAGE_INSTANCE *FormPackage,
1468 IN EFI_VARSTORE_ID VarStoreId
1469 )
1470 {
1471 UINT8 *OpCodeData;
1472 UINT32 Offset;
1473 EFI_IFR_OP_HEADER *OpCodeHeader;
1474 UINT32 FormDataLen;
1475
1476 ASSERT (FormPackage != NULL);
1477
1478 FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
1479 Offset = 0;
1480 while (Offset < FormDataLen) {
1481 OpCodeData = FormPackage->IfrData + Offset;
1482 OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
1483
1484 if (IsStorageOpCode(OpCodeHeader->OpCode)) {
1485 switch (OpCodeHeader->OpCode) {
1486 case EFI_IFR_VARSTORE_OP:
1487 if (VarStoreId == ((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId) {
1488 return OpCodeData;
1489 }
1490 break;
1491
1492 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1493 if (VarStoreId == ((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId) {
1494 return OpCodeData;
1495 }
1496 break;
1497
1498 case EFI_IFR_VARSTORE_EFI_OP:
1499 if (VarStoreId == ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId) {
1500 return OpCodeData;
1501 }
1502 break;
1503
1504 default:
1505 break;
1506 }
1507 }
1508
1509 Offset += OpCodeHeader->Length;
1510 }
1511
1512 return NULL;
1513 }
1514
1515 /**
1516 Get width info for one question.
1517
1518 @param OpCodeData The input opcode for one question.
1519
1520 @retval the width info for one question.
1521
1522 **/
1523 UINT16
1524 GetWidth (
1525 IN UINT8 *OpCodeData
1526 )
1527 {
1528 UINT8 *NextOpCodeData;
1529
1530 ASSERT (OpCodeData != NULL);
1531
1532 switch (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode) {
1533 case EFI_IFR_REF_OP:
1534 return (UINT16) sizeof (EFI_HII_REF);
1535
1536 case EFI_IFR_ONE_OF_OP:
1537 case EFI_IFR_NUMERIC_OP:
1538 switch (((EFI_IFR_ONE_OF *) OpCodeData)->Flags & EFI_IFR_NUMERIC_SIZE) {
1539 case EFI_IFR_NUMERIC_SIZE_1:
1540 return (UINT16) sizeof (UINT8);
1541
1542 case EFI_IFR_NUMERIC_SIZE_2:
1543 return (UINT16) sizeof (UINT16);
1544
1545 case EFI_IFR_NUMERIC_SIZE_4:
1546 return (UINT16) sizeof (UINT32);
1547
1548 case EFI_IFR_NUMERIC_SIZE_8:
1549 return (UINT16) sizeof (UINT64);
1550
1551 default:
1552 ASSERT (FALSE);
1553 return 0;
1554 }
1555
1556 case EFI_IFR_ORDERED_LIST_OP:
1557 NextOpCodeData = OpCodeData + ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Header.Length;
1558 //
1559 // OneOfOption must follow the orderedlist opcode.
1560 //
1561 ASSERT (((EFI_IFR_OP_HEADER *) NextOpCodeData)->OpCode == EFI_IFR_ONE_OF_OPTION_OP);
1562 switch (((EFI_IFR_ONE_OF_OPTION *) NextOpCodeData)->Type) {
1563 case EFI_IFR_TYPE_NUM_SIZE_8:
1564 return (UINT16) sizeof (UINT8) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
1565
1566 case EFI_IFR_TYPE_NUM_SIZE_16:
1567 return (UINT16) sizeof (UINT16) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers ;
1568
1569 case EFI_IFR_TYPE_NUM_SIZE_32:
1570 return (UINT16) sizeof (UINT32) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
1571
1572 case EFI_IFR_TYPE_NUM_SIZE_64:
1573 return (UINT16) sizeof (UINT64) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
1574 break;
1575
1576 default:
1577 ASSERT (FALSE);
1578 return 0;
1579 }
1580
1581 case EFI_IFR_CHECKBOX_OP:
1582 return (UINT16) sizeof (BOOLEAN);
1583
1584 case EFI_IFR_PASSWORD_OP:
1585 case EFI_IFR_STRING_OP:
1586 return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16));
1587
1588 case EFI_IFR_DATE_OP:
1589 return (UINT16) sizeof (EFI_HII_DATE);
1590
1591 case EFI_IFR_TIME_OP:
1592 return (UINT16) sizeof (EFI_HII_TIME);
1593
1594 default:
1595 ASSERT (FALSE);
1596 return 0;
1597 }
1598 }
1599
1600 /**
1601 Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for
1602 hex digits that appear between a '=' and a '&' in a config string.
1603
1604 If ConfigString is NULL, then ASSERT().
1605
1606 @param[in] ConfigString Pointer to a Null-terminated Unicode string.
1607
1608 @return Pointer to the Null-terminated Unicode result string.
1609
1610 **/
1611 EFI_STRING
1612 EFIAPI
1613 InternalLowerConfigString (
1614 IN EFI_STRING ConfigString
1615 )
1616 {
1617 EFI_STRING String;
1618 BOOLEAN Lower;
1619
1620 ASSERT (ConfigString != NULL);
1621
1622 //
1623 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
1624 //
1625 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
1626 if (*String == L'=') {
1627 Lower = TRUE;
1628 } else if (*String == L'&') {
1629 Lower = FALSE;
1630 } else if (Lower && *String >= L'A' && *String <= L'F') {
1631 *String = (CHAR16) (*String - L'A' + L'a');
1632 }
1633 }
1634
1635 return ConfigString;
1636 }
1637
1638 /**
1639 Allocates and returns a Null-terminated Unicode <ConfigHdr> string.
1640
1641 The format of a <ConfigHdr> is as follows:
1642
1643 GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
1644
1645 @param[in] OpCodeData The opcode for the storage.
1646 @param[in] DriverHandle The driver handle which supports a Device Path Protocol
1647 that is the routing information PATH. Each byte of
1648 the Device Path associated with DriverHandle is converted
1649 to a 2 Unicode character hexidecimal string.
1650
1651 @retval NULL DriverHandle does not support the Device Path Protocol.
1652 @retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
1653
1654 **/
1655 EFI_STRING
1656 ConstructConfigHdr (
1657 IN UINT8 *OpCodeData,
1658 IN EFI_HANDLE DriverHandle
1659 )
1660 {
1661 UINTN NameLength;
1662 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1663 UINTN DevicePathSize;
1664 CHAR16 *String;
1665 CHAR16 *ReturnString;
1666 UINTN Index;
1667 UINT8 *Buffer;
1668 CHAR16 *Name;
1669 CHAR8 *AsciiName;
1670 EFI_GUID *Guid;
1671
1672 ASSERT (OpCodeData != NULL);
1673
1674 switch (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode) {
1675 case EFI_IFR_VARSTORE_OP:
1676 Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE *) OpCodeData)->Guid;
1677 AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
1678 break;
1679
1680 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1681 Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid;
1682 AsciiName = NULL;
1683 break;
1684
1685 case EFI_IFR_VARSTORE_EFI_OP:
1686 Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid;
1687 AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
1688 break;
1689
1690 default:
1691 ASSERT (FALSE);
1692 Guid = NULL;
1693 AsciiName = NULL;
1694 break;
1695 }
1696
1697 if (AsciiName != NULL) {
1698 Name = AllocateZeroPool (AsciiStrSize (AsciiName) * 2);
1699 ASSERT (Name != NULL);
1700 AsciiStrToUnicodeStr(AsciiName, Name);
1701 } else {
1702 Name = NULL;
1703 }
1704
1705 //
1706 // Compute the length of Name in Unicode characters.
1707 // If Name is NULL, then the length is 0.
1708 //
1709 NameLength = 0;
1710 if (Name != NULL) {
1711 NameLength = StrLen (Name);
1712 }
1713
1714 DevicePath = NULL;
1715 DevicePathSize = 0;
1716 //
1717 // Retrieve DevicePath Protocol associated with DriverHandle
1718 //
1719 if (DriverHandle != NULL) {
1720 DevicePath = DevicePathFromHandle (DriverHandle);
1721 if (DevicePath == NULL) {
1722 return NULL;
1723 }
1724 //
1725 // Compute the size of the device path in bytes
1726 //
1727 DevicePathSize = GetDevicePathSize (DevicePath);
1728 }
1729
1730 //
1731 // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
1732 // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
1733 //
1734 String = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16));
1735 if (String == NULL) {
1736 return NULL;
1737 }
1738
1739 //
1740 // Start with L"GUID="
1741 //
1742 ReturnString = StrCpy (String, L"GUID=");
1743 String += StrLen (String);
1744
1745 if (Guid != NULL) {
1746 //
1747 // Append Guid converted to <HexCh>32
1748 //
1749 for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
1750 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
1751 }
1752 }
1753
1754 //
1755 // Append L"&NAME="
1756 //
1757 StrCpy (String, L"&NAME=");
1758 String += StrLen (String);
1759
1760 if (Name != NULL) {
1761 //
1762 // Append Name converted to <Char>NameLength
1763 //
1764 for (; *Name != L'\0'; Name++) {
1765 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4);
1766 }
1767 }
1768
1769 //
1770 // Append L"&PATH="
1771 //
1772 StrCpy (String, L"&PATH=");
1773 String += StrLen (String);
1774
1775 //
1776 // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
1777 //
1778 for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
1779 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
1780 }
1781
1782 //
1783 // Null terminate the Unicode string
1784 //
1785 *String = L'\0';
1786
1787 //
1788 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
1789 //
1790 return InternalLowerConfigString (ReturnString);
1791 }
1792
1793 /**
1794 Generate the Config request element for one question.
1795
1796 @param Name The name info for one question.
1797 @param Offset The offset info for one question.
1798 @param Width The width info for one question.
1799
1800 @return Pointer to the Null-terminated Unicode request element string.
1801
1802 **/
1803 EFI_STRING
1804 ConstructRequestElement (
1805 IN CHAR16 *Name,
1806 IN UINT16 Offset,
1807 IN UINT16 Width
1808 )
1809 {
1810 CHAR16 *StringPtr;
1811 UINTN Length;
1812
1813 if (Name != NULL) {
1814 //
1815 // Add <BlockName> length for each Name
1816 //
1817 // <BlockName> ::= Name + \0
1818 // StrLen(Name) | 1
1819 //
1820 Length = StrLen (Name) + 1;
1821 } else {
1822 //
1823 // Add <BlockName> length for each Offset/Width pair
1824 //
1825 // <BlockName> ::= OFFSET=1234&WIDTH=1234 + \0
1826 // | 7 | 4 | 7 | 4 | 1
1827 //
1828 Length = (7 + 4 + 7 + 4 + 1);
1829 }
1830
1831 //
1832 // Allocate buffer for the entire <ConfigRequest>
1833 //
1834 StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
1835 ASSERT (StringPtr != NULL);
1836
1837 if (Name != NULL) {
1838 //
1839 // Append Name\0
1840 //
1841 UnicodeSPrint (
1842 StringPtr,
1843 (StrLen (Name) + 1) * sizeof (CHAR16),
1844 L"%s",
1845 Name
1846 );
1847 } else {
1848 //
1849 // Append OFFSET=XXXX&WIDTH=YYYY\0
1850 //
1851 UnicodeSPrint (
1852 StringPtr,
1853 (7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
1854 L"OFFSET=%04X&WIDTH=%04X",
1855 Offset,
1856 Width
1857 );
1858 }
1859
1860 return StringPtr;
1861 }
1862
1863 /**
1864 Get string value for question's name field.
1865
1866 @param DatabaseRecord HII_DATABASE_RECORD format string.
1867 @param NameId The string id for the name field.
1868
1869 @retval Name string.
1870
1871 **/
1872 CHAR16 *
1873 GetNameFromId (
1874 IN HII_DATABASE_RECORD *DatabaseRecord,
1875 IN EFI_STRING_ID NameId
1876 )
1877 {
1878 CHAR16 *Name;
1879 CHAR8 *PlatformLanguage;
1880 CHAR8 *SupportedLanguages;
1881 CHAR8 *BestLanguage;
1882 UINTN StringSize;
1883 CHAR16 TempString;
1884 EFI_STATUS Status;
1885
1886 Name = NULL;
1887 BestLanguage = NULL;
1888 PlatformLanguage = NULL;
1889 SupportedLanguages = NULL;
1890
1891 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
1892 SupportedLanguages = GetSupportedLanguages(DatabaseRecord->Handle);
1893
1894 //
1895 // Get the best matching language from SupportedLanguages
1896 //
1897 BestLanguage = GetBestLanguage (
1898 SupportedLanguages,
1899 FALSE, // RFC 4646 mode
1900 PlatformLanguage != NULL ? PlatformLanguage : "", // Highest priority
1901 SupportedLanguages, // Lowest priority
1902 NULL
1903 );
1904 if (BestLanguage == NULL) {
1905 BestLanguage = AllocateCopyPool (AsciiStrLen ("en-US"), "en-US");
1906 ASSERT (BestLanguage != NULL);
1907 }
1908
1909 StringSize = 0;
1910 Status = mPrivate.HiiString.GetString (
1911 &mPrivate.HiiString,
1912 BestLanguage,
1913 DatabaseRecord->Handle,
1914 NameId,
1915 &TempString,
1916 &StringSize,
1917 NULL
1918 );
1919 if (Status != EFI_BUFFER_TOO_SMALL) {
1920 goto Done;
1921 }
1922
1923 Name = AllocateZeroPool (StringSize);
1924 if (Name == NULL) {
1925 goto Done;
1926 }
1927
1928 Status = mPrivate.HiiString.GetString (
1929 &mPrivate.HiiString,
1930 BestLanguage,
1931 DatabaseRecord->Handle,
1932 NameId,
1933 Name,
1934 &StringSize,
1935 NULL
1936 );
1937
1938 if (EFI_ERROR (Status)) {
1939 FreePool (Name);
1940 Name = NULL;
1941 goto Done;
1942 }
1943
1944 Done:
1945 if (SupportedLanguages != NULL) {
1946 FreePool(SupportedLanguages);
1947 }
1948 if (BestLanguage != NULL) {
1949 FreePool (BestLanguage);
1950 }
1951 if (PlatformLanguage != NULL) {
1952 FreePool (PlatformLanguage);
1953 }
1954
1955 return Name;
1956 }
1957
1958 /**
1959 Base on the input parameter to generate the ConfigRequest string.
1960
1961 This is a internal function.
1962
1963 @param DatabaseRecord HII_DATABASE_RECORD format string.
1964 @param KeywordStrId Keyword string id.
1965 @param OpCodeData The IFR data for this question.
1966 @param ConfigRequest Return the generate ConfigRequest string.
1967
1968 @retval EFI_SUCCESS Generate ConfigResp string success.
1969 @retval EFI_OUT_OF_RESOURCES System out of memory resource error.
1970 @retval EFI_NOT_FOUND Not found the question which use this string id
1971 as the prompt string id.
1972 **/
1973 EFI_STATUS
1974 ExtractConfigRequest (
1975 IN HII_DATABASE_RECORD *DatabaseRecord,
1976 IN EFI_STRING_ID KeywordStrId,
1977 OUT UINT8 **OpCodeData,
1978 OUT EFI_STRING *ConfigRequest
1979 )
1980 {
1981 LIST_ENTRY *Link;
1982 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
1983 HII_IFR_PACKAGE_INSTANCE *FormPackage;
1984 EFI_IFR_QUESTION_HEADER *Header;
1985 UINT8 *Storage;
1986 UINT8 *OpCode;
1987 CHAR16 *Name;
1988 UINT16 Offset;
1989 UINT16 Width;
1990 CHAR16 *ConfigHdr;
1991 CHAR16 *RequestElement;
1992 UINTN Length;
1993 CHAR16 *StringPtr;
1994
1995 ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL);
1996
1997 OpCode = NULL;
1998 Name = NULL;
1999 Width = 0;
2000 Offset = 0;
2001
2002 PackageListNode = DatabaseRecord->PackageList;
2003
2004 //
2005 // Search the languages in the specified packagelist.
2006 //
2007 for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
2008 FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
2009
2010 OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
2011 if (OpCode != NULL) {
2012 *OpCodeData = OpCode;
2013 Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
2014 //
2015 // Header->VarStoreId == 0 means no storage for this question.
2016 //
2017 ASSERT (Header->VarStoreId != 0);
2018 DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
2019
2020 Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
2021 ASSERT (Storage != NULL);
2022
2023 if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
2024 Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
2025 } else {
2026 Offset = Header->VarStoreInfo.VarOffset;
2027 Width = GetWidth (OpCode);
2028 }
2029 RequestElement = ConstructRequestElement(Name, Offset, Width);
2030 ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
2031
2032 Length = (StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1) * sizeof (CHAR16);
2033 *ConfigRequest = AllocatePool (Length);
2034 if (*ConfigRequest == NULL) {
2035 FreePool (ConfigHdr);
2036 FreePool (RequestElement);
2037 return EFI_OUT_OF_RESOURCES;
2038 }
2039 StringPtr = *ConfigRequest;
2040
2041 StrCpy (StringPtr, ConfigHdr);
2042 StringPtr += StrLen (StringPtr);
2043
2044 *StringPtr = L'&';
2045 StringPtr++;
2046
2047 StrCpy (StringPtr, RequestElement);
2048 StringPtr += StrLen (StringPtr);
2049 *StringPtr = L'\0';
2050
2051 FreePool (ConfigHdr);
2052 FreePool (RequestElement);
2053
2054 return EFI_SUCCESS;
2055 }
2056 }
2057
2058 return EFI_NOT_FOUND;
2059 }
2060
2061 /**
2062 Base on the input parameter to generate the ConfigResp string.
2063
2064 This is a internal function.
2065
2066 @param DatabaseRecord HII_DATABASE_RECORD format string.
2067 @param KeywordStrId Keyword string id.
2068 @param ValueElement The value for the question which use keyword string id
2069 as the prompt string id.
2070 @param OpCodeData The IFR data for this question.
2071 @param ConfigResp Return the generate ConfigResp string.
2072
2073 @retval EFI_SUCCESS Generate ConfigResp string success.
2074 @retval EFI_OUT_OF_RESOURCES System out of memory resource error.
2075 @retval EFI_NOT_FOUND Not found the question which use this string id
2076 as the prompt string id.
2077 **/
2078 EFI_STATUS
2079 ExtractConfigResp (
2080 IN HII_DATABASE_RECORD *DatabaseRecord,
2081 IN EFI_STRING_ID KeywordStrId,
2082 IN EFI_STRING ValueElement,
2083 OUT UINT8 **OpCodeData,
2084 OUT EFI_STRING *ConfigResp
2085 )
2086 {
2087 LIST_ENTRY *Link;
2088 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
2089 HII_IFR_PACKAGE_INSTANCE *FormPackage;
2090 EFI_IFR_QUESTION_HEADER *Header;
2091 UINT8 *Storage;
2092 UINT8 *OpCode;
2093 CHAR16 *Name;
2094 UINT16 Offset;
2095 UINT16 Width;
2096 CHAR16 *ConfigHdr;
2097 CHAR16 *RequestElement;
2098 UINTN Length;
2099 CHAR16 *StringPtr;
2100
2101 ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL));
2102
2103 OpCode = NULL;
2104 Name = NULL;
2105 Width = 0;
2106 Offset = 0;
2107
2108 PackageListNode = DatabaseRecord->PackageList;
2109
2110 //
2111 // Search the languages in the specified packagelist.
2112 //
2113 for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
2114 FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
2115
2116 OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
2117 if (OpCode != NULL) {
2118 *OpCodeData = OpCode;
2119 Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
2120 //
2121 // Header->VarStoreId == 0 means no storage for this question.
2122 //
2123 ASSERT (Header->VarStoreId != 0);
2124 DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
2125
2126 Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
2127 ASSERT (Storage != NULL);
2128
2129 if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
2130 Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
2131 } else {
2132 Offset = Header->VarStoreInfo.VarOffset;
2133 Width = GetWidth (OpCode);
2134 }
2135 RequestElement = ConstructRequestElement(Name, Offset, Width);
2136
2137 ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
2138
2139 Length = (StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1) * sizeof (CHAR16);
2140 *ConfigResp = AllocatePool (Length);
2141 if (*ConfigResp == NULL) {
2142 FreePool (ConfigHdr);
2143 FreePool (RequestElement);
2144 return EFI_OUT_OF_RESOURCES;
2145 }
2146 StringPtr = *ConfigResp;
2147
2148 StrCpy (StringPtr, ConfigHdr);
2149 StringPtr += StrLen (StringPtr);
2150
2151 *StringPtr = L'&';
2152 StringPtr++;
2153
2154 StrCpy (StringPtr, RequestElement);
2155 StringPtr += StrLen (StringPtr);
2156
2157 *StringPtr = L'&';
2158 StringPtr++;
2159
2160 StrCpy (StringPtr, L"VALUE=");
2161 StringPtr += StrLen (StringPtr);
2162
2163 StrCpy (StringPtr, ValueElement);
2164 StringPtr += StrLen (StringPtr);
2165 *StringPtr = L'\0';
2166
2167 FreePool (ConfigHdr);
2168 FreePool (RequestElement);
2169
2170 return EFI_SUCCESS;
2171 }
2172 }
2173
2174 return EFI_NOT_FOUND;
2175 }
2176
2177 /**
2178 Get the Value section from the Hii driver.
2179
2180 This is a internal function.
2181
2182 @param ConfigRequest The input ConfigRequest string.
2183 @param ValueElement The respond Value section from the hii driver.
2184
2185 @retval Misc value The error status return from ExtractConfig function.
2186 @retval EFI_OUT_OF_RESOURCES The memory can't be allocated
2187 @retval EFI_SUCCESS Get the value section success.
2188
2189 **/
2190 EFI_STATUS
2191 ExtractValueFromDriver (
2192 IN CHAR16 *ConfigRequest,
2193 OUT CHAR16 **ValueElement
2194 )
2195 {
2196 EFI_STATUS Status;
2197 EFI_STRING Result;
2198 EFI_STRING Progress;
2199 CHAR16 *StringPtr;
2200 CHAR16 *StringEnd;
2201
2202 ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL));
2203
2204 Status = mPrivate.ConfigRouting.ExtractConfig (
2205 &mPrivate.ConfigRouting,
2206 (EFI_STRING) ConfigRequest,
2207 &Progress,
2208 &Result
2209 );
2210 if (EFI_ERROR (Status)) {
2211 return Status;
2212 }
2213
2214 //
2215 // Find Value Section and return it.
2216 //
2217 StringPtr = StrStr (Result, L"&VALUE=");
2218 ASSERT (StringPtr != NULL);
2219 StringEnd = StrStr (StringPtr + 1, L"&");
2220 if (StringEnd != NULL) {
2221 *StringEnd = L'\0';
2222 }
2223
2224 *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr);
2225 if (*ValueElement == NULL) {
2226 return EFI_OUT_OF_RESOURCES;
2227 }
2228
2229 if (StringEnd != NULL) {
2230 *StringEnd = L'&';
2231 }
2232 FreePool (Result);
2233
2234 return EFI_SUCCESS;
2235 }
2236
2237 /**
2238 Get EFI_STRING_ID info from the input device path, namespace and keyword.
2239
2240 This is a internal function.
2241
2242 @param DevicePath Input device path info.
2243 @param NameSpace NameSpace format string.
2244 @param KeywordData Keyword used to get string id.
2245 @param ProgressErr Return extra error type.
2246 @param KeywordStringId Return EFI_STRING_ID.
2247 @param DataBaseRecord DataBase record data for this driver.
2248
2249 @retval EFI_INVALID_PARAMETER Can't find the database record base on the input device path or namespace.
2250 @retval EFI_NOT_FOUND Can't find the EFI_STRING_ID for the keyword.
2251 @retval EFI_SUCCESS Find the EFI_STRING_ID.
2252
2253 **/
2254 EFI_STATUS
2255 GetStringIdFromDatabase (
2256 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath,
2257 IN CHAR8 **NameSpace,
2258 IN CHAR16 *KeywordData,
2259 OUT UINT32 *ProgressErr,
2260 OUT EFI_STRING_ID *KeywordStringId,
2261 OUT HII_DATABASE_RECORD **DataBaseRecord
2262 )
2263 {
2264 HII_DATABASE_RECORD *Record;
2265 LIST_ENTRY *Link;
2266 BOOLEAN FindNameSpace;
2267 EFI_DEVICE_PATH_PROTOCOL *DestDevicePath;
2268 UINT8 *DevicePathPkg;
2269 UINTN DevicePathSize;
2270
2271 ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL));
2272
2273 FindNameSpace = FALSE;
2274
2275 if (*DevicePath != NULL) {
2276 //
2277 // Get DataBaseRecord from device path protocol.
2278 //
2279 Record = GetRecordFromDevicePath(*DevicePath);
2280 if (Record == NULL) {
2281 //
2282 // Can't find the DatabaseRecord base on the input device path info.
2283 // NEED TO CONFIRM the return ProgressErr.
2284 //
2285 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
2286 return EFI_INVALID_PARAMETER;
2287 }
2288
2289 //
2290 // Get string id from the record.
2291 //
2292 *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
2293 switch (*ProgressErr) {
2294 case KEYWORD_HANDLER_NO_ERROR:
2295 *DataBaseRecord = Record;
2296 return EFI_SUCCESS;
2297
2298 case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND:
2299 return EFI_INVALID_PARAMETER;
2300
2301 default:
2302 ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND);
2303 return EFI_NOT_FOUND;
2304 }
2305 } else {
2306 //
2307 // Find driver which matches the routing data.
2308 //
2309 for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
2310 Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2311
2312 *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
2313 if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) {
2314 *DataBaseRecord = Record;
2315
2316 if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) {
2317 DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER));
2318 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath);
2319 *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath);
2320 if (*DevicePath == NULL) {
2321 return EFI_OUT_OF_RESOURCES;
2322 }
2323 } else {
2324 //
2325 // Need to verify this ASSERT.
2326 //
2327 ASSERT (FALSE);
2328 }
2329
2330 return EFI_SUCCESS;
2331 } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) {
2332 return EFI_OUT_OF_RESOURCES;
2333 } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) {
2334 FindNameSpace = TRUE;
2335 }
2336 }
2337
2338 //
2339 // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND.
2340 // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND.
2341 //
2342 if (FindNameSpace) {
2343 return EFI_NOT_FOUND;
2344 } else {
2345 return EFI_INVALID_PARAMETER;
2346 }
2347 }
2348 }
2349
2350 /**
2351 Genereate the KeywordResp String.
2352
2353 <KeywordResp> ::= <NameSpaceId><PathHdr>'&'<Keyword>'&VALUE='<Number>['&READONLY']
2354
2355 @param NameSpace NameSpace format string.
2356 @param DevicePath Input device path info.
2357 @param KeywordData Keyword used to get string id.
2358 @param ValueStr The value section for the keyword.
2359 @param ReadOnly Whether this value is readonly.
2360 @param KeywordResp Return the point to the KeywordResp string.
2361
2362 @retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
2363 @retval EFI_SUCCESS Generate the KeywordResp string.
2364
2365 **/
2366 EFI_STATUS
2367 GenerateKeywordResp (
2368 IN CHAR8 *NameSpace,
2369 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
2370 IN EFI_STRING KeywordData,
2371 IN EFI_STRING ValueStr,
2372 IN BOOLEAN ReadOnly,
2373 OUT EFI_STRING *KeywordResp
2374 )
2375 {
2376 UINTN RespStrLen;
2377 CHAR16 *RespStr;
2378 CHAR16 *PathHdr;
2379 CHAR16 *UnicodeNameSpace;
2380
2381 ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL));
2382
2383 //
2384 // 1. Calculate the string length.
2385 //
2386 //
2387 // 1.1 NameSpaceId size.
2388 // 'NAMESPACE='<String>
2389 //
2390 RespStrLen = 10 + AsciiStrLen (NameSpace);
2391 UnicodeNameSpace = AllocatePool ((AsciiStrLen (NameSpace) + 1) * sizeof (CHAR16));
2392 if (UnicodeNameSpace == NULL) {
2393 return EFI_OUT_OF_RESOURCES;
2394 }
2395 AsciiStrToUnicodeStr(NameSpace, UnicodeNameSpace);
2396
2397 //
2398 // 1.2 PathHdr size.
2399 // PATH=<UEFI binary Device Path represented as hex number>'&'
2400 // Attention: The output include the '&' at the end.
2401 //
2402 GenerateSubStr (
2403 L"&PATH=",
2404 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
2405 (VOID *) DevicePath,
2406 1,
2407 &PathHdr
2408 );
2409 RespStrLen += StrLen (PathHdr);
2410
2411 //
2412 // 1.3 Keyword setion.
2413 // 'KEYWORD='<String>[':'<DecCh>(1/4)]
2414 //
2415 RespStrLen += 8 + StrLen (KeywordData);
2416
2417 //
2418 // 1.4 Value section.
2419 // ValueStr = '&VALUE='<Number>
2420 //
2421 RespStrLen += StrLen (ValueStr);
2422
2423 //
2424 // 1.5 ReadOnly Section.
2425 // '&READONLY'
2426 //
2427 if (ReadOnly) {
2428 RespStrLen += 9;
2429 }
2430
2431 //
2432 // 2. Allocate the buffer and create the KeywordResp string.
2433 //
2434 *KeywordResp = AllocatePool ((RespStrLen + 1) * sizeof (CHAR16));
2435 if (*KeywordResp == NULL) {
2436 if (UnicodeNameSpace != NULL) {
2437 FreePool (UnicodeNameSpace);
2438 }
2439
2440 return EFI_OUT_OF_RESOURCES;
2441 }
2442 RespStr = *KeywordResp;
2443
2444 //
2445 // 2.1 Copy NameSpaceId section.
2446 //
2447 StrCpy (RespStr, L"NAMESPACE=");
2448 RespStr += StrLen (RespStr);
2449 StrCpy (RespStr, UnicodeNameSpace);
2450 RespStr += StrLen (RespStr);
2451
2452 //
2453 // 2.2 Copy PathHdr section.
2454 //
2455 StrCpy (RespStr, PathHdr);
2456 RespStr += StrLen (RespStr);
2457
2458 //
2459 // 2.3 Copy Keyword section.
2460 //
2461 StrCpy (RespStr, L"KEYWORD=");
2462 RespStr += StrLen (RespStr);
2463 StrCpy (RespStr, KeywordData);
2464 RespStr += StrLen (RespStr);
2465
2466 //
2467 // 2.4 Copy the Value section.
2468 //
2469 StrCpy (RespStr, ValueStr);
2470 RespStr += StrLen (RespStr);
2471
2472 //
2473 // 2.5 Copy ReadOnly section if exist.
2474 //
2475 if (ReadOnly) {
2476 StrCpy (RespStr, L"&READONLY");
2477 RespStr += StrLen (RespStr);
2478 }
2479
2480 //
2481 // 2.6 Add the end.
2482 //
2483 *RespStr = L'\0';
2484
2485 if (UnicodeNameSpace != NULL) {
2486 FreePool (UnicodeNameSpace);
2487 }
2488 if (PathHdr != NULL) {
2489 FreePool (PathHdr);
2490 }
2491
2492 return EFI_SUCCESS;
2493 }
2494
2495 /**
2496 Merge the KeywordResp String to MultiKeywordResp string.
2497
2498 This is a internal function.
2499
2500 @param MultiKeywordResp The existed multikeywordresp string.
2501 @param KeywordResp The input keywordResp string.
2502
2503 @retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
2504 @retval EFI_SUCCESS Generate the MultiKeywordResp string.
2505
2506 **/
2507 EFI_STATUS
2508 MergeToMultiKeywordResp (
2509 IN OUT EFI_STRING *MultiKeywordResp,
2510 IN EFI_STRING *KeywordResp
2511 )
2512 {
2513 UINTN MultiKeywordRespLen;
2514 EFI_STRING StringPtr;
2515
2516 if (*MultiKeywordResp == NULL) {
2517 *MultiKeywordResp = *KeywordResp;
2518 *KeywordResp = NULL;
2519 return EFI_SUCCESS;
2520 }
2521
2522 MultiKeywordRespLen = (StrLen (*MultiKeywordResp) + 1 + StrLen (*KeywordResp) + 1) * sizeof (CHAR16);
2523
2524 StringPtr = AllocateCopyPool (MultiKeywordRespLen, *MultiKeywordResp);
2525 if (StringPtr == NULL) {
2526 return EFI_OUT_OF_RESOURCES;
2527 }
2528
2529 FreePool (*MultiKeywordResp);
2530 *MultiKeywordResp = StringPtr;
2531
2532 StringPtr += StrLen (StringPtr);
2533
2534 *StringPtr = L'&';
2535 StringPtr++;
2536
2537 StrCpy (StringPtr, *KeywordResp);
2538
2539 return EFI_SUCCESS;
2540 }
2541
2542 /**
2543 Enumerate all keyword in the system.
2544
2545 If error occur when parse one keyword, just skip it and parse the next one.
2546
2547 This is a internal function.
2548
2549 @param NameSpace The namespace used to search the string.
2550 @param MultiResp Return the MultiKeywordResp string for the system.
2551
2552 @retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
2553 @retval EFI_SUCCESS Generate the MultiKeywordResp string.
2554 @retval EFI_NOT_FOUND No keyword found.
2555
2556 **/
2557 EFI_STATUS
2558 EnumerateAllKeywords (
2559 IN CHAR8 *NameSpace,
2560 OUT EFI_STRING *MultiResp
2561 )
2562 {
2563 LIST_ENTRY *Link;
2564 LIST_ENTRY *StringLink;
2565 UINT8 *DevicePathPkg;
2566 UINT8 *DevicePath;
2567 HII_DATABASE_RECORD *DataBaseRecord;
2568 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
2569 HII_STRING_PACKAGE_INSTANCE *StringPackage;
2570 CHAR8 *LocalNameSpace;
2571 EFI_STRING_ID NextStringId;
2572 EFI_STATUS Status;
2573 UINT8 *OpCode;
2574 CHAR16 *ConfigRequest;
2575 CHAR16 *ValueElement;
2576 CHAR16 *KeywordResp;
2577 CHAR16 *MultiKeywordResp;
2578 CHAR16 *KeywordData;
2579 BOOLEAN ReadOnly;
2580
2581 DataBaseRecord = NULL;
2582 Status = EFI_SUCCESS;
2583 MultiKeywordResp = NULL;
2584 DevicePath = NULL;
2585 LocalNameSpace = NULL;
2586 ConfigRequest = NULL;
2587 ValueElement = NULL;
2588 KeywordResp = NULL;
2589
2590 if (NameSpace == NULL) {
2591 NameSpace = UEFI_CONFIG_LANG;
2592 }
2593
2594 //
2595 // Find driver which matches the routing data.
2596 //
2597 for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
2598 DataBaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2599 if ((DevicePathPkg = DataBaseRecord->PackageList->DevicePathPkg) != NULL) {
2600 DevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2601 }
2602 PackageListNode = DataBaseRecord->PackageList;
2603
2604 for (StringLink = PackageListNode->StringPkgHdr.ForwardLink; StringLink != &PackageListNode->StringPkgHdr; StringLink = StringLink->ForwardLink) {
2605 StringPackage = CR (StringLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
2606
2607 //
2608 // Check whether has keyword string package.
2609 //
2610 if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) {
2611 //
2612 // Keep the NameSpace string.
2613 //
2614 LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
2615 if (LocalNameSpace == NULL) {
2616 return EFI_OUT_OF_RESOURCES;
2617 }
2618
2619 //
2620 // 1 means just begin the enumerate the valid string ids.
2621 // StringId == 1 is always used to save the language for this string package.
2622 // Any valid string start from 2. so here initial it to 1.
2623 //
2624 NextStringId = 1;
2625
2626 //
2627 // Enumerate all valid stringid in the package.
2628 //
2629 while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) {
2630 //
2631 // 3.3 Construct the ConfigRequest string.
2632 //
2633 Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest);
2634 if (EFI_ERROR (Status)) {
2635 //
2636 // If can't generate ConfigRequest for this question, skip it and start the next.
2637 //
2638 goto Error;
2639 }
2640
2641 //
2642 // 3.4 Extract Value for the input keyword.
2643 //
2644 Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
2645 if (EFI_ERROR (Status)) {
2646 if (Status != EFI_OUT_OF_RESOURCES) {
2647 //
2648 // If can't generate ConfigRequest for this question, skip it and start the next.
2649 //
2650 goto Error;
2651 }
2652 //
2653 // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
2654 //
2655 goto Done;
2656 }
2657
2658 //
2659 // Extract readonly flag from opcode.
2660 //
2661 ReadOnly = ExtractReadOnlyFromOpCode(OpCode);
2662
2663 //
2664 // 5. Generate KeywordResp string.
2665 //
2666 ASSERT (DevicePath != NULL);
2667 Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
2668 if (Status != EFI_SUCCESS) {
2669 //
2670 // If EFI_OUT_OF_RESOURCES error occur, no need to continue.
2671 //
2672 goto Done;
2673 }
2674
2675 //
2676 // 6. Merge to the MultiKeywordResp string.
2677 //
2678 Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
2679 if (EFI_ERROR (Status)) {
2680 goto Done;
2681 }
2682 Error:
2683 //
2684 // Clean the temp buffer to later use again.
2685 //
2686 if (ConfigRequest != NULL) {
2687 FreePool (ConfigRequest);
2688 ConfigRequest = NULL;
2689 }
2690 if (ValueElement != NULL) {
2691 FreePool (ValueElement);
2692 ValueElement = NULL;
2693 }
2694 if (KeywordResp != NULL) {
2695 FreePool (KeywordResp);
2696 KeywordResp = NULL;
2697 }
2698 }
2699
2700 if (LocalNameSpace != NULL) {
2701 FreePool (LocalNameSpace);
2702 LocalNameSpace = NULL;
2703 }
2704 }
2705 }
2706 }
2707
2708 //
2709 // return the already get MultiKeywordString even error occured.
2710 //
2711 if (MultiKeywordResp == NULL) {
2712 Status = EFI_NOT_FOUND;
2713 } else {
2714 Status = EFI_SUCCESS;
2715 }
2716 *MultiResp = MultiKeywordResp;
2717
2718 Done:
2719 if (LocalNameSpace != NULL) {
2720 FreePool (LocalNameSpace);
2721 }
2722 if (ConfigRequest != NULL) {
2723 FreePool (ConfigRequest);
2724 }
2725 if (ValueElement != NULL) {
2726 FreePool (ValueElement);
2727 }
2728
2729 return Status;
2730 }
2731
2732 /**
2733
2734 This function accepts a <MultiKeywordResp> formatted string, finds the associated
2735 keyword owners, creates a <MultiConfigResp> string from it and forwards it to the
2736 EFI_HII_ROUTING_PROTOCOL.RouteConfig function.
2737
2738 If there is an issue in resolving the contents of the KeywordString, then the
2739 function returns an error and also sets the Progress and ProgressErr with the
2740 appropriate information about where the issue occurred and additional data about
2741 the nature of the issue.
2742
2743 In the case when KeywordString containing multiple keywords, when an EFI_NOT_FOUND
2744 error is generated during processing the second or later keyword element, the system
2745 storage associated with earlier keywords is not modified. All elements of the
2746 KeywordString must successfully pass all tests for format and access prior to making
2747 any modifications to storage.
2748
2749 In the case when EFI_DEVICE_ERROR is returned from the processing of a KeywordString
2750 containing multiple keywords, the state of storage associated with earlier keywords
2751 is undefined.
2752
2753
2754 @param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
2755
2756 @param KeywordString A null-terminated string in <MultiKeywordResp> format.
2757
2758 @param Progress On return, points to a character in the KeywordString.
2759 Points to the string's NULL terminator if the request
2760 was successful. Points to the most recent '&' before
2761 the first failing string element if the request was
2762 not successful.
2763
2764 @param ProgressErr If during the processing of the KeywordString there was
2765 a failure, this parameter gives additional information
2766 about the possible source of the problem. The various
2767 errors are defined in "Related Definitions" below.
2768
2769
2770 @retval EFI_SUCCESS The specified action was completed successfully.
2771
2772 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
2773 1. KeywordString is NULL.
2774 2. Parsing of the KeywordString resulted in an
2775 error. See Progress and ProgressErr for more data.
2776
2777 @retval EFI_NOT_FOUND An element of the KeywordString was not found.
2778 See ProgressErr for more data.
2779
2780 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2781 See ProgressErr for more data.
2782
2783 @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr
2784 for more data.
2785
2786 @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
2787 for more data.
2788
2789 **/
2790 EFI_STATUS
2791 EFIAPI
2792 EfiConfigKeywordHandlerSetData (
2793 IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
2794 IN CONST EFI_STRING KeywordString,
2795 OUT EFI_STRING *Progress,
2796 OUT UINT32 *ProgressErr
2797 )
2798 {
2799 CHAR8 *NameSpace;
2800 EFI_STATUS Status;
2801 CHAR16 *StringPtr;
2802 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2803 CHAR16 *NextStringPtr;
2804 CHAR16 *KeywordData;
2805 EFI_STRING_ID KeywordStringId;
2806 UINT32 RetVal;
2807 HII_DATABASE_RECORD *DataBaseRecord;
2808 UINT8 *OpCode;
2809 CHAR16 *ConfigResp;
2810 CHAR16 *MultiConfigResp;
2811 CHAR16 *ValueElement;
2812 BOOLEAN ReadOnly;
2813 EFI_STRING InternalProgress;
2814
2815 if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) {
2816 return EFI_INVALID_PARAMETER;
2817 }
2818
2819 *Progress = KeywordString;
2820 *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
2821 Status = EFI_SUCCESS;
2822 StringPtr = KeywordString;
2823 MultiConfigResp = NULL;
2824 NameSpace = NULL;
2825 DevicePath = NULL;
2826 KeywordData = NULL;
2827 ValueElement = NULL;
2828 ConfigResp = NULL;
2829 KeywordStringId = 0;
2830
2831 while ((StringPtr != NULL) && (*StringPtr != L'\0')) {
2832 //
2833 // 1. Get NameSpace from NameSpaceId keyword.
2834 //
2835 Status = ExtractNameSpace (StringPtr, &NameSpace, &NextStringPtr);
2836 if (EFI_ERROR (Status)) {
2837 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
2838 return Status;
2839 }
2840 StringPtr = NextStringPtr;
2841
2842 //
2843 // 2. Get possible Device Path info from KeywordString.
2844 //
2845 Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
2846 if (EFI_ERROR (Status)) {
2847 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
2848 goto Done;
2849 }
2850 StringPtr = NextStringPtr;
2851
2852 //
2853 // 3. Extract keyword from the KeywordRequest string.
2854 //
2855 Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
2856 if (EFI_ERROR (Status)) {
2857 //
2858 // Can't find Keyword base on the input device path info.
2859 //
2860 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
2861 Status = EFI_INVALID_PARAMETER;
2862 goto Done;
2863 }
2864 StringPtr = NextStringPtr;
2865
2866 //
2867 // 4. Extract Value from the KeywordRequest string.
2868 //
2869 Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr);
2870 if (EFI_ERROR (Status)) {
2871 //
2872 // Can't find Value base on the input device path info.
2873 //
2874 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
2875 Status = EFI_INVALID_PARAMETER;
2876 goto Done;
2877 }
2878 StringPtr = NextStringPtr;
2879
2880 //
2881 // 5. Find ReadOnly filter.
2882 //
2883 if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&ReadOnly", StrLen (L"&ReadOnly")) == 0) {
2884 ReadOnly = TRUE;
2885 StringPtr += StrLen (L"&ReadOnly");
2886 } else {
2887 ReadOnly = FALSE;
2888 }
2889
2890 //
2891 // 6. Get EFI_STRING_ID for the input keyword.
2892 //
2893 Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
2894 if (EFI_ERROR (Status)) {
2895 *ProgressErr = RetVal;
2896 goto Done;
2897 }
2898
2899 //
2900 // 7. Construct the ConfigRequest string.
2901 //
2902 Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp);
2903 if (EFI_ERROR (Status)) {
2904 goto Done;
2905 }
2906
2907 //
2908 // 8. Check the readonly flag.
2909 //
2910 if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) {
2911 *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
2912 Status = EFI_INVALID_PARAMETER;
2913 goto Done;
2914 }
2915
2916 //
2917 // 9. Merge to the MultiKeywordResp string.
2918 //
2919 Status = MergeToMultiKeywordResp(&MultiConfigResp, &ConfigResp);
2920 if (EFI_ERROR (Status)) {
2921 goto Done;
2922 }
2923
2924 //
2925 // 10. Clean the temp buffer point.
2926 //
2927 FreePool (NameSpace);
2928 FreePool (DevicePath);
2929 FreePool (KeywordData);
2930 FreePool (ValueElement);
2931 NameSpace = NULL;
2932 DevicePath = NULL;
2933 KeywordData = NULL;
2934 ValueElement = NULL;
2935 if (ConfigResp != NULL) {
2936 FreePool (ConfigResp);
2937 ConfigResp = NULL;
2938 }
2939 }
2940
2941 //
2942 // 11. Set value to driver.
2943 //
2944 Status = mPrivate.ConfigRouting.RouteConfig(
2945 &mPrivate.ConfigRouting,
2946 (EFI_STRING) MultiConfigResp,
2947 &InternalProgress
2948 );
2949 if (EFI_ERROR (Status)) {
2950 Status = EFI_DEVICE_ERROR;
2951 goto Done;
2952 }
2953
2954 *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
2955
2956 Done:
2957 if (NameSpace != NULL) {
2958 FreePool (NameSpace);
2959 }
2960 if (DevicePath != NULL) {
2961 FreePool (DevicePath);
2962 }
2963 if (KeywordData != NULL) {
2964 FreePool (KeywordData);
2965 }
2966 if (ValueElement != NULL) {
2967 FreePool (ValueElement);
2968 }
2969 if (ConfigResp != NULL) {
2970 FreePool (ConfigResp);
2971 }
2972 if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) {
2973 FreePool (MultiConfigResp);
2974 }
2975 *Progress = StringPtr;
2976 return Status;
2977 }
2978
2979 /**
2980
2981 This function accepts a <MultiKeywordRequest> formatted string, finds the underlying
2982 keyword owners, creates a <MultiConfigRequest> string from it and forwards it to the
2983 EFI_HII_ROUTING_PROTOCOL.ExtractConfig function.
2984
2985 If there is an issue in resolving the contents of the KeywordString, then the function
2986 returns an EFI_INVALID_PARAMETER and also set the Progress and ProgressErr with the
2987 appropriate information about where the issue occurred and additional data about the
2988 nature of the issue.
2989
2990 In the case when KeywordString is NULL, or contains multiple keywords, or when
2991 EFI_NOT_FOUND is generated while processing the keyword elements, the Results string
2992 contains values returned for all keywords processed prior to the keyword generating the
2993 error but no values for the keyword with error or any following keywords.
2994
2995
2996 @param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
2997
2998 @param NameSpaceId A null-terminated string containing the platform configuration
2999 language to search through in the system. If a NULL is passed
3000 in, then it is assumed that any platform configuration language
3001 with the prefix of "x-UEFI-" are searched.
3002
3003 @param KeywordString A null-terminated string in <MultiKeywordRequest> format. If a
3004 NULL is passed in the KeywordString field, all of the known
3005 keywords in the system for the NameSpaceId specified are
3006 returned in the Results field.
3007
3008 @param Progress On return, points to a character in the KeywordString. Points
3009 to the string's NULL terminator if the request was successful.
3010 Points to the most recent '&' before the first failing string
3011 element if the request was not successful.
3012
3013 @param ProgressErr If during the processing of the KeywordString there was a
3014 failure, this parameter gives additional information about the
3015 possible source of the problem. See the definitions in SetData()
3016 for valid value definitions.
3017
3018 @param Results A null-terminated string in <MultiKeywordResp> format is returned
3019 which has all the values filled in for the keywords in the
3020 KeywordString. This is a callee-allocated field, and must be freed
3021 by the caller after being used.
3022
3023 @retval EFI_SUCCESS The specified action was completed successfully.
3024
3025 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
3026 1.Progress, ProgressErr, or Resuts is NULL.
3027 2.Parsing of the KeywordString resulted in an error. See
3028 Progress and ProgressErr for more data.
3029
3030
3031 @retval EFI_NOT_FOUND An element of the KeywordString was not found. See
3032 ProgressErr for more data.
3033
3034 @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr
3035 for more data.
3036
3037 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See
3038 ProgressErr for more data.
3039
3040 @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for
3041 more data.
3042
3043 @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
3044 for more data.
3045
3046 **/
3047 EFI_STATUS
3048 EFIAPI
3049 EfiConfigKeywordHandlerGetData (
3050 IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
3051 IN CONST EFI_STRING NameSpaceId, OPTIONAL
3052 IN CONST EFI_STRING KeywordString, OPTIONAL
3053 OUT EFI_STRING *Progress,
3054 OUT UINT32 *ProgressErr,
3055 OUT EFI_STRING *Results
3056 )
3057 {
3058 CHAR8 *NameSpace;
3059 EFI_STATUS Status;
3060 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
3061 HII_DATABASE_RECORD *DataBaseRecord;
3062 CHAR16 *StringPtr;
3063 CHAR16 *NextStringPtr;
3064 CHAR16 *KeywordData;
3065 EFI_STRING_ID KeywordStringId;
3066 UINT8 *OpCode;
3067 CHAR16 *ConfigRequest;
3068 CHAR16 *ValueElement;
3069 UINT32 RetVal;
3070 BOOLEAN ReadOnly;
3071 CHAR16 *KeywordResp;
3072 CHAR16 *MultiKeywordResp;
3073
3074 if (This == NULL || Progress == NULL || ProgressErr == NULL || Results == NULL) {
3075 return EFI_INVALID_PARAMETER;
3076 }
3077
3078 *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
3079 Status = EFI_SUCCESS;
3080 DevicePath = NULL;
3081 NameSpace = NULL;
3082 KeywordData = NULL;
3083 ConfigRequest= NULL;
3084 StringPtr = KeywordString;
3085 ReadOnly = FALSE;
3086 MultiKeywordResp = NULL;
3087 KeywordStringId = 0;
3088
3089 //
3090 // 1. Get NameSpace from NameSpaceId keyword.
3091 //
3092 Status = ExtractNameSpace (NameSpaceId, &NameSpace, NULL);
3093 if (EFI_ERROR (Status)) {
3094 *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
3095 return Status;
3096 }
3097
3098 if (KeywordString != NULL) {
3099 StringPtr = KeywordString;
3100
3101 while (*StringPtr != L'\0') {
3102 //
3103 // 2. Get possible Device Path info from KeywordString.
3104 //
3105 Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
3106 if (EFI_ERROR (Status)) {
3107 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
3108 goto Done;
3109 }
3110 StringPtr = NextStringPtr;
3111
3112
3113 //
3114 // 3. Process Keyword section from the input keywordRequest string.
3115 //
3116 // 3.1 Extract keyword from the KeywordRequest string.
3117 //
3118 Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
3119 if (EFI_ERROR (Status)) {
3120 //
3121 // Can't find Keyword base on the input device path info.
3122 //
3123 *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
3124 Status = EFI_INVALID_PARAMETER;
3125 goto Done;
3126 }
3127
3128 //
3129 // 3.2 Get EFI_STRING_ID for the input keyword.
3130 //
3131 Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
3132 if (EFI_ERROR (Status)) {
3133 *ProgressErr = RetVal;
3134 goto Done;
3135 }
3136
3137 //
3138 // 3.3 Construct the ConfigRequest string.
3139 //
3140 Status = ExtractConfigRequest (DataBaseRecord, KeywordStringId, &OpCode, &ConfigRequest);
3141 if (EFI_ERROR (Status)) {
3142 goto Done;
3143 }
3144
3145 //
3146 // 3.4 Extract Value for the input keyword.
3147 //
3148 Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
3149 if (EFI_ERROR (Status)) {
3150 if (Status != EFI_OUT_OF_RESOURCES) {
3151 Status = EFI_DEVICE_ERROR;
3152 }
3153 goto Done;
3154 }
3155 StringPtr = NextStringPtr;
3156
3157 //
3158 // 4. Process the possible filter section.
3159 //
3160 RetVal = ValidateFilter (OpCode, StringPtr, &NextStringPtr, &ReadOnly);
3161 if (RetVal != KEYWORD_HANDLER_NO_ERROR) {
3162 *ProgressErr = RetVal;
3163 Status = EFI_INVALID_PARAMETER;
3164 goto Done;
3165 }
3166 StringPtr = NextStringPtr;
3167
3168
3169 //
3170 // 5. Generate KeywordResp string.
3171 //
3172 Status = GenerateKeywordResp(NameSpace, DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
3173 if (Status != EFI_SUCCESS) {
3174 goto Done;
3175 }
3176
3177 //
3178 // 6. Merge to the MultiKeywordResp string.
3179 //
3180 Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
3181 if (EFI_ERROR (Status)) {
3182 goto Done;
3183 }
3184
3185 //
3186 // 7. Update return value.
3187 //
3188 *Results = MultiKeywordResp;
3189
3190 //
3191 // 8. Clean the temp buffer.
3192 //
3193 FreePool (DevicePath);
3194 FreePool (KeywordData);
3195 FreePool (ValueElement);
3196 FreePool (ConfigRequest);
3197 DevicePath = NULL;
3198 KeywordData = NULL;
3199 ValueElement = NULL;
3200 ConfigRequest = NULL;
3201 if (KeywordResp != NULL) {
3202 FreePool (KeywordResp);
3203 KeywordResp = NULL;
3204 }
3205 }
3206 } else {
3207 //
3208 // Enumerate all keyword in the system.
3209 //
3210 Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp);
3211 if (EFI_ERROR (Status)) {
3212 goto Done;
3213 }
3214 *Results = MultiKeywordResp;
3215 }
3216
3217 *ProgressErr = KEYWORD_HANDLER_NO_ERROR;
3218
3219 Done:
3220 if (NameSpace != NULL) {
3221 FreePool (NameSpace);
3222 }
3223 if (DevicePath != NULL) {
3224 FreePool (DevicePath);
3225 }
3226 if (KeywordData != NULL) {
3227 FreePool (KeywordData);
3228 }
3229 *Progress = StringPtr;
3230 return Status;
3231 }