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