blob: 4caf361bd22272cc51c0a3de82e9305cd0ef5ee4 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @file
2Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
3
4Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15
16#include "HiiDatabase.h"
17extern HII_DATABASE_PRIVATE_DATA mPrivate;
18
19/**
20 Calculate the number of Unicode characters of the incoming Configuration string,
21 not including NULL terminator.
22
23 This is a internal function.
24
25 @param String String in <MultiConfigRequest> or
26 <MultiConfigResp> format.
27
28 @return The number of Unicode characters.
29
30**/
31UINTN
32CalculateConfigStringLen (
33 IN EFI_STRING String
34 )
35{
36 EFI_STRING TmpPtr;
37
38 //
39 // "GUID=" should be the first element of incoming string.
40 //
41 ASSERT (String != NULL);
42 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
43
44 //
45 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
46 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
47 //
48 TmpPtr = StrStr (String, L"&GUID=");
49 if (TmpPtr == NULL) {
50 return StrLen (String);
51 }
52
53 return (TmpPtr - String);
54}
55
56
57/**
58 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
59 from <PathHdr> of <ConfigHdr>.
60
61 This is a internal function.
62
63 @param String UEFI configuration string
64 @param DevicePathData Binary of a UEFI device path.
65
66 @retval EFI_NOT_FOUND The device path is not invalid.
67 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
68 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
69 @retval EFI_SUCCESS The device path is retrieved and translated to
70 binary format.
71
72**/
73EFI_STATUS
74GetDevicePath (
75 IN EFI_STRING String,
76 OUT UINT8 **DevicePathData
77 )
78{
79 UINTN Length;
80 EFI_STRING PathHdr;
81 UINT8 *DevicePathBuffer;
82 CHAR16 TemStr[2];
83 UINTN Index;
84 UINT8 DigitUint8;
85 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
86
87
88 if (String == NULL || DevicePathData == NULL) {
89 return EFI_INVALID_PARAMETER;
90 }
91
92 //
93 // Find the 'PATH=' of <PathHdr> and skip it.
94 //
95 for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
96 if (*String == 0) {
97 return EFI_INVALID_PARAMETER;
98 }
99 //
100 // Check whether path data does exist.
101 //
102 String += StrLen (L"PATH=");
103 if (*String == 0) {
104 return EFI_INVALID_PARAMETER;
105 }
106 PathHdr = String;
107
108 //
109 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
110 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
111 // of UEFI device path.
112 //
113 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
114 //
115 // Check DevicePath Length
116 //
117 if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
118 return EFI_NOT_FOUND;
119 }
120
121 //
122 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
123 // as the device path resides in RAM memory.
124 // Translate the data into binary.
125 //
126 DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
127 if (DevicePathBuffer == NULL) {
128 return EFI_OUT_OF_RESOURCES;
129 }
130
131 //
132 // Convert DevicePath
133 //
134 ZeroMem (TemStr, sizeof (TemStr));
135 for (Index = 0; Index < Length; Index ++) {
136 TemStr[0] = PathHdr[Index];
137 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
138 if ((Index & 1) == 0) {
139 DevicePathBuffer [Index/2] = DigitUint8;
140 } else {
141 DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
142 }
143 }
144
145 //
146 // Validate DevicePath
147 //
148 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
149 while (!IsDevicePathEnd (DevicePath)) {
150 if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
151 //
152 // Invalid device path
153 //
154 FreePool (DevicePathBuffer);
155 return EFI_NOT_FOUND;
156 }
157 DevicePath = NextDevicePathNode (DevicePath);
158 }
159
160 //
161 // return the device path
162 //
163 *DevicePathData = DevicePathBuffer;
164 return EFI_SUCCESS;
165}
166
167/**
168 Converts the unicode character of the string from uppercase to lowercase.
169 This is a internal function.
170
171 @param ConfigString String to be converted
172
173**/
174VOID
175EFIAPI
176HiiToLower (
177 IN EFI_STRING ConfigString
178 )
179{
180 EFI_STRING String;
181 BOOLEAN Lower;
182
183 ASSERT (ConfigString != NULL);
184
185 //
186 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
187 //
188 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
189 if (*String == L'=') {
190 Lower = TRUE;
191 } else if (*String == L'&') {
192 Lower = FALSE;
193 } else if (Lower && *String >= L'A' && *String <= L'F') {
194 *String = (CHAR16) (*String - L'A' + L'a');
195 }
196 }
197
198 return;
199}
200
201/**
202 Generate a sub string then output it.
203
204 This is a internal function.
205
206 @param String A constant string which is the prefix of the to be
207 generated string, e.g. GUID=
208
209 @param BufferLen The length of the Buffer in bytes.
210
211 @param Buffer Points to a buffer which will be converted to be the
212 content of the generated string.
213
214 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
215 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
216 if 3, the buffer contains other data.
217
218 @param SubStr Points to the output string. It's caller's
219 responsibility to free this buffer.
220
221
222**/
223VOID
224GenerateSubStr (
225 IN CONST EFI_STRING String,
226 IN UINTN BufferLen,
227 IN VOID *Buffer,
228 IN UINT8 Flag,
229 OUT EFI_STRING *SubStr
230 )
231{
232 UINTN Length;
233 EFI_STRING Str;
234 EFI_STRING StringHeader;
235 CHAR16 *TemString;
236 CHAR16 *TemName;
237 UINT8 *TemBuffer;
238 UINTN Index;
239
240 ASSERT (String != NULL && SubStr != NULL);
241
242 if (Buffer == NULL) {
243 *SubStr = AllocateCopyPool (StrSize (String), String);
244 ASSERT (*SubStr != NULL);
245 return;
246 }
247
248 //
249 // Header + Data + '&' + '\0'
250 //
251 Length = StrLen (String) + BufferLen * 2 + 1 + 1;
252 Str = AllocateZeroPool (Length * sizeof (CHAR16));
253 ASSERT (Str != NULL);
254
255 StrCpy (Str, String);
256 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
257
258 StringHeader = Str + StrLen (String);
259 TemString = (CHAR16 *) StringHeader;
260
261 switch (Flag) {
262 case 1:
263 //
264 // Convert Buffer to Hex String in reverse order
265 //
266 TemBuffer = ((UINT8 *) Buffer);
267 for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) {
268 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
269 }
270 break;
271 case 2:
272 //
273 // Check buffer is enough
274 //
275 TemName = (CHAR16 *) Buffer;
276 ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1));
277 //
278 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
279 //
280 for (; *TemName != L'\0'; TemName++) {
281 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
282 }
283 break;
284 case 3:
285 //
286 // Convert Buffer to Hex String
287 //
288 TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1;
289 for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) {
290 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
291 }
292 break;
293 default:
294 break;
295 }
296
297 //
298 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
299 //
300 StrCat (Str, L"&");
301 HiiToLower (Str);
302
303 *SubStr = Str;
304}
305
306
307/**
308 Retrieve the <ConfigBody> from String then output it.
309
310 This is a internal function.
311
312 @param String A sub string of a configuration string in
313 <MultiConfigAltResp> format.
314 @param ConfigBody Points to the output string. It's caller's
315 responsibility to free this buffer.
316
317 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
318 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
319 @retval EFI_SUCCESS All existing storage is exported.
320
321**/
322EFI_STATUS
323OutputConfigBody (
324 IN EFI_STRING String,
325 OUT EFI_STRING *ConfigBody
326 )
327{
328 EFI_STRING TmpPtr;
329 EFI_STRING Result;
330 UINTN Length;
331
332 if (String == NULL || ConfigBody == NULL) {
333 return EFI_INVALID_PARAMETER;
334 }
335
336 //
337 // The setting information should start OFFSET, not ALTCFG.
338 //
339 if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) {
340 return EFI_INVALID_PARAMETER;
341 }
342
343 TmpPtr = StrStr (String, L"GUID=");
344 if (TmpPtr == NULL) {
345 //
346 // It is the last <ConfigResp> of the incoming configuration string.
347 //
348 Result = AllocateCopyPool (StrSize (String), String);
349 if (Result == NULL) {
350 return EFI_OUT_OF_RESOURCES;
351 } else {
352 *ConfigBody = Result;
353 return EFI_SUCCESS;
354 }
355 }
356
357 Length = TmpPtr - String;
358 if (Length == 0) {
359 return EFI_NOT_FOUND;
360 }
361 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
362 if (Result == NULL) {
363 return EFI_OUT_OF_RESOURCES;
364 }
365
366 *(Result + Length - 1) = 0;
367 *ConfigBody = Result;
368 return EFI_SUCCESS;
369}
370
371/**
372 Append a string to a multi-string format.
373
374 This is a internal function.
375
376 @param MultiString String in <MultiConfigRequest>,
377 <MultiConfigAltResp>, or <MultiConfigResp>. On
378 input, the buffer length of this string is
379 MAX_STRING_LENGTH. On output, the buffer length
380 might be updated.
381 @param AppendString NULL-terminated Unicode string.
382
383 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
384 @retval EFI_SUCCESS AppendString is append to the end of MultiString
385
386**/
387EFI_STATUS
388AppendToMultiString (
389 IN OUT EFI_STRING *MultiString,
390 IN EFI_STRING AppendString
391 )
392{
393 UINTN AppendStringSize;
394 UINTN MultiStringSize;
395
396 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
397 return EFI_INVALID_PARAMETER;
398 }
399
400 AppendStringSize = StrSize (AppendString);
401 MultiStringSize = StrSize (*MultiString);
402
403 //
404 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
405 //
406 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
407 MultiStringSize > MAX_STRING_LENGTH) {
408 *MultiString = (EFI_STRING) ReallocatePool (
409 MultiStringSize,
410 MultiStringSize + AppendStringSize,
411 (VOID *) (*MultiString)
412 );
413 ASSERT (*MultiString != NULL);
414 }
415 //
416 // Append the incoming string
417 //
418 StrCat (*MultiString, AppendString);
419
420 return EFI_SUCCESS;
421}
422
423
424/**
425 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
426 or WIDTH or VALUE.
427 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
428
429 This is a internal function.
430
431 @param StringPtr String in <BlockConfig> format and points to the
432 first character of <Number>.
433 @param Number The output value. Caller takes the responsibility
434 to free memory.
435 @param Len Length of the <Number>, in characters.
436
437 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
438 structures.
439 @retval EFI_SUCCESS Value of <Number> is outputted in Number
440 successfully.
441
442**/
443EFI_STATUS
444GetValueOfNumber (
445 IN EFI_STRING StringPtr,
446 OUT UINT8 **Number,
447 OUT UINTN *Len
448 )
449{
450 EFI_STRING TmpPtr;
451 UINTN Length;
452 EFI_STRING Str;
453 UINT8 *Buf;
454 EFI_STATUS Status;
455 UINT8 DigitUint8;
456 UINTN Index;
457 CHAR16 TemStr[2];
458
459 if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) {
460 return EFI_INVALID_PARAMETER;
461 }
462
463 Buf = NULL;
464
465 TmpPtr = StringPtr;
466 while (*StringPtr != L'\0' && *StringPtr != L'&') {
467 StringPtr++;
468 }
469 *Len = StringPtr - TmpPtr;
470 Length = *Len + 1;
471
472 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
473 if (Str == NULL) {
474 Status = EFI_OUT_OF_RESOURCES;
475 goto Exit;
476 }
477 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
478 *(Str + *Len) = L'\0';
479
480 Length = (Length + 1) / 2;
481 Buf = (UINT8 *) AllocateZeroPool (Length);
482 if (Buf == NULL) {
483 Status = EFI_OUT_OF_RESOURCES;
484 goto Exit;
485 }
486
487 Length = *Len;
488 ZeroMem (TemStr, sizeof (TemStr));
489 for (Index = 0; Index < Length; Index ++) {
490 TemStr[0] = Str[Length - Index - 1];
491 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
492 if ((Index & 1) == 0) {
493 Buf [Index/2] = DigitUint8;
494 } else {
495 Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
496 }
497 }
498
499 *Number = Buf;
500 Status = EFI_SUCCESS;
501
502Exit:
503 if (Str != NULL) {
504 FreePool (Str);
505 }
506
507 return Status;
508}
509
510/**
511 This function merges DefaultAltCfgResp string into AltCfgResp string for
512 the missing AltCfgId in AltCfgResq.
513
514 @param AltCfgResp Pointer to a null-terminated Unicode string in
515 <ConfigAltResp> format. The default value string
516 will be merged into it.
517 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
518 <MultiConfigAltResp> format. The default value
519 string may contain more than one ConfigAltResp
520 string for the different varstore buffer.
521
522 @retval EFI_SUCCESS The merged string returns.
523 @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.
524**/
525EFI_STATUS
526EFIAPI
527MergeDefaultString (
528 IN OUT EFI_STRING *AltCfgResp,
529 IN EFI_STRING DefaultAltCfgResp
530 )
531{
532 EFI_STRING StringPtrDefault;
533 EFI_STRING StringPtrEnd;
534 CHAR16 TempChar;
535 EFI_STRING StringPtr;
536 EFI_STRING AltConfigHdr;
537 UINTN HeaderLength;
538 UINTN SizeAltCfgResp;
539
540 if (*AltCfgResp == NULL) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 //
545 // Get the requestr ConfigHdr
546 //
547 SizeAltCfgResp = 0;
548 StringPtr = *AltCfgResp;
549
550 //
551 // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
552 //
553 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
554 return EFI_INVALID_PARAMETER;
555 }
556 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
557 StringPtr++;
558 }
559 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
560 StringPtr++;
561 }
562 if (*StringPtr == L'\0') {
563 return EFI_INVALID_PARAMETER;
564 }
565 StringPtr += StrLen (L"&PATH=");
566 while (*StringPtr != L'\0' && *StringPtr != L'&') {
567 StringPtr ++;
568 }
569 HeaderLength = StringPtr - *AltCfgResp;
570
571 //
572 // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"
573 // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
574 //
575 AltConfigHdr = AllocateZeroPool ((1 + HeaderLength + 8 + 4 + 1) * sizeof (CHAR16));
576 if (AltConfigHdr == NULL) {
577 return EFI_OUT_OF_RESOURCES;
578 }
579 StrCpy (AltConfigHdr, L"&");
580 StrnCat (AltConfigHdr, *AltCfgResp, HeaderLength);
581 StrCat (AltConfigHdr, L"&ALTCFG=");
582 HeaderLength = StrLen (AltConfigHdr);
583
584 StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
585 while (StringPtrDefault != NULL) {
586 //
587 // Get AltCfg Name
588 //
589 StrnCat (AltConfigHdr, StringPtrDefault + HeaderLength, 4);
590 StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
591
592 //
593 // Append the found default value string to the input AltCfgResp
594 //
595 if (StringPtr == NULL) {
596 StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");
597 SizeAltCfgResp = StrSize (*AltCfgResp);
598 if (StringPtrEnd == NULL) {
599 //
600 // No more default string is found.
601 //
602 *AltCfgResp = (EFI_STRING) ReallocatePool (
603 SizeAltCfgResp,
604 SizeAltCfgResp + StrSize (StringPtrDefault),
605 (VOID *) (*AltCfgResp)
606 );
607 if (*AltCfgResp == NULL) {
608 FreePool (AltConfigHdr);
609 return EFI_OUT_OF_RESOURCES;
610 }
611 StrCat (*AltCfgResp, StringPtrDefault);
612 break;
613 } else {
614 TempChar = *StringPtrEnd;
615 *StringPtrEnd = L'\0';
616 *AltCfgResp = (EFI_STRING) ReallocatePool (
617 SizeAltCfgResp,
618 SizeAltCfgResp + StrSize (StringPtrDefault),
619 (VOID *) (*AltCfgResp)
620 );
621 if (*AltCfgResp == NULL) {
622 FreePool (AltConfigHdr);
623 return EFI_OUT_OF_RESOURCES;
624 }
625 StrCat (*AltCfgResp, StringPtrDefault);
626 *StringPtrEnd = TempChar;
627 }
628 }
629
630 //
631 // Find next AltCfg String
632 //
633 *(AltConfigHdr + HeaderLength) = L'\0';
634 StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
635 }
636
637 FreePool (AltConfigHdr);
638 return EFI_SUCCESS;
639}
640
641/**
642 This function inserts new DefaultValueData into the BlockData DefaultValue array.
643
644 @param BlockData The BlockData is updated to add new default value.
645 @param DefaultValueData The DefaultValue is added.
646
647**/
648VOID
649InsertDefaultValue (
650 IN IFR_BLOCK_DATA *BlockData,
651 IN IFR_DEFAULT_DATA *DefaultValueData
652 )
653{
654 LIST_ENTRY *Link;
655 IFR_DEFAULT_DATA *DefaultValueArray;
656 LIST_ENTRY *DefaultLink;
657
658 DefaultLink = &BlockData->DefaultValueEntry;
659
660 for (Link = DefaultLink->ForwardLink; Link != DefaultLink; Link = Link->ForwardLink) {
661 DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
662 if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
663 //
664 // DEFAULT_VALUE_FROM_OPCODE has high priority, DEFAULT_VALUE_FROM_DEFAULT has low priority.
665 //
666 if (DefaultValueData->Type > DefaultValueArray->Type) {
667 //
668 // Update the default value array in BlockData.
669 //
670 CopyMem (&DefaultValueArray->Value, &DefaultValueData->Value, sizeof (EFI_IFR_TYPE_VALUE));
671 DefaultValueArray->Type = DefaultValueData->Type;
672 DefaultValueArray->Cleaned = DefaultValueData->Cleaned;
673 }
674 return;
675 }
676 }
677
678 //
679 // Insert new default value data in tail.
680 //
681 DefaultValueArray = AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
682 ASSERT (DefaultValueArray != NULL);
683 CopyMem (DefaultValueArray, DefaultValueData, sizeof (IFR_DEFAULT_DATA));
684 InsertTailList (Link, &DefaultValueArray->Entry);
685}
686
687/**
688 This function inserts new BlockData into the block link
689
690 @param BlockLink The list entry points to block array.
691 @param BlockData The point to BlockData is added.
692
693**/
694VOID
695InsertBlockData (
696 IN LIST_ENTRY *BlockLink,
697 IN IFR_BLOCK_DATA **BlockData
698 )
699{
700 LIST_ENTRY *Link;
701 IFR_BLOCK_DATA *BlockArray;
702 IFR_BLOCK_DATA *BlockSingleData;
703
704 BlockSingleData = *BlockData;
705
706 if (BlockSingleData->Name != NULL) {
707 InsertTailList (BlockLink, &BlockSingleData->Entry);
708 return;
709 }
710
711 //
712 // Insert block data in its Offset and Width order.
713 //
714 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
715 BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
716 if (BlockArray->Offset == BlockSingleData->Offset) {
717 if (BlockArray->Width > BlockSingleData->Width) {
718 //
719 // Insert this block data in the front of block array
720 //
721 InsertTailList (Link, &BlockSingleData->Entry);
722 return;
723 }
724
725 if (BlockArray->Width == BlockSingleData->Width) {
726 //
727 // The same block array has been added.
728 //
729 if (BlockSingleData != BlockArray) {
730 FreePool (BlockSingleData);
731 *BlockData = BlockArray;
732 }
733 return;
734 }
735 } else if (BlockArray->Offset > BlockSingleData->Offset) {
736 //
737 // Insert new block data in the front of block array
738 //
739 InsertTailList (Link, &BlockSingleData->Entry);
740 return;
741 }
742 }
743
744 //
745 // Add new block data into the tail.
746 //
747 InsertTailList (Link, &BlockSingleData->Entry);
748}
749
750/**
751 Retrieves a pointer to the a Null-terminated ASCII string containing the list
752 of languages that an HII handle in the HII Database supports. The returned
753 string is allocated using AllocatePool(). The caller is responsible for freeing
754 the returned string using FreePool(). The format of the returned string follows
755 the language format assumed the HII Database.
756
757 If HiiHandle is NULL, then ASSERT().
758
759 @param[in] HiiHandle A handle that was previously registered in the HII Database.
760
761 @retval NULL HiiHandle is not registered in the HII database
762 @retval NULL There are not enough resources available to retrieve the suported
763 languages.
764 @retval NULL The list of suported languages could not be retrieved.
765 @retval Other A pointer to the Null-terminated ASCII string of supported languages.
766
767**/
768CHAR8 *
769GetSupportedLanguages (
770 IN EFI_HII_HANDLE HiiHandle
771 )
772{
773 EFI_STATUS Status;
774 UINTN LanguageSize;
775 CHAR8 TempSupportedLanguages;
776 CHAR8 *SupportedLanguages;
777
778 ASSERT (HiiHandle != NULL);
779
780 //
781 // Retrieve the size required for the supported languages buffer.
782 //
783 LanguageSize = 0;
784 Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize);
785
786 //
787 // If GetLanguages() returns EFI_SUCCESS for a zero size,
788 // then there are no supported languages registered for HiiHandle. If GetLanguages()
789 // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
790 // in the HII Database
791 //
792 if (Status != EFI_BUFFER_TOO_SMALL) {
793 //
794 // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database
795 //
796 return NULL;
797 }
798
799 //
800 // Allocate the supported languages buffer.
801 //
802 SupportedLanguages = AllocateZeroPool (LanguageSize);
803 if (SupportedLanguages == NULL) {
804 //
805 // Return NULL if allocation fails.
806 //
807 return NULL;
808 }
809
810 //
811 // Retrieve the supported languages string
812 //
813 Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, SupportedLanguages, &LanguageSize);
814 if (EFI_ERROR (Status)) {
815 //
816 // Free the buffer and return NULL if the supported languages can not be retrieved.
817 //
818 FreePool (SupportedLanguages);
819 return NULL;
820 }
821
822 //
823 // Return the Null-terminated ASCII string of supported languages
824 //
825 return SupportedLanguages;
826}
827
828/**
829 Retrieves a string from a string package.
830
831 If HiiHandle is NULL, then ASSERT().
832 If StringId is 0, then ASSET.
833
834 @param[in] HiiHandle A handle that was previously registered in the HII Database.
835 @param[in] StringId The identifier of the string to retrieved from the string
836 package associated with HiiHandle.
837
838 @retval NULL The string specified by StringId is not present in the string package.
839 @retval Other The string was returned.
840
841**/
842EFI_STRING
843InternalGetString (
844 IN EFI_HII_HANDLE HiiHandle,
845 IN EFI_STRING_ID StringId
846 )
847{
848 EFI_STATUS Status;
849 UINTN StringSize;
850 CHAR16 TempString;
851 EFI_STRING String;
852 CHAR8 *SupportedLanguages;
853 CHAR8 *PlatformLanguage;
854 CHAR8 *BestLanguage;
855 CHAR8 *Language;
856
857 ASSERT (HiiHandle != NULL);
858 ASSERT (StringId != 0);
859
860 //
861 // Initialize all allocated buffers to NULL
862 //
863 SupportedLanguages = NULL;
864 PlatformLanguage = NULL;
865 BestLanguage = NULL;
866 String = NULL;
867 Language = "";
868
869 //
870 // Get the languages that the package specified by HiiHandle supports
871 //
872 SupportedLanguages = GetSupportedLanguages (HiiHandle);
873 if (SupportedLanguages == NULL) {
874 goto Error;
875 }
876
877 //
878 // Get the current platform language setting
879 //
880 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
881
882 //
883 // Get the best matching language from SupportedLanguages
884 //
885 BestLanguage = GetBestLanguage (
886 SupportedLanguages,
887 FALSE, // RFC 4646 mode
888 Language, // Highest priority
889 PlatformLanguage != NULL ? PlatformLanguage : "", // Next highest priority
890 SupportedLanguages, // Lowest priority
891 NULL
892 );
893 if (BestLanguage == NULL) {
894 goto Error;
895 }
896
897 //
898 // Retrieve the size of the string in the string package for the BestLanguage
899 //
900 StringSize = 0;
901 Status = mPrivate.HiiString.GetString (
902 &mPrivate.HiiString,
903 BestLanguage,
904 HiiHandle,
905 StringId,
906 &TempString,
907 &StringSize,
908 NULL
909 );
910 //
911 // If GetString() returns EFI_SUCCESS for a zero size,
912 // then there are no supported languages registered for HiiHandle. If GetString()
913 // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
914 // in the HII Database
915 //
916 if (Status != EFI_BUFFER_TOO_SMALL) {
917 goto Error;
918 }
919
920 //
921 // Allocate a buffer for the return string
922 //
923 String = AllocateZeroPool (StringSize);
924 if (String == NULL) {
925 goto Error;
926 }
927
928 //
929 // Retrieve the string from the string package
930 //
931 Status = mPrivate.HiiString.GetString (
932 &mPrivate.HiiString,
933 BestLanguage,
934 HiiHandle,
935 StringId,
936 String,
937 &StringSize,
938 NULL
939 );
940 if (EFI_ERROR (Status)) {
941 //
942 // Free the buffer and return NULL if the supported languages can not be retrieved.
943 //
944 FreePool (String);
945 String = NULL;
946 }
947
948Error:
949 //
950 // Free allocated buffers
951 //
952 if (SupportedLanguages != NULL) {
953 FreePool (SupportedLanguages);
954 }
955 if (PlatformLanguage != NULL) {
956 FreePool (PlatformLanguage);
957 }
958 if (BestLanguage != NULL) {
959 FreePool (BestLanguage);
960 }
961
962 //
963 // Return the Null-terminated Unicode string
964 //
965 return String;
966}
967
968/**
969 This function checks VarOffset and VarWidth is in the block range.
970
971 @param RequestBlockArray The block array is to be checked.
972 @param VarOffset Offset of var to the structure
973 @param VarWidth Width of var.
974 @param IsNameValueType Whether this varstore is name/value varstore or not.
975 @param HiiHandle Hii handle for this hii package.
976
977 @retval TRUE This Var is in the block range.
978 @retval FALSE This Var is not in the block range.
979**/
980BOOLEAN
981BlockArrayCheck (
982 IN IFR_BLOCK_DATA *RequestBlockArray,
983 IN UINT16 VarOffset,
984 IN UINT16 VarWidth,
985 IN BOOLEAN IsNameValueType,
986 IN EFI_HII_HANDLE HiiHandle
987 )
988{
989 LIST_ENTRY *Link;
990 IFR_BLOCK_DATA *BlockData;
991 EFI_STRING Name;
992
993 //
994 // No Request Block array, all vars are got.
995 //
996 if (RequestBlockArray == NULL) {
997 return TRUE;
998 }
999
1000 //
1001 // Check the input var is in the request block range.
1002 //
1003 for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
1004 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1005
1006 if (IsNameValueType) {
1007 Name = InternalGetString (HiiHandle, VarOffset);
1008 ASSERT (Name != NULL);
1009
1010 if (StrnCmp (BlockData->Name, Name, StrLen (Name)) == 0) {
1011 FreePool (Name);
1012 return TRUE;
1013 }
1014 FreePool (Name);
1015 } else {
1016 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
1017 return TRUE;
1018 }
1019 }
1020 }
1021
1022 return FALSE;
1023}
1024
1025/**
1026 Get form package data from data base.
1027
1028 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1029 @param HiiFormPackage The buffer saves the package data.
1030 @param PackageSize The buffer size of the package data.
1031
1032**/
1033EFI_STATUS
1034GetFormPackageData (
1035 IN HII_DATABASE_RECORD *DataBaseRecord,
1036 IN OUT UINT8 **HiiFormPackage,
1037 OUT UINTN *PackageSize
1038 )
1039{
1040 EFI_STATUS Status;
1041 UINTN Size;
1042 UINTN ResultSize;
1043
1044 if (DataBaseRecord == NULL || HiiFormPackage == NULL || PackageSize == NULL) {
1045 return EFI_INVALID_PARAMETER;
1046 }
1047
1048 Size = 0;
1049 ResultSize = 0;
1050 //
1051 // 0. Get Hii Form Package by HiiHandle
1052 //
1053 Status = ExportFormPackages (
1054 &mPrivate,
1055 DataBaseRecord->Handle,
1056 DataBaseRecord->PackageList,
1057 0,
1058 Size,
1059 HiiFormPackage,
1060 &ResultSize
1061 );
1062 if (EFI_ERROR (Status)) {
1063 return Status;
1064 }
1065
1066 (*HiiFormPackage) = AllocatePool (ResultSize);
1067 if (*HiiFormPackage == NULL) {
1068 Status = EFI_OUT_OF_RESOURCES;
1069 return Status;
1070 }
1071
1072 //
1073 // Get HiiFormPackage by HiiHandle
1074 //
1075 Size = ResultSize;
1076 ResultSize = 0;
1077 Status = ExportFormPackages (
1078 &mPrivate,
1079 DataBaseRecord->Handle,
1080 DataBaseRecord->PackageList,
1081 0,
1082 Size,
1083 *HiiFormPackage,
1084 &ResultSize
1085 );
1086 if (EFI_ERROR (Status)) {
1087 FreePool (*HiiFormPackage);
1088 }
1089
1090 *PackageSize = Size;
1091
1092 return Status;
1093}
1094
1095
1096/**
1097 This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
1098
1099 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1100 @param ConfigHdr Request string ConfigHdr. If it is NULL,
1101 the first found varstore will be as ConfigHdr.
1102 @param IsEfiVarstore Whether the request storage type is efi varstore type.
1103 @param EfiVarStore The efi varstore info which will return.
1104**/
1105EFI_STATUS
1106GetVarStoreType (
1107 IN HII_DATABASE_RECORD *DataBaseRecord,
1108 IN EFI_STRING ConfigHdr,
1109 OUT BOOLEAN *IsEfiVarstore,
1110 OUT EFI_IFR_VARSTORE_EFI **EfiVarStore
1111 )
1112{
1113 EFI_STATUS Status;
1114 UINTN IfrOffset;
1115 UINTN PackageOffset;
1116 EFI_IFR_OP_HEADER *IfrOpHdr;
1117 CHAR16 *VarStoreName;
1118 EFI_STRING GuidStr;
1119 EFI_STRING NameStr;
1120 EFI_STRING TempStr;
1121 UINTN LengthString;
1122 UINT8 *HiiFormPackage;
1123 UINTN PackageSize;
1124 EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
1125 EFI_HII_PACKAGE_HEADER *PackageHeader;
1126
1127 HiiFormPackage = NULL;
1128 LengthString = 0;
1129 Status = EFI_SUCCESS;
1130 GuidStr = NULL;
1131 NameStr = NULL;
1132 TempStr = NULL;
1133 *IsEfiVarstore = FALSE;
1134
1135 Status = GetFormPackageData(DataBaseRecord, &HiiFormPackage, &PackageSize);
1136 if (EFI_ERROR (Status)) {
1137 return Status;
1138 }
1139
1140 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1141 PackageOffset = IfrOffset;
1142 PackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiFormPackage;
1143
1144 while (IfrOffset < PackageSize) {
1145 //
1146 // More than one form packages exist.
1147 //
1148 if (PackageOffset >= PackageHeader->Length) {
1149 //
1150 // Process the new form package.
1151 //
1152 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1153 IfrOffset += PackageOffset;
1154 PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiFormPackage + IfrOffset);
1155 }
1156
1157 IfrOpHdr = (EFI_IFR_OP_HEADER *) (HiiFormPackage + IfrOffset);
1158 IfrOffset += IfrOpHdr->Length;
1159 PackageOffset += IfrOpHdr->Length;
1160
1161 if (IfrOpHdr->OpCode == EFI_IFR_VARSTORE_EFI_OP ) {
1162 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1163 //
1164 // If the length is small than the structure, this is from old efi
1165 // varstore definition. Old efi varstore get config directly from
1166 // GetVariable function.
1167 //
1168 if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
1169 continue;
1170 }
1171
1172 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
1173 if (VarStoreName == NULL) {
1174 Status = EFI_OUT_OF_RESOURCES;
1175 goto Done;
1176 }
1177 AsciiStrToUnicodeStr ((CHAR8 *) IfrEfiVarStore->Name, VarStoreName);
1178
1179 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrEfiVarStore->Guid, 1, &GuidStr);
1180 GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);
1181 LengthString = StrLen (GuidStr);
1182 LengthString = LengthString + StrLen (NameStr) + 1;
1183 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
1184 if (TempStr == NULL) {
1185 FreePool (GuidStr);
1186 FreePool (NameStr);
1187 FreePool (VarStoreName);
1188 Status = EFI_OUT_OF_RESOURCES;
1189 goto Done;
1190 }
1191 StrCpy (TempStr, GuidStr);
1192 StrCat (TempStr, NameStr);
1193 if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
1194 *EfiVarStore = (EFI_IFR_VARSTORE_EFI *) AllocateZeroPool (IfrOpHdr->Length);
1195 if (*EfiVarStore == NULL) {
1196 FreePool (VarStoreName);
1197 FreePool (GuidStr);
1198 FreePool (NameStr);
1199 FreePool (TempStr);
1200 Status = EFI_OUT_OF_RESOURCES;
1201 goto Done;
1202 }
1203 *IsEfiVarstore = TRUE;
1204 CopyMem (*EfiVarStore, IfrEfiVarStore, IfrOpHdr->Length);
1205 }
1206
1207 //
1208 // Free alllocated temp string.
1209 //
1210 FreePool (VarStoreName);
1211 FreePool (GuidStr);
1212 FreePool (NameStr);
1213 FreePool (TempStr);
1214
1215 //
1216 // Already found the varstore, break;
1217 //
1218 if (*IsEfiVarstore) {
1219 break;
1220 }
1221 }
1222 }
1223Done:
1224 if (HiiFormPackage != NULL) {
1225 FreePool (HiiFormPackage);
1226 }
1227
1228 return Status;
1229}
1230
1231/**
1232 Check whether the ConfigRequest string has the request elements.
1233 For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
1234 For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
1235
1236 @param ConfigRequest The input config request string.
1237
1238 @retval TRUE The input include config request elements.
1239 @retval FALSE The input string not includes.
1240
1241**/
1242BOOLEAN
1243GetElementsFromRequest (
1244 IN EFI_STRING ConfigRequest
1245 )
1246{
1247 EFI_STRING TmpRequest;
1248
1249 TmpRequest = StrStr (ConfigRequest, L"PATH=");
1250 ASSERT (TmpRequest != NULL);
1251
1252 if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
1253 return TRUE;
1254 }
1255
1256 return FALSE;
1257}
1258
1259/**
1260 Check whether the this varstore is the request varstore.
1261
1262 @param VarstoreGuid Varstore guid.
1263 @param Name Varstore name.
1264 @param ConfigHdr Current configRequest info.
1265
1266 @retval TRUE This varstore is the requst one.
1267 @retval FALSE This varstore is not the requst one.
1268
1269**/
1270BOOLEAN
1271IsThisVarstore (
1272 IN EFI_GUID *VarstoreGuid,
1273 IN CHAR16 *Name,
1274 IN CHAR16 *ConfigHdr
1275 )
1276{
1277 EFI_STRING GuidStr;
1278 EFI_STRING NameStr;
1279 EFI_STRING TempStr;
1280 UINTN LengthString;
1281 BOOLEAN RetVal;
1282
1283 RetVal = FALSE;
1284 GuidStr = NULL;
1285 TempStr = NULL;
1286
1287 //
1288 // If ConfigHdr has name field and varstore not has name, return FALSE.
1289 //
1290 if (Name == NULL && ConfigHdr != NULL && StrStr (ConfigHdr, L"NAME=&") == NULL) {
1291 return FALSE;
1292 }
1293
1294 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)VarstoreGuid, 1, &GuidStr);
1295 if (Name != NULL) {
1296 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
1297 } else {
1298 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1299 }
1300 LengthString = StrLen (GuidStr);
1301 LengthString = LengthString + StrLen (NameStr) + 1;
1302 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
1303 if (TempStr == NULL) {
1304 goto Done;
1305 }
1306
1307 StrCpy (TempStr, GuidStr);
1308 StrCat (TempStr, NameStr);
1309
1310 if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
1311 RetVal = TRUE;
1312 }
1313
1314Done:
1315 if (GuidStr != NULL) {
1316 FreePool (GuidStr);
1317 }
1318
1319 if (NameStr != NULL) {
1320 FreePool (NameStr);
1321 }
1322
1323 if (TempStr != NULL) {
1324 FreePool (TempStr);
1325 }
1326
1327 return RetVal;
1328}
1329
1330/**
1331 This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
1332
1333 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1334 @param ConfigHdr Request string ConfigHdr. If it is NULL,
1335 the first found varstore will be as ConfigHdr.
1336 @retval TRUE This hii package is the reqeust one.
1337 @retval FALSE This hii package is not the reqeust one.
1338**/
1339BOOLEAN
1340IsThisPackageList (
1341 IN HII_DATABASE_RECORD *DataBaseRecord,
1342 IN EFI_STRING ConfigHdr
1343 )
1344{
1345 EFI_STATUS Status;
1346 UINTN IfrOffset;
1347 UINTN PackageOffset;
1348 EFI_IFR_OP_HEADER *IfrOpHdr;
1349 CHAR16 *VarStoreName;
1350 UINT8 *HiiFormPackage;
1351 UINTN PackageSize;
1352 EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
1353 EFI_HII_PACKAGE_HEADER *PackageHeader;
1354 EFI_IFR_VARSTORE *IfrVarStore;
1355 EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
1356 BOOLEAN FindVarstore;
1357
1358 HiiFormPackage = NULL;
1359 VarStoreName = NULL;
1360 Status = EFI_SUCCESS;
1361 FindVarstore = FALSE;
1362
1363 Status = GetFormPackageData(DataBaseRecord, &HiiFormPackage, &PackageSize);
1364 if (EFI_ERROR (Status)) {
1365 return FALSE;
1366 }
1367
1368 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1369 PackageOffset = IfrOffset;
1370 PackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiFormPackage;
1371
1372 while (IfrOffset < PackageSize) {
1373 //
1374 // More than one form packages exist.
1375 //
1376 if (PackageOffset >= PackageHeader->Length) {
1377 //
1378 // Process the new form package.
1379 //
1380 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1381 IfrOffset += PackageOffset;
1382 PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiFormPackage + IfrOffset);
1383 }
1384
1385 IfrOpHdr = (EFI_IFR_OP_HEADER *) (HiiFormPackage + IfrOffset);
1386 IfrOffset += IfrOpHdr->Length;
1387 PackageOffset += IfrOpHdr->Length;
1388
1389 switch (IfrOpHdr->OpCode) {
1390
1391 case EFI_IFR_VARSTORE_OP:
1392 IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
1393
1394 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
1395 if (VarStoreName == NULL) {
1396 goto Done;
1397 }
1398 AsciiStrToUnicodeStr ((CHAR8 *)IfrVarStore->Name, VarStoreName);
1399
1400 if (IsThisVarstore((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
1401 FindVarstore = TRUE;
1402 goto Done;
1403 }
1404 break;
1405
1406 case EFI_IFR_VARSTORE_EFI_OP:
1407 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1408 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
1409 if (VarStoreName == NULL) {
1410 goto Done;
1411 }
1412 AsciiStrToUnicodeStr ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName);
1413
1414 if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
1415 FindVarstore = TRUE;
1416 goto Done;
1417 }
1418 break;
1419
1420 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1421 IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
1422
1423 if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
1424 FindVarstore = TRUE;
1425 goto Done;
1426 }
1427 break;
1428
1429 case EFI_IFR_FORM_OP:
1430 case EFI_IFR_FORM_MAP_OP:
1431 //
1432 // No matched varstore is found and directly return.
1433 //
1434 goto Done;
1435
1436 default:
1437 break;
1438 }
1439 }
1440Done:
1441 if (HiiFormPackage != NULL) {
1442 FreePool (HiiFormPackage);
1443 }
1444
1445 if (VarStoreName != NULL) {
1446 FreePool (VarStoreName);
1447 }
1448
1449 return FindVarstore;
1450}
1451
1452/**
1453 Check whether the this op code is required.
1454
1455 @param RequestBlockArray The array includes all the request info or NULL.
1456 @param HiiHandle The hii handle for this form package.
1457 @param VarStorageData The varstore data strucure.
1458 @param IfrOpHdr Ifr opcode header for this opcode.
1459 @param VarWidth The buffer width for this opcode.
1460 @param ReturnData The data block added for this opcode.
1461
1462 @retval EFI_SUCCESS This opcode is required.
1463 @retval Others This opcode is not required or error occur.
1464
1465**/
1466EFI_STATUS
1467IsThisOpcodeRequired (
1468 IN IFR_BLOCK_DATA *RequestBlockArray,
1469 IN EFI_HII_HANDLE HiiHandle,
1470 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
1471 IN EFI_IFR_OP_HEADER *IfrOpHdr,
1472 IN UINT16 VarWidth,
1473 OUT IFR_BLOCK_DATA **ReturnData
1474 )
1475{
1476 IFR_BLOCK_DATA *BlockData;
1477 UINT16 VarOffset;
1478 EFI_STRING_ID NameId;
1479 EFI_IFR_QUESTION_HEADER *IfrQuestionHdr;
1480
1481 NameId = 0;
1482 VarOffset = 0;
1483 IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *)((CHAR8 *) IfrOpHdr + sizeof (EFI_IFR_OP_HEADER));
1484
1485 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
1486 NameId = IfrQuestionHdr->VarStoreInfo.VarName;
1487
1488 //
1489 // Check whether this question is in requested block array.
1490 //
1491 if (!BlockArrayCheck (RequestBlockArray, NameId, 0, TRUE, HiiHandle)) {
1492 //
1493 // This question is not in the requested string. Skip it.
1494 //
1495 return EFI_SUCCESS;
1496 }
1497 } else {
1498 VarOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
1499
1500 //
1501 // Check whether this question is in requested block array.
1502 //
1503 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth, FALSE, HiiHandle)) {
1504 //
1505 // This question is not in the requested string. Skip it.
1506 //
1507 return EFI_SUCCESS;
1508 }
1509
1510 //
1511 // Check this var question is in the var storage
1512 //
1513 if (((VarOffset + VarWidth) > VarStorageData->Size)) {
1514 return EFI_INVALID_PARAMETER;
1515 }
1516 }
1517
1518 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1519 if (BlockData == NULL) {
1520 return EFI_OUT_OF_RESOURCES;
1521 }
1522
1523 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
1524 BlockData->Name = InternalGetString(HiiHandle, NameId);
1525 } else {
1526 BlockData->Offset = VarOffset;
1527 }
1528
1529 BlockData->Width = VarWidth;
1530 BlockData->QuestionId = IfrQuestionHdr->QuestionId;
1531 BlockData->OpCode = IfrOpHdr->OpCode;
1532 BlockData->Scope = IfrOpHdr->Scope;
1533 InitializeListHead (&BlockData->DefaultValueEntry);
1534 //
1535 // Add Block Data into VarStorageData BlockEntry
1536 //
1537 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1538 *ReturnData = BlockData;
1539
1540 return EFI_SUCCESS;
1541}
1542
1543/**
1544 This function parses Form Package to get the block array and the default
1545 value array according to the request ConfigHdr.
1546
1547 @param HiiHandle Hii Handle for this hii package.
1548 @param Package Pointer to the form package data.
1549 @param PackageLength Length of the pacakge.
1550 @param ConfigHdr Request string ConfigHdr. If it is NULL,
1551 the first found varstore will be as ConfigHdr.
1552 @param RequestBlockArray The block array is retrieved from the request string.
1553 @param VarStorageData VarStorage structure contains the got block and default value.
1554 @param DefaultIdArray Point to the got default id and default name array.
1555
1556 @retval EFI_SUCCESS The block array and the default value array are got.
1557 @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges
1558 are conflicted.
1559 @retval EFI_OUT_OF_RESOURCES No enough memory.
1560**/
1561EFI_STATUS
1562EFIAPI
1563ParseIfrData (
1564 IN EFI_HII_HANDLE HiiHandle,
1565 IN UINT8 *Package,
1566 IN UINT32 PackageLength,
1567 IN EFI_STRING ConfigHdr,
1568 IN IFR_BLOCK_DATA *RequestBlockArray,
1569 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
1570 OUT IFR_DEFAULT_DATA *DefaultIdArray
1571 )
1572{
1573 EFI_STATUS Status;
1574 UINTN IfrOffset;
1575 UINTN PackageOffset;
1576 EFI_IFR_VARSTORE *IfrVarStore;
1577 EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
1578 EFI_IFR_OP_HEADER *IfrOpHdr;
1579 EFI_IFR_ONE_OF *IfrOneOf;
1580 EFI_IFR_REF4 *IfrRef;
1581 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
1582 EFI_IFR_DEFAULT *IfrDefault;
1583 EFI_IFR_ORDERED_LIST *IfrOrderedList;
1584 EFI_IFR_CHECKBOX *IfrCheckBox;
1585 EFI_IFR_PASSWORD *IfrPassword;
1586 EFI_IFR_STRING *IfrString;
1587 EFI_IFR_DATE *IfrDate;
1588 EFI_IFR_TIME *IfrTime;
1589 IFR_DEFAULT_DATA DefaultData;
1590 IFR_DEFAULT_DATA *DefaultDataPtr;
1591 IFR_BLOCK_DATA *BlockData;
1592 CHAR16 *VarStoreName;
1593 UINT16 VarWidth;
1594 UINT16 VarDefaultId;
1595 BOOLEAN FirstOneOfOption;
1596 LIST_ENTRY *LinkData;
1597 LIST_ENTRY *LinkDefault;
1598 EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
1599 EFI_HII_PACKAGE_HEADER *PackageHeader;
1600 EFI_VARSTORE_ID VarStoreId;
1601
1602 Status = EFI_SUCCESS;
1603 BlockData = NULL;
1604 DefaultDataPtr = NULL;
1605 FirstOneOfOption = FALSE;
1606 VarStoreId = 0;
1607 ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA));
1608
1609 //
1610 // Go through the form package to parse OpCode one by one.
1611 //
1612 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1613 PackageHeader = (EFI_HII_PACKAGE_HEADER *) Package;
1614 IfrOffset = PackageOffset;
1615 while (IfrOffset < PackageLength) {
1616
1617 //
1618 // More than one form package found.
1619 //
1620 if (PackageOffset >= PackageHeader->Length) {
1621 //
1622 // Already found varstore for this request, break;
1623 //
1624 if (VarStoreId != 0) {
1625 VarStoreId = 0;
1626 }
1627
1628 //
1629 // Get next package header info.
1630 //
1631 IfrOffset += sizeof (EFI_HII_PACKAGE_HEADER);
1632 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1633 PackageHeader = (EFI_HII_PACKAGE_HEADER *) (Package + IfrOffset);
1634 }
1635
1636 IfrOpHdr = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);
1637 switch (IfrOpHdr->OpCode) {
1638 case EFI_IFR_VARSTORE_OP:
1639 //
1640 // VarStore is found. Don't need to search any more.
1641 //
1642 if (VarStoreId != 0) {
1643 break;
1644 }
1645
1646 IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
1647
1648 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
1649 if (VarStoreName == NULL) {
1650 Status = EFI_OUT_OF_RESOURCES;
1651 goto Done;
1652 }
1653 AsciiStrToUnicodeStr ((CHAR8 *)IfrVarStore->Name, VarStoreName);
1654
1655 if (IsThisVarstore((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
1656 //
1657 // Find the matched VarStore
1658 //
1659 CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);
1660 VarStorageData->Size = IfrVarStore->Size;
1661 VarStorageData->Name = VarStoreName;
1662 VarStorageData->Type = EFI_HII_VARSTORE_BUFFER;
1663 VarStoreId = IfrVarStore->VarStoreId;
1664 }
1665 break;
1666
1667 case EFI_IFR_VARSTORE_EFI_OP:
1668 //
1669 // VarStore is found. Don't need to search any more.
1670 //
1671 if (VarStoreId != 0) {
1672 break;
1673 }
1674
1675 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1676
1677 //
1678 // If the length is small than the structure, this is from old efi
1679 // varstore definition. Old efi varstore get config directly from
1680 // GetVariable function.
1681 //
1682 if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
1683 break;
1684 }
1685
1686 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
1687 if (VarStoreName == NULL) {
1688 Status = EFI_OUT_OF_RESOURCES;
1689 goto Done;
1690 }
1691 AsciiStrToUnicodeStr ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName);
1692
1693 if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
1694 //
1695 // Find the matched VarStore
1696 //
1697 CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid);
1698 VarStorageData->Size = IfrEfiVarStore->Size;
1699 VarStorageData->Name = VarStoreName;
1700 VarStorageData->Type = EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER;
1701 VarStoreId = IfrEfiVarStore->VarStoreId;
1702 }
1703 break;
1704
1705 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1706 //
1707 // VarStore is found. Don't need to search any more.
1708 //
1709 if (VarStoreId != 0) {
1710 break;
1711 }
1712
1713 IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
1714
1715 if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
1716 //
1717 // Find the matched VarStore
1718 //
1719 CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrNameValueVarStore->Guid);
1720 VarStorageData->Type = EFI_HII_VARSTORE_NAME_VALUE;
1721 VarStoreId = IfrNameValueVarStore->VarStoreId;
1722 }
1723 break;
1724
1725 case EFI_IFR_DEFAULTSTORE_OP:
1726 //
1727 // Add new the map between default id and default name.
1728 //
1729 DefaultDataPtr = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1730 if (DefaultDataPtr == NULL) {
1731 Status = EFI_OUT_OF_RESOURCES;
1732 goto Done;
1733 }
1734 DefaultDataPtr->DefaultId = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
1735 InsertTailList (&DefaultIdArray->Entry, &DefaultDataPtr->Entry);
1736 DefaultDataPtr = NULL;
1737 break;
1738
1739 case EFI_IFR_FORM_OP:
1740 case EFI_IFR_FORM_MAP_OP:
1741 //
1742 // No matched varstore is found and directly return.
1743 //
1744 if ( VarStoreId == 0) {
1745 Status = EFI_SUCCESS;
1746 goto Done;
1747 }
1748 break;
1749
1750 case EFI_IFR_REF_OP:
1751 //
1752 // Ref question is not in IFR Form. This IFR form is not valid.
1753 //
1754 if ( VarStoreId == 0) {
1755 Status = EFI_INVALID_PARAMETER;
1756 goto Done;
1757 }
1758 //
1759 // Check whether this question is for the requested varstore.
1760 //
1761 IfrRef = (EFI_IFR_REF4 *) IfrOpHdr;
1762 if (IfrRef->Question.VarStoreId != VarStoreId) {
1763 break;
1764 }
1765 VarWidth = (UINT16) (sizeof (EFI_HII_REF));
1766
1767 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1768 if (EFI_ERROR (Status)) {
1769 goto Done;
1770 }
1771 break;
1772
1773 case EFI_IFR_ONE_OF_OP:
1774 case EFI_IFR_NUMERIC_OP:
1775 //
1776 // Numeric and OneOf has the same opcode structure.
1777 //
1778
1779 //
1780 // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
1781 //
1782 if (VarStoreId == 0) {
1783 Status = EFI_INVALID_PARAMETER;
1784 goto Done;
1785 }
1786 //
1787 // Check whether this question is for the requested varstore.
1788 //
1789 IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
1790 if (IfrOneOf->Question.VarStoreId != VarStoreId) {
1791 break;
1792 }
1793 VarWidth = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
1794
1795 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1796 if (EFI_ERROR (Status)) {
1797 goto Done;
1798 }
1799
1800 if (BlockData == NULL) {
1801 //
1802 // BlockData == NULL means this opcode is not in the requst array.
1803 //
1804 break;
1805 }
1806
1807 if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
1808 //
1809 // Set this flag to TRUE for the first oneof option.
1810 //
1811 FirstOneOfOption = TRUE;
1812 } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
1813 //
1814 // Numeric minimum value will be used as default value when no default is specified.
1815 //
1816 DefaultData.Type = DefaultValueFromDefault;
1817 switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
1818 case EFI_IFR_NUMERIC_SIZE_1:
1819 DefaultData.Value.u8 = IfrOneOf->data.u8.MinValue;
1820 break;
1821
1822 case EFI_IFR_NUMERIC_SIZE_2:
1823 CopyMem (&DefaultData.Value.u16, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
1824 break;
1825
1826 case EFI_IFR_NUMERIC_SIZE_4:
1827 CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
1828 break;
1829
1830 case EFI_IFR_NUMERIC_SIZE_8:
1831 CopyMem (&DefaultData.Value.u64, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
1832 break;
1833
1834 default:
1835 Status = EFI_INVALID_PARAMETER;
1836 goto Done;
1837 }
1838 //
1839 // Set default value base on the DefaultId list get from IFR data.
1840 //
1841 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
1842 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
1843 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
1844 InsertDefaultValue (BlockData, &DefaultData);
1845 }
1846 }
1847 break;
1848
1849 case EFI_IFR_ORDERED_LIST_OP:
1850 //
1851 // offset by question header
1852 // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
1853 // no default value and default id, how to define its default value?
1854 //
1855
1856 //
1857 // OrderedList question is not in IFR Form. This IFR form is not valid.
1858 //
1859 if (VarStoreId == 0) {
1860 Status = EFI_INVALID_PARAMETER;
1861 goto Done;
1862 }
1863 //
1864 // Check whether this question is for the requested varstore.
1865 //
1866 IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;
1867 if (IfrOrderedList->Question.VarStoreId != VarStoreId) {
1868 BlockData = NULL;
1869 break;
1870 }
1871 VarWidth = IfrOrderedList->MaxContainers;
1872 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1873 if (EFI_ERROR (Status)) {
1874 goto Done;
1875 }
1876 break;
1877
1878 case EFI_IFR_CHECKBOX_OP:
1879 //
1880 // EFI_IFR_DEFAULT_OP
1881 // offset by question header
1882 // width is 1 sizeof (BOOLEAN)
1883 // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
1884 // value by DefaultOption
1885 // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
1886 //
1887
1888 //
1889 // CheckBox question is not in IFR Form. This IFR form is not valid.
1890 //
1891 if (VarStoreId == 0) {
1892 Status = EFI_INVALID_PARAMETER;
1893 goto Done;
1894 }
1895 //
1896 // Check whether this question is for the requested varstore.
1897 //
1898 IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1899 if (IfrCheckBox->Question.VarStoreId != VarStoreId) {
1900 break;
1901 }
1902 VarWidth = (UINT16) sizeof (BOOLEAN);
1903 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1904 if (EFI_ERROR (Status)) {
1905 goto Done;
1906 }
1907
1908 if (BlockData == NULL) {
1909 //
1910 // BlockData == NULL means this opcode is not in the requst array.
1911 //
1912 break;
1913 }
1914
1915 //
1916 // Add default value for standard ID by CheckBox Flag
1917 //
1918 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1919 //
1920 // Prepare new DefaultValue
1921 //
1922 DefaultData.DefaultId = VarDefaultId;
1923 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
1924 //
1925 // When flag is set, defautl value is TRUE.
1926 //
1927 DefaultData.Type = DefaultValueFromFlag;
1928 DefaultData.Value.b = TRUE;
1929 } else {
1930 //
1931 // When flag is not set, defautl value is FASLE.
1932 //
1933 DefaultData.Type = DefaultValueFromDefault;
1934 DefaultData.Value.b = FALSE;
1935 }
1936 //
1937 // Add DefaultValue into current BlockData
1938 //
1939 InsertDefaultValue (BlockData, &DefaultData);
1940
1941 //
1942 // Add default value for Manufacture ID by CheckBox Flag
1943 //
1944 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1945 //
1946 // Prepare new DefaultValue
1947 //
1948 DefaultData.DefaultId = VarDefaultId;
1949 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
1950 //
1951 // When flag is set, defautl value is TRUE.
1952 //
1953 DefaultData.Type = DefaultValueFromFlag;
1954 DefaultData.Value.b = TRUE;
1955 } else {
1956 //
1957 // When flag is not set, defautl value is FASLE.
1958 //
1959 DefaultData.Type = DefaultValueFromDefault;
1960 DefaultData.Value.b = FALSE;
1961 }
1962 //
1963 // Add DefaultValue into current BlockData
1964 //
1965 InsertDefaultValue (BlockData, &DefaultData);
1966 break;
1967
1968 case EFI_IFR_DATE_OP:
1969 //
1970 // offset by question header
1971 // width MaxSize * sizeof (CHAR16)
1972 // no default value, only block array
1973 //
1974
1975 //
1976 // Date question is not in IFR Form. This IFR form is not valid.
1977 //
1978 if (VarStoreId == 0) {
1979 Status = EFI_INVALID_PARAMETER;
1980 goto Done;
1981 }
1982 //
1983 // Check whether this question is for the requested varstore.
1984 //
1985 IfrDate = (EFI_IFR_DATE *) IfrOpHdr;
1986 if (IfrDate->Question.VarStoreId != VarStoreId) {
1987 break;
1988 }
1989
1990 VarWidth = (UINT16) sizeof (EFI_HII_DATE);
1991 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
1992 if (EFI_ERROR (Status)) {
1993 goto Done;
1994 }
1995 break;
1996
1997 case EFI_IFR_TIME_OP:
1998 //
1999 // offset by question header
2000 // width MaxSize * sizeof (CHAR16)
2001 // no default value, only block array
2002 //
2003
2004 //
2005 // Time question is not in IFR Form. This IFR form is not valid.
2006 //
2007 if (VarStoreId == 0) {
2008 Status = EFI_INVALID_PARAMETER;
2009 goto Done;
2010 }
2011 //
2012 // Check whether this question is for the requested varstore.
2013 //
2014 IfrTime = (EFI_IFR_TIME *) IfrOpHdr;
2015 if (IfrTime->Question.VarStoreId != VarStoreId) {
2016 break;
2017 }
2018
2019 VarWidth = (UINT16) sizeof (EFI_HII_TIME);
2020 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2021 if (EFI_ERROR (Status)) {
2022 goto Done;
2023 }
2024 break;
2025
2026 case EFI_IFR_STRING_OP:
2027 //
2028 // offset by question header
2029 // width MaxSize * sizeof (CHAR16)
2030 // no default value, only block array
2031 //
2032
2033 //
2034 // String question is not in IFR Form. This IFR form is not valid.
2035 //
2036 if (VarStoreId == 0) {
2037 Status = EFI_INVALID_PARAMETER;
2038 goto Done;
2039 }
2040 //
2041 // Check whether this question is for the requested varstore.
2042 //
2043 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
2044 if (IfrString->Question.VarStoreId != VarStoreId) {
2045 break;
2046 }
2047
2048 VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
2049 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2050 if (EFI_ERROR (Status)) {
2051 goto Done;
2052 }
2053
2054 //
2055 // No default value for string.
2056 //
2057 BlockData = NULL;
2058 break;
2059
2060 case EFI_IFR_PASSWORD_OP:
2061 //
2062 // offset by question header
2063 // width MaxSize * sizeof (CHAR16)
2064 // no default value, only block array
2065 //
2066
2067 //
2068 // Password question is not in IFR Form. This IFR form is not valid.
2069 //
2070 if (VarStoreId == 0) {
2071 Status = EFI_INVALID_PARAMETER;
2072 goto Done;
2073 }
2074 //
2075 // Check whether this question is for the requested varstore.
2076 //
2077 IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
2078 if (IfrPassword->Question.VarStoreId != VarStoreId) {
2079 break;
2080 }
2081
2082 VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
2083 Status = IsThisOpcodeRequired(RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData);
2084 if (EFI_ERROR (Status)) {
2085 goto Done;
2086 }
2087
2088 //
2089 // No default value for string.
2090 //
2091 BlockData = NULL;
2092 break;
2093
2094 case EFI_IFR_ONE_OF_OPTION_OP:
2095 //
2096 // No matched block data is ignored.
2097 //
2098 if (BlockData == NULL || BlockData->Scope == 0) {
2099 break;
2100 }
2101
2102 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
2103 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
2104 //
2105 // Get ordered list option data type.
2106 //
2107 if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
2108 VarWidth = 1;
2109 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
2110 VarWidth = 2;
2111 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
2112 VarWidth = 4;
2113 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
2114 VarWidth = 8;
2115 } else {
2116 //
2117 // Invalid ordered list option data type.
2118 //
2119 Status = EFI_INVALID_PARAMETER;
2120 if (BlockData->Name != NULL) {
2121 FreePool (BlockData->Name);
2122 }
2123 FreePool (BlockData);
2124 goto Done;
2125 }
2126
2127 //
2128 // Calculate Ordered list QuestionId width.
2129 //
2130 BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
2131 //
2132 // Check whether this question is in requested block array.
2133 //
2134 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width, (BOOLEAN)(BlockData->Name != NULL), HiiHandle)) {
2135 //
2136 // This question is not in the requested string. Skip it.
2137 //
2138 if (BlockData->Name != NULL) {
2139 FreePool (BlockData->Name);
2140 }
2141 FreePool (BlockData);
2142 BlockData = NULL;
2143 break;
2144 }
2145 //
2146 // Check this var question is in the var storage
2147 //
2148 if ((BlockData->Name == NULL) && ((BlockData->Offset + BlockData->Width) > VarStorageData->Size)) {
2149 Status = EFI_INVALID_PARAMETER;
2150 if (BlockData->Name != NULL) {
2151 FreePool (BlockData->Name);
2152 }
2153 FreePool (BlockData);
2154 goto Done;
2155 }
2156 //
2157 // Add Block Data into VarStorageData BlockEntry
2158 //
2159 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
2160 //
2161 // No default data for OrderedList.
2162 //
2163 BlockData = NULL;
2164 break;
2165 }
2166
2167 //
2168 // 1. Set default value for OneOf option when flag field has default attribute.
2169 //
2170 if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
2171 ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG)) {
2172 //
2173 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
2174 // The first oneof option value will be used as default value when no default value is specified.
2175 //
2176 FirstOneOfOption = FALSE;
2177
2178 // Prepare new DefaultValue
2179 //
2180 DefaultData.Type = DefaultValueFromFlag;
2181 CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
2182 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {
2183 DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
2184 InsertDefaultValue (BlockData, &DefaultData);
2185 }
2186 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
2187 DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
2188 InsertDefaultValue (BlockData, &DefaultData);
2189 }
2190 }
2191
2192 //
2193 // 2. Set as the default value when this is the first option.
2194 // The first oneof option value will be used as default value when no default value is specified.
2195 //
2196 if (FirstOneOfOption) {
2197 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
2198 FirstOneOfOption = FALSE;
2199
2200 //
2201 // Prepare new DefaultValue
2202 //
2203 DefaultData.Type = DefaultValueFromDefault;
2204 CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
2205 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2206 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2207 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2208 InsertDefaultValue (BlockData, &DefaultData);
2209 }
2210 }
2211 break;
2212
2213 case EFI_IFR_DEFAULT_OP:
2214 //
2215 // Update Current BlockData to the default value.
2216 //
2217 if (BlockData == NULL || BlockData->Scope == 0) {
2218 //
2219 // No matched block data is ignored.
2220 //
2221 break;
2222 }
2223
2224 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
2225 //
2226 // OrderedList Opcode is no default value.
2227 //
2228 break;
2229 }
2230 //
2231 // Get the DefaultId
2232 //
2233 IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
2234 VarDefaultId = IfrDefault->DefaultId;
2235 //
2236 // Prepare new DefaultValue
2237 //
2238 DefaultData.Type = DefaultValueFromOpcode;
2239 DefaultData.DefaultId = VarDefaultId;
2240 CopyMem (&DefaultData.Value, &IfrDefault->Value, IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value));
2241
2242 // If the value field is expression, set the cleaned flag.
2243 if (IfrDefault->Type == EFI_IFR_TYPE_OTHER) {
2244 DefaultData.Cleaned = TRUE;
2245 }
2246 //
2247 // Add DefaultValue into current BlockData
2248 //
2249 InsertDefaultValue (BlockData, &DefaultData);
2250
2251 //
2252 // After insert the default value, reset the cleaned value for next
2253 // time used. If not set here, need to set the value before everytime
2254 // use it.
2255 //
2256 DefaultData.Cleaned = FALSE;
2257 break;
2258
2259 case EFI_IFR_END_OP:
2260 //
2261 // End Opcode is for Var question.
2262 //
2263 if (BlockData != NULL) {
2264 if (BlockData->Scope > 0) {
2265 BlockData->Scope--;
2266 }
2267 if (BlockData->Scope == 0) {
2268 BlockData = NULL;
2269 }
2270 }
2271
2272 break;
2273
2274 default:
2275 if (BlockData != NULL) {
2276 if (BlockData->Scope > 0) {
2277 BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);
2278 }
2279
2280 if (BlockData->Scope == 0) {
2281 BlockData = NULL;
2282 }
2283 }
2284 break;
2285 }
2286
2287 IfrOffset += IfrOpHdr->Length;
2288 PackageOffset += IfrOpHdr->Length;
2289 }
2290
2291Done:
2292 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2293 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2294 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; ) {
2295 DefaultDataPtr = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2296 LinkDefault = LinkDefault->ForwardLink;
2297 if (DefaultDataPtr->Cleaned == TRUE) {
2298 RemoveEntryList (&DefaultDataPtr->Entry);
2299 FreePool (DefaultDataPtr);
2300 }
2301 }
2302 }
2303
2304 return Status;
2305}
2306
2307/**
2308 parse the configrequest string, get the elements.
2309
2310 @param ConfigRequest The input configrequest string.
2311 @param Progress Return the progress data.
2312
2313 @retval Block data pointer.
2314**/
2315IFR_BLOCK_DATA *
2316GetBlockElement (
2317 IN EFI_STRING ConfigRequest,
2318 OUT EFI_STRING *Progress
2319 )
2320{
2321 EFI_STRING StringPtr;
2322 IFR_BLOCK_DATA *BlockData;
2323 IFR_BLOCK_DATA *RequestBlockArray;
2324 EFI_STATUS Status;
2325 UINT8 *TmpBuffer;
2326 UINT16 Offset;
2327 UINT16 Width;
2328 LIST_ENTRY *Link;
2329 IFR_BLOCK_DATA *NextBlockData;
2330 UINTN Length;
2331
2332 TmpBuffer = NULL;
2333
2334 //
2335 // Init RequestBlockArray
2336 //
2337 RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2338 if (RequestBlockArray == NULL) {
2339 goto Done;
2340 }
2341 InitializeListHead (&RequestBlockArray->Entry);
2342
2343 //
2344 // Get the request Block array from the request string
2345 // Offset and Width
2346 //
2347
2348 //
2349 // Parse each <RequestElement> if exists
2350 // Only <BlockName> format is supported by this help function.
2351 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
2352 //
2353 StringPtr = ConfigRequest;
2354 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
2355 //
2356 // Skip the OFFSET string
2357 //
2358 *Progress = StringPtr;
2359 StringPtr += StrLen (L"&OFFSET=");
2360 //
2361 // Get Offset
2362 //
2363 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
2364 if (EFI_ERROR (Status)) {
2365 goto Done;
2366 }
2367 Offset = 0;
2368 CopyMem (
2369 &Offset,
2370 TmpBuffer,
2371 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
2372 );
2373 FreePool (TmpBuffer);
2374
2375 StringPtr += Length;
2376 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
2377 goto Done;
2378 }
2379 StringPtr += StrLen (L"&WIDTH=");
2380
2381 //
2382 // Get Width
2383 //
2384 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
2385 if (EFI_ERROR (Status)) {
2386 goto Done;
2387 }
2388 Width = 0;
2389 CopyMem (
2390 &Width,
2391 TmpBuffer,
2392 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
2393 );
2394 FreePool (TmpBuffer);
2395
2396 StringPtr += Length;
2397 if (*StringPtr != 0 && *StringPtr != L'&') {
2398 goto Done;
2399 }
2400
2401 //
2402 // Set Block Data
2403 //
2404 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2405 if (BlockData == NULL) {
2406 goto Done;
2407 }
2408 BlockData->Offset = Offset;
2409 BlockData->Width = Width;
2410 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
2411
2412 //
2413 // Skip &VALUE string if &VALUE does exists.
2414 //
2415 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
2416 StringPtr += StrLen (L"&VALUE=");
2417
2418 //
2419 // Get Value
2420 //
2421 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
2422 if (EFI_ERROR (Status)) {
2423 goto Done;
2424 }
2425
2426 StringPtr += Length;
2427 if (*StringPtr != 0 && *StringPtr != L'&') {
2428 goto Done;
2429 }
2430 }
2431 //
2432 // If '\0', parsing is finished.
2433 //
2434 if (*StringPtr == 0) {
2435 break;
2436 }
2437 }
2438
2439 //
2440 // Merge the requested block data.
2441 //
2442 Link = RequestBlockArray->Entry.ForwardLink;
2443 while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
2444 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2445 NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
2446 if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
2447 if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
2448 BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
2449 }
2450 RemoveEntryList (Link->ForwardLink);
2451 FreePool (NextBlockData);
2452 continue;
2453 }
2454 Link = Link->ForwardLink;
2455 }
2456
2457 return RequestBlockArray;
2458
2459Done:
2460 if (RequestBlockArray != NULL) {
2461 //
2462 // Free Link Array RequestBlockArray
2463 //
2464 while (!IsListEmpty (&RequestBlockArray->Entry)) {
2465 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2466 RemoveEntryList (&BlockData->Entry);
2467 FreePool (BlockData);
2468 }
2469
2470 FreePool (RequestBlockArray);
2471 }
2472
2473 return NULL;
2474}
2475
2476/**
2477 parse the configrequest string, get the elements.
2478
2479 @param ConfigRequest The input config request string.
2480 @param Progress Return the progress data.
2481
2482 @retval return data block array.
2483**/
2484IFR_BLOCK_DATA *
2485GetNameElement (
2486 IN EFI_STRING ConfigRequest,
2487 OUT EFI_STRING *Progress
2488 )
2489{
2490 EFI_STRING StringPtr;
2491 EFI_STRING NextTag;
2492 IFR_BLOCK_DATA *BlockData;
2493 IFR_BLOCK_DATA *RequestBlockArray;
2494 BOOLEAN HasValue;
2495
2496 StringPtr = ConfigRequest;
2497
2498 //
2499 // Init RequestBlockArray
2500 //
2501 RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2502 if (RequestBlockArray == NULL) {
2503 goto Done;
2504 }
2505 InitializeListHead (&RequestBlockArray->Entry);
2506
2507 //
2508 // Get the request Block array from the request string
2509 //
2510
2511 //
2512 // Parse each <RequestElement> if exists
2513 // Only <BlockName> format is supported by this help function.
2514 // <BlockName> ::= &'Name***=***
2515 //
2516 while (StringPtr != NULL && *StringPtr == L'&') {
2517
2518 *Progress = StringPtr;
2519 //
2520 // Skip the L"&" string
2521 //
2522 StringPtr += 1;
2523
2524 HasValue = FALSE;
2525 if ((NextTag = StrStr (StringPtr, L"=")) != NULL) {
2526 *NextTag = L'\0';
2527 HasValue = TRUE;
2528 } else if ((NextTag = StrStr (StringPtr, L"&")) != NULL) {
2529 *NextTag = L'\0';
2530 }
2531
2532 //
2533 // Set Block Data
2534 //
2535 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2536 if (BlockData == NULL) {
2537 goto Done;
2538 }
2539
2540 //
2541 // Get Name
2542 //
2543 BlockData->Name = AllocateCopyPool(StrSize (StringPtr), StringPtr);
2544 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
2545
2546 if (HasValue) {
2547 //
2548 // If has value, skip the value.
2549 //
2550 StringPtr = NextTag + 1;
2551 *NextTag = L'=';
2552 StringPtr = StrStr (StringPtr, L"&");
2553 } else if (NextTag != NULL) {
2554 //
2555 // restore the '&' text.
2556 //
2557 StringPtr = NextTag;
2558 *NextTag = L'&';
2559 }
2560 }
2561
2562 return RequestBlockArray;
2563
2564Done:
2565 if (RequestBlockArray != NULL) {
2566 //
2567 // Free Link Array RequestBlockArray
2568 //
2569 while (!IsListEmpty (&RequestBlockArray->Entry)) {
2570 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2571 RemoveEntryList (&BlockData->Entry);
2572 if (BlockData->Name != NULL) {
2573 FreePool (BlockData->Name);
2574 }
2575 FreePool (BlockData);
2576 }
2577
2578 FreePool (RequestBlockArray);
2579 }
2580
2581 return NULL;
2582}
2583
2584/**
2585 Generate ConfigRequest string base on the varstore info.
2586
2587 @param ConfigHdr The config header for this varstore.
2588 @param VarStorageData The varstore info.
2589 @param Status Return Status.
2590 @param ConfigRequest The ConfigRequest info may be return.
2591
2592 @retval TRUE Need to continue
2593 @retval Others NO need to continue or error occur.
2594**/
2595BOOLEAN
2596GenerateConfigRequest (
2597 IN CHAR16 *ConfigHdr,
2598 IN IFR_VARSTORAGE_DATA *VarStorageData,
2599 OUT EFI_STATUS *Status,
2600 IN OUT EFI_STRING *ConfigRequest
2601 )
2602{
2603 BOOLEAN DataExist;
2604 UINTN Length;
2605 LIST_ENTRY *Link;
2606 CHAR16 *FullConfigRequest;
2607 CHAR16 *StringPtr;
2608 IFR_BLOCK_DATA *BlockData;
2609
2610 //
2611 // Append VarStorageData BlockEntry into *Request string
2612 // Now support only one varstore in a form package.
2613 //
2614
2615 //
2616 // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
2617 // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
2618 //
2619
2620 //
2621 // Compute the length of the entire request starting with <ConfigHdr> and a
2622 // Null-terminator
2623 //
2624 DataExist = FALSE;
2625 Length = StrLen (ConfigHdr) + 1;
2626
2627 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
2628 DataExist = TRUE;
2629 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2630 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2631 //
2632 // Add <BlockName> length for each Name
2633 //
2634 // <BlockName> ::= &Name1&Name2&...
2635 // |1| StrLen(Name1)
2636 //
2637 Length = Length + (1 + StrLen (BlockData->Name));
2638 } else {
2639 //
2640 // Add <BlockName> length for each Offset/Width pair
2641 //
2642 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
2643 // | 8 | 4 | 7 | 4 |
2644 //
2645 Length = Length + (8 + 4 + 7 + 4);
2646 }
2647 }
2648 //
2649 // No any request block data is found. The request string can't be constructed.
2650 //
2651 if (!DataExist) {
2652 *Status = EFI_SUCCESS;
2653 return FALSE;
2654 }
2655
2656 //
2657 // Allocate buffer for the entire <ConfigRequest>
2658 //
2659 FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
2660 if (FullConfigRequest == NULL) {
2661 *Status = EFI_OUT_OF_RESOURCES;
2662 return FALSE;
2663 }
2664 StringPtr = FullConfigRequest;
2665
2666 //
2667 // Start with <ConfigHdr>
2668 //
2669 StrCpy (StringPtr, ConfigHdr);
2670 StringPtr += StrLen (StringPtr);
2671
2672 //
2673 // Loop through all the Offset/Width pairs and append them to ConfigRequest
2674 //
2675 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
2676 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2677 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2678 //
2679 // Append &Name1\0
2680 //
2681 UnicodeSPrint (
2682 StringPtr,
2683 (1 + StrLen (BlockData->Name) + 1) * sizeof (CHAR16),
2684 L"&%s",
2685 BlockData->Name
2686 );
2687 } else {
2688 //
2689 // Append &OFFSET=XXXX&WIDTH=YYYY\0
2690 //
2691 UnicodeSPrint (
2692 StringPtr,
2693 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
2694 L"&OFFSET=%04X&WIDTH=%04X",
2695 BlockData->Offset,
2696 BlockData->Width
2697 );
2698 }
2699 StringPtr += StrLen (StringPtr);
2700 }
2701 //
2702 // Set to the got full request string.
2703 //
2704 HiiToLower (FullConfigRequest);
2705
2706 if (*ConfigRequest != NULL) {
2707 FreePool (*ConfigRequest);
2708 }
2709 *ConfigRequest = FullConfigRequest;
2710
2711 return TRUE;
2712}
2713
2714/**
2715 Generate ConfigRequest Header base on the varstore info.
2716
2717 @param VarStorageData The varstore info.
2718 @param DevicePath Device path for this varstore.
2719 @param ConfigHdr The config header for this varstore.
2720
2721 @retval EFI_SUCCESS Generate the header success.
2722 @retval EFI_OUT_OF_RESOURCES Allocate buffer fail.
2723**/
2724EFI_STATUS
2725GenerateHdr (
2726 IN IFR_VARSTORAGE_DATA *VarStorageData,
2727 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
2728 OUT EFI_STRING *ConfigHdr
2729 )
2730{
2731 EFI_STRING GuidStr;
2732 EFI_STRING NameStr;
2733 EFI_STRING PathStr;
2734 UINTN Length;
2735 EFI_STATUS Status;
2736
2737 Status = EFI_SUCCESS;
2738 NameStr = NULL;
2739 GuidStr = NULL;
2740 PathStr = NULL;
2741
2742 //
2743 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
2744 //
2745 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);
2746 if (VarStorageData->Name != NULL) {
2747 GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);
2748 } else {
2749 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
2750 }
2751 GenerateSubStr (
2752 L"PATH=",
2753 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
2754 (VOID *) DevicePath,
2755 1,
2756 &PathStr
2757 );
2758 Length = StrLen (GuidStr) + StrLen (NameStr) + StrLen (PathStr) + 1;
2759 if (VarStorageData->Name == NULL) {
2760 Length += 1;
2761 }
2762
2763 *ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
2764 if (*ConfigHdr == NULL) {
2765 Status = EFI_OUT_OF_RESOURCES;
2766 goto Done;
2767 }
2768 StrCpy (*ConfigHdr, GuidStr);
2769 StrCat (*ConfigHdr, NameStr);
2770 if (VarStorageData->Name == NULL) {
2771 StrCat (*ConfigHdr, L"&");
2772 }
2773 StrCat (*ConfigHdr, PathStr);
2774
2775 //
2776 // Remove the last character L'&'
2777 //
2778 *(*ConfigHdr + StrLen (*ConfigHdr) - 1) = L'\0';
2779
2780Done:
2781 if (GuidStr != NULL) {
2782 FreePool (GuidStr);
2783 }
2784
2785 if (NameStr != NULL) {
2786 FreePool (NameStr);
2787 }
2788
2789 if (PathStr != NULL) {
2790 FreePool (PathStr);
2791 }
2792
2793 return Status;
2794}
2795
2796/**
2797 Get Data buffer size based on data type.
2798
2799 @param ValueType The input data type.
2800
2801 @retval The data buffer size for the input type.
2802**/
2803UINT16
2804GetStorageWidth (
2805 IN UINT8 ValueType
2806 )
2807{
2808 UINT16 StorageWidth;
2809
2810 switch (ValueType) {
2811 case EFI_IFR_NUMERIC_SIZE_1:
2812 case EFI_IFR_TYPE_BOOLEAN:
2813 StorageWidth = (UINT16) sizeof (UINT8);
2814 break;
2815
2816 case EFI_IFR_NUMERIC_SIZE_2:
2817 StorageWidth = (UINT16) sizeof (UINT16);
2818 break;
2819
2820 case EFI_IFR_NUMERIC_SIZE_4:
2821 StorageWidth = (UINT16) sizeof (UINT32);
2822 break;
2823
2824 case EFI_IFR_NUMERIC_SIZE_8:
2825 StorageWidth = (UINT16) sizeof (UINT64);
2826 break;
2827
2828 case EFI_IFR_TYPE_TIME:
2829 StorageWidth = (UINT16) sizeof (EFI_IFR_TIME);
2830 break;
2831
2832 case EFI_IFR_TYPE_DATE:
2833 StorageWidth = (UINT16) sizeof (EFI_IFR_DATE);
2834 break;
2835
2836 default:
2837 StorageWidth = 0;
2838 break;
2839 }
2840
2841 return StorageWidth;
2842}
2843
2844/**
2845 Generate ConfigAltResp string base on the varstore info.
2846
2847 @param ConfigHdr The config header for this varstore.
2848 @param VarStorageData The varstore info.
2849 @param DefaultIdArray The Default id array.
2850 @param DefaultAltCfgResp The DefaultAltCfgResp info may be return.
2851
2852 @retval TRUE Need to continue
2853 @retval Others NO need to continue or error occur.
2854**/
2855EFI_STATUS
2856GenerateAltConfigResp (
2857 IN CHAR16 *ConfigHdr,
2858 IN IFR_VARSTORAGE_DATA *VarStorageData,
2859 IN IFR_DEFAULT_DATA *DefaultIdArray,
2860 IN OUT EFI_STRING *DefaultAltCfgResp
2861 )
2862{
2863 BOOLEAN DataExist;
2864 UINTN Length;
2865 LIST_ENTRY *Link;
2866 LIST_ENTRY *LinkData;
2867 LIST_ENTRY *LinkDefault;
2868 LIST_ENTRY *ListEntry;
2869 CHAR16 *StringPtr;
2870 IFR_BLOCK_DATA *BlockData;
2871 IFR_DEFAULT_DATA *DefaultId;
2872 IFR_DEFAULT_DATA *DefaultValueData;
2873 UINTN Width;
2874 UINT8 *TmpBuffer;
2875
2876 BlockData = NULL;
2877 DataExist = FALSE;
2878
2879 //
2880 // Add length for <ConfigHdr> + '\0'
2881 //
2882 Length = StrLen (ConfigHdr) + 1;
2883
2884 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2885 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2886 //
2887 // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
2888 // |1| StrLen (ConfigHdr) | 8 | 4 |
2889 //
2890 Length += (1 + StrLen (ConfigHdr) + 8 + 4);
2891
2892 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2893 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2894 ListEntry = &BlockData->DefaultValueEntry;
2895 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
2896 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2897 if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
2898 continue;
2899 }
2900 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2901 //
2902 // Add length for "&Name1=zzzzzzzzzzzz"
2903 // |1|Name|1|Value|
2904 //
2905 Length += (1 + StrLen (BlockData->Name) + 1 + BlockData->Width * 2);
2906 } else {
2907 //
2908 // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
2909 // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
2910 //
2911 Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
2912 }
2913 DataExist = TRUE;
2914 }
2915 }
2916 }
2917
2918 //
2919 // No default value is found. The default string doesn't exist.
2920 //
2921 if (!DataExist) {
2922 return EFI_SUCCESS;
2923 }
2924
2925 //
2926 // Allocate buffer for the entire <DefaultAltCfgResp>
2927 //
2928 *DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
2929 if (*DefaultAltCfgResp == NULL) {
2930 return EFI_OUT_OF_RESOURCES;
2931 }
2932 StringPtr = *DefaultAltCfgResp;
2933
2934 //
2935 // Start with <ConfigHdr>
2936 //
2937 StrCpy (StringPtr, ConfigHdr);
2938 StringPtr += StrLen (StringPtr);
2939
2940 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2941 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2942 //
2943 // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
2944 // |1| StrLen (ConfigHdr) | 8 | 4 |
2945 //
2946 UnicodeSPrint (
2947 StringPtr,
2948 (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
2949 L"&%s&ALTCFG=%04X",
2950 ConfigHdr,
2951 DefaultId->DefaultId
2952 );
2953 StringPtr += StrLen (StringPtr);
2954
2955 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2956 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2957 ListEntry = &BlockData->DefaultValueEntry;
2958 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
2959 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2960 if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
2961 continue;
2962 }
2963 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2964 UnicodeSPrint (
2965 StringPtr,
2966 (1 + StrLen (ConfigHdr) + 1) * sizeof (CHAR16),
2967 L"&%s=",
2968 BlockData->Name
2969 );
2970 StringPtr += StrLen (StringPtr);
2971 } else {
2972 //
2973 // Add <BlockConfig>
2974 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
2975 //
2976 UnicodeSPrint (
2977 StringPtr,
2978 (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
2979 L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
2980 BlockData->Offset,
2981 BlockData->Width
2982 );
2983 StringPtr += StrLen (StringPtr);
2984 }
2985 Width = BlockData->Width;
2986 //
2987 // Convert Value to a hex string in "%x" format
2988 // NOTE: This is in the opposite byte that GUID and PATH use
2989 //
2990 TmpBuffer = (UINT8 *) &(DefaultValueData->Value);
2991 for (; Width > 0; Width--) {
2992 StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2);
2993 }
2994 }
2995 }
2996 }
2997
2998 HiiToLower (*DefaultAltCfgResp);
2999
3000 return EFI_SUCCESS;
3001}
3002
3003/**
3004 This function gets the full request string and full default value string by
3005 parsing IFR data in HII form packages.
3006
3007 When Request points to NULL string, the request string and default value string
3008 for each varstore in form package will return.
3009
3010 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
3011 @param DevicePath Device Path which Hii Config Access Protocol is registered.
3012 @param Request Pointer to a null-terminated Unicode string in
3013 <ConfigRequest> format. When it doesn't contain
3014 any RequestElement, it will be updated to return
3015 the full RequestElement retrieved from IFR data.
3016 If it points to NULL, the request string for the first
3017 varstore in form package will be merged into a
3018 <MultiConfigRequest> format string and return.
3019 @param AltCfgResp Pointer to a null-terminated Unicode string in
3020 <ConfigAltResp> format. When the pointer is to NULL,
3021 the full default value string retrieved from IFR data
3022 will return. When the pinter is to a string, the
3023 full default value string retrieved from IFR data
3024 will be merged into the input string and return.
3025 When Request points to NULL, the default value string
3026 for each varstore in form package will be merged into
3027 a <MultiConfigAltResp> format string and return.
3028 @param PointerProgress Optional parameter, it can be be NULL.
3029 When it is not NULL, if Request is NULL, it returns NULL.
3030 On return, points to a character in the Request
3031 string. Points to the string's null terminator if
3032 request was successful. Points to the most recent
3033 & before the first failing name / value pair (or
3034 the beginning of the string if the failure is in
3035 the first name / value pair) if the request was
3036 not successful.
3037 @retval EFI_SUCCESS The Results string is set to the full request string.
3038 And AltCfgResp contains all default value string.
3039 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
3040 @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
3041 can't be found in Form package.
3042 @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
3043 @retval EFI_INVALID_PARAMETER Request points to NULL.
3044
3045**/
3046EFI_STATUS
3047EFIAPI
3048GetFullStringFromHiiFormPackages (
3049 IN HII_DATABASE_RECORD *DataBaseRecord,
3050 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3051 IN OUT EFI_STRING *Request,
3052 IN OUT EFI_STRING *AltCfgResp,
3053 OUT EFI_STRING *PointerProgress OPTIONAL
3054 )
3055{
3056 EFI_STATUS Status;
3057 UINT8 *HiiFormPackage;
3058 UINTN PackageSize;
3059 IFR_BLOCK_DATA *RequestBlockArray;
3060 IFR_BLOCK_DATA *BlockData;
3061 IFR_DEFAULT_DATA *DefaultValueData;
3062 IFR_DEFAULT_DATA *DefaultId;
3063 IFR_DEFAULT_DATA *DefaultIdArray;
3064 IFR_VARSTORAGE_DATA *VarStorageData;
3065 EFI_STRING DefaultAltCfgResp;
3066 EFI_STRING ConfigHdr;
3067 EFI_STRING StringPtr;
3068 EFI_STRING Progress;
3069
3070 if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {
3071 return EFI_INVALID_PARAMETER;
3072 }
3073
3074 //
3075 // Initialize the local variables.
3076 //
3077 RequestBlockArray = NULL;
3078 DefaultIdArray = NULL;
3079 VarStorageData = NULL;
3080 DefaultAltCfgResp = NULL;
3081 ConfigHdr = NULL;
3082 HiiFormPackage = NULL;
3083 PackageSize = 0;
3084 Progress = *Request;
3085
3086 Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
3087 if (EFI_ERROR (Status)) {
3088 goto Done;
3089 }
3090
3091 //
3092 // 1. Get the request block array by Request String when Request string containts the block array.
3093 //
3094 StringPtr = NULL;
3095 if (*Request != NULL) {
3096 StringPtr = *Request;
3097 //
3098 // Jump <ConfigHdr>
3099 //
3100 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3101 Status = EFI_INVALID_PARAMETER;
3102 goto Done;
3103 }
3104 StringPtr += StrLen (L"GUID=");
3105 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
3106 StringPtr++;
3107 }
3108 if (*StringPtr == L'\0') {
3109 Status = EFI_INVALID_PARAMETER;
3110 goto Done;
3111 }
3112 StringPtr += StrLen (L"&NAME=");
3113 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
3114 StringPtr++;
3115 }
3116 if (*StringPtr == L'\0') {
3117 Status = EFI_INVALID_PARAMETER;
3118 goto Done;
3119 }
3120 StringPtr += StrLen (L"&PATH=");
3121 while (*StringPtr != L'\0' && *StringPtr != L'&') {
3122 StringPtr ++;
3123 }
3124
3125 if (*StringPtr == L'\0') {
3126 //
3127 // No request block is found.
3128 //
3129 StringPtr = NULL;
3130 }
3131 }
3132
3133 //
3134 // If StringPtr != NULL, get the request elements.
3135 //
3136 if (StringPtr != NULL) {
3137 if (StrStr (StringPtr, L"&OFFSET=") != NULL) {
3138 RequestBlockArray = GetBlockElement(StringPtr, &Progress);
3139 } else {
3140 RequestBlockArray = GetNameElement(StringPtr, &Progress);
3141 }
3142
3143 if (RequestBlockArray == NULL) {
3144 Status = EFI_INVALID_PARAMETER;
3145 goto Done;
3146 }
3147 }
3148
3149 //
3150 // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
3151 //
3152 DefaultIdArray = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
3153 if (DefaultIdArray == NULL) {
3154 Status = EFI_OUT_OF_RESOURCES;
3155 goto Done;
3156 }
3157 InitializeListHead (&DefaultIdArray->Entry);
3158
3159 //
3160 // Initialize VarStorageData to store the var store Block and Default value information.
3161 //
3162 VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
3163 if (VarStorageData == NULL) {
3164 Status = EFI_OUT_OF_RESOURCES;
3165 goto Done;
3166 }
3167 InitializeListHead (&VarStorageData->Entry);
3168 InitializeListHead (&VarStorageData->BlockEntry);
3169
3170 //
3171 // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
3172 //
3173
3174 //
3175 // Parse the opcode in form pacakge to get the default setting.
3176 //
3177 Status = ParseIfrData (DataBaseRecord->Handle,
3178 HiiFormPackage,
3179 (UINT32) PackageSize,
3180 *Request,
3181 RequestBlockArray,
3182 VarStorageData,
3183 DefaultIdArray);
3184 if (EFI_ERROR (Status)) {
3185 goto Done;
3186 }
3187
3188 //
3189 // No requested varstore in IFR data and directly return
3190 //
3191 if (VarStorageData->Type == 0 && VarStorageData->Name == NULL) {
3192 Status = EFI_SUCCESS;
3193 goto Done;
3194 }
3195
3196 //
3197 // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
3198 //
3199 Status = GenerateHdr (VarStorageData, DevicePath, &ConfigHdr);
3200 if (EFI_ERROR (Status)) {
3201 goto Done;
3202 }
3203
3204 if (RequestBlockArray == NULL) {
3205 if (!GenerateConfigRequest(ConfigHdr, VarStorageData, &Status, Request)) {
3206 goto Done;
3207 }
3208 }
3209
3210 //
3211 // 4. Construct Default Value string in AltResp according to request element.
3212 // Go through all VarStorageData Entry and get the DefaultId array for each one
3213 // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
3214 //
3215 Status = GenerateAltConfigResp (ConfigHdr, VarStorageData, DefaultIdArray, &DefaultAltCfgResp);
3216 if (EFI_ERROR (Status)) {
3217 goto Done;
3218 }
3219
3220 //
3221 // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL.
3222 //
3223 if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {
3224 Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
3225 FreePool (DefaultAltCfgResp);
3226 } else if (*AltCfgResp == NULL) {
3227 *AltCfgResp = DefaultAltCfgResp;
3228 }
3229
3230Done:
3231 if (RequestBlockArray != NULL) {
3232 //
3233 // Free Link Array RequestBlockArray
3234 //
3235 while (!IsListEmpty (&RequestBlockArray->Entry)) {
3236 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
3237 RemoveEntryList (&BlockData->Entry);
3238 if (BlockData->Name != NULL) {
3239 FreePool (BlockData->Name);
3240 }
3241 FreePool (BlockData);
3242 }
3243
3244 FreePool (RequestBlockArray);
3245 }
3246
3247 if (VarStorageData != NULL) {
3248 //
3249 // Free link array VarStorageData
3250 //
3251 while (!IsListEmpty (&VarStorageData->BlockEntry)) {
3252 BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
3253 RemoveEntryList (&BlockData->Entry);
3254 if (BlockData->Name != NULL) {
3255 FreePool (BlockData->Name);
3256 }
3257 //
3258 // Free default value link array
3259 //
3260 while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
3261 DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
3262 RemoveEntryList (&DefaultValueData->Entry);
3263 FreePool (DefaultValueData);
3264 }
3265 FreePool (BlockData);
3266 }
3267 FreePool (VarStorageData);
3268 }
3269
3270 if (DefaultIdArray != NULL) {
3271 //
3272 // Free DefaultId Array
3273 //
3274 while (!IsListEmpty (&DefaultIdArray->Entry)) {
3275 DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
3276 RemoveEntryList (&DefaultId->Entry);
3277 FreePool (DefaultId);
3278 }
3279 FreePool (DefaultIdArray);
3280 }
3281
3282 //
3283 // Free the allocated string
3284 //
3285 if (ConfigHdr != NULL) {
3286 FreePool (ConfigHdr);
3287 }
3288
3289 //
3290 // Free Pacakge data
3291 //
3292 if (HiiFormPackage != NULL) {
3293 FreePool (HiiFormPackage);
3294 }
3295
3296 if (PointerProgress != NULL) {
3297 if (*Request == NULL) {
3298 *PointerProgress = NULL;
3299 } else if (EFI_ERROR (Status)) {
3300 *PointerProgress = *Request;
3301 } else {
3302 *PointerProgress = *Request + StrLen (*Request);
3303 }
3304 }
3305
3306 return Status;
3307}
3308
3309/**
3310 This function gets the full request resp string by
3311 parsing IFR data in HII form packages.
3312
3313 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3314 instance.
3315 @param EfiVarStoreInfo The efi varstore info which is save in the EFI
3316 varstore data structure.
3317 @param Request Pointer to a null-terminated Unicode string in
3318 <ConfigRequest> format.
3319 @param RequestResp Pointer to a null-terminated Unicode string in
3320 <ConfigResp> format.
3321 @param AccessProgress On return, points to a character in the Request
3322 string. Points to the string's null terminator if
3323 request was successful. Points to the most recent
3324 & before the first failing name / value pair (or
3325 the beginning of the string if the failure is in
3326 the first name / value pair) if the request was
3327 not successful.
3328
3329 @retval EFI_SUCCESS The Results string is set to the full request string.
3330 And AltCfgResp contains all default value string.
3331 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
3332 @retval EFI_INVALID_PARAMETER Request points to NULL.
3333
3334**/
3335EFI_STATUS
3336GetConfigRespFromEfiVarStore (
3337 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3338 IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
3339 IN EFI_STRING Request,
3340 OUT EFI_STRING *RequestResp,
3341 OUT EFI_STRING *AccessProgress
3342 )
3343{
3344 EFI_STATUS Status;
3345 EFI_STRING VarStoreName;
3346 UINT8 *VarStore;
3347 UINTN BufferSize;
3348
3349 Status = EFI_SUCCESS;
3350 BufferSize = 0;
3351 VarStore = NULL;
3352 VarStoreName = NULL;
3353 *AccessProgress = Request;
3354
3355 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name) * sizeof (CHAR16));
3356 if (VarStoreName == NULL) {
3357 Status = EFI_OUT_OF_RESOURCES;
3358 goto Done;
3359 }
3360 AsciiStrToUnicodeStr ((CHAR8 *) EfiVarStoreInfo->Name, VarStoreName);
3361
3362
3363 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
3364 if (Status != EFI_BUFFER_TOO_SMALL) {
3365 goto Done;
3366 }
3367
3368 VarStore = AllocateZeroPool (BufferSize);
3369 ASSERT (VarStore != NULL);
3370 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
3371 if (EFI_ERROR (Status)) {
3372 goto Done;
3373 }
3374
3375 Status = HiiBlockToConfig(This, Request, VarStore, BufferSize, RequestResp, AccessProgress);
3376 if (EFI_ERROR (Status)) {
3377 goto Done;
3378 }
3379
3380Done:
3381 if (VarStoreName != NULL) {
3382 FreePool (VarStoreName);
3383 }
3384
3385 if (VarStore != NULL) {
3386 FreePool (VarStore);
3387 }
3388
3389 return Status;
3390}
3391
3392
3393/**
3394 This function route the full request resp string for efi varstore.
3395
3396 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3397 instance.
3398 @param EfiVarStoreInfo The efi varstore info which is save in the EFI
3399 varstore data structure.
3400 @param RequestResp Pointer to a null-terminated Unicode string in
3401 <ConfigResp> format.
3402 @param Result Pointer to a null-terminated Unicode string in
3403 <ConfigResp> format.
3404
3405 @retval EFI_SUCCESS The Results string is set to the full request string.
3406 And AltCfgResp contains all default value string.
3407 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
3408 @retval EFI_INVALID_PARAMETER Request points to NULL.
3409
3410**/
3411EFI_STATUS
3412RouteConfigRespForEfiVarStore (
3413 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3414 IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
3415 IN EFI_STRING RequestResp,
3416 OUT EFI_STRING *Result
3417 )
3418{
3419 EFI_STATUS Status;
3420 EFI_STRING VarStoreName;
3421 UINT8 *VarStore;
3422 UINTN BufferSize;
3423 UINTN BlockSize;
3424
3425 Status = EFI_SUCCESS;
3426 BufferSize = 0;
3427 VarStore = NULL;
3428 VarStoreName = NULL;
3429
3430 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name) * sizeof (CHAR16));
3431 if (VarStoreName == NULL) {
3432 Status = EFI_OUT_OF_RESOURCES;
3433 goto Done;
3434 }
3435 AsciiStrToUnicodeStr ((CHAR8 *) EfiVarStoreInfo->Name, VarStoreName);
3436
3437 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
3438 if (Status != EFI_BUFFER_TOO_SMALL) {
3439 goto Done;
3440 }
3441
3442 BlockSize = BufferSize;
3443 VarStore = AllocateZeroPool (BufferSize);
3444 ASSERT (VarStore != NULL);
3445 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
3446 if (EFI_ERROR (Status)) {
3447 goto Done;
3448 }
3449
3450 Status = HiiConfigToBlock(This, RequestResp, VarStore, &BlockSize, Result);
3451 if (EFI_ERROR (Status)) {
3452 goto Done;
3453 }
3454
3455 Status = gRT->SetVariable (VarStoreName, &EfiVarStoreInfo->Guid, EfiVarStoreInfo->Attributes, BufferSize, VarStore);
3456 if (EFI_ERROR (Status)) {
3457 goto Done;
3458 }
3459
3460Done:
3461 if (VarStoreName != NULL) {
3462 FreePool (VarStoreName);
3463 }
3464
3465 if (VarStore != NULL) {
3466 FreePool (VarStore);
3467 }
3468
3469 return Status;
3470}
3471
3472/**
3473 Validate the config request elements.
3474
3475 @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
3476 without configHdr field.
3477
3478 @retval CHAR16 * THE first Name/value pair not correct.
3479 @retval NULL Success parse the name/value pair
3480**/
3481CHAR16 *
3482OffsetWidthValidate (
3483 CHAR16 *ConfigElements
3484 )
3485{
3486 CHAR16 *StringPtr;
3487 CHAR16 *RetVal;
3488
3489 StringPtr = ConfigElements;
3490
3491 while (1) {
3492 RetVal = StringPtr;
3493 if (StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
3494 return RetVal;
3495 }
3496
3497 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3498 StringPtr++;
3499 }
3500 if (*StringPtr == L'\0') {
3501 return RetVal;
3502 }
3503
3504 StringPtr += StrLen (L"&WIDTH=");
3505 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
3506 StringPtr ++;
3507 }
3508
3509 if (*StringPtr == L'\0') {
3510 return NULL;
3511 }
3512 }
3513}
3514
3515/**
3516 Validate the config request elements.
3517
3518 @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
3519 without configHdr field.
3520
3521 @retval CHAR16 * THE first Name/value pair not correct.
3522 @retval NULL Success parse the name/value pair
3523
3524**/
3525CHAR16 *
3526NameValueValidate (
3527 CHAR16 *ConfigElements
3528 )
3529{
3530 CHAR16 *StringPtr;
3531 CHAR16 *RetVal;
3532
3533 StringPtr = ConfigElements;
3534
3535 while (1) {
3536 RetVal = StringPtr;
3537 if (*StringPtr != L'&') {
3538 return RetVal;
3539 }
3540 StringPtr += 1;
3541
3542 StringPtr = StrStr (StringPtr, L"&");
3543
3544 if (StringPtr == NULL) {
3545 return NULL;
3546 }
3547 }
3548}
3549
3550/**
3551 Validate the config request string.
3552
3553 @param ConfigRequest A null-terminated Unicode string in <ConfigRequest> format.
3554
3555 @retval CHAR16 * THE first element not correct.
3556 @retval NULL Success parse the name/value pair
3557
3558**/
3559CHAR16 *
3560ConfigRequestValidate (
3561 CHAR16 *ConfigRequest
3562 )
3563{
3564 BOOLEAN HasNameField;
3565 CHAR16 *StringPtr;
3566
3567 HasNameField = TRUE;
3568 StringPtr = ConfigRequest;
3569
3570 //
3571 // Check <ConfigHdr>
3572 //
3573 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3574 return ConfigRequest;
3575 }
3576 StringPtr += StrLen (L"GUID=");
3577 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
3578 StringPtr++;
3579 }
3580 if (*StringPtr == L'\0') {
3581 return ConfigRequest;
3582 }
3583 StringPtr += StrLen (L"&NAME=");
3584 if (*StringPtr == L'&') {
3585 HasNameField = FALSE;
3586 }
3587 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
3588 StringPtr++;
3589 }
3590 if (*StringPtr == L'\0') {
3591 return ConfigRequest;
3592 }
3593 StringPtr += StrLen (L"&PATH=");
3594 while (*StringPtr != L'\0' && *StringPtr != L'&') {
3595 StringPtr ++;
3596 }
3597
3598 if (*StringPtr == L'\0') {
3599 return NULL;
3600 }
3601
3602 if (HasNameField) {
3603 //
3604 // Should be Buffer varstore, config request should be "OFFSET/Width" pairs.
3605 //
3606 return OffsetWidthValidate(StringPtr);
3607 } else {
3608 //
3609 // Should be Name/Value varstore, config request should be "&name1&name2..." pairs.
3610 //
3611 return NameValueValidate(StringPtr);
3612 }
3613}
3614
3615/**
3616 This function allows a caller to extract the current configuration
3617 for one or more named elements from one or more drivers.
3618
3619 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3620 instance.
3621 @param Request A null-terminated Unicode string in
3622 <MultiConfigRequest> format.
3623 @param Progress On return, points to a character in the Request
3624 string. Points to the string's null terminator if
3625 request was successful. Points to the most recent
3626 & before the first failing name / value pair (or
3627 the beginning of the string if the failure is in
3628 the first name / value pair) if the request was
3629 not successful.
3630 @param Results Null-terminated Unicode string in
3631 <MultiConfigAltResp> format which has all values
3632 filled in for the names in the Request string.
3633 String to be allocated by the called function.
3634
3635 @retval EFI_SUCCESS The Results string is filled with the values
3636 corresponding to all requested names.
3637 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
3638 results that must be stored awaiting possible
3639 future protocols.
3640 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
3641 Progress set to the "G" in "GUID" of the routing
3642 header that doesn't match. Note: There is no
3643 requirement that all routing data be validated
3644 before any configuration extraction.
3645 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
3646 parameter would result in this type of error. The
3647 Progress parameter is set to NULL.
3648 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
3649 before the error or the beginning of the string.
3650 @retval EFI_INVALID_PARAMETER The ExtractConfig function of the underlying HII
3651 Configuration Access Protocol returned
3652 EFI_INVALID_PARAMETER. Progress set to most recent
3653 & before the error or the beginning of the string.
3654
3655**/
3656EFI_STATUS
3657EFIAPI
3658HiiConfigRoutingExtractConfig (
3659 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3660 IN CONST EFI_STRING Request,
3661 OUT EFI_STRING *Progress,
3662 OUT EFI_STRING *Results
3663 )
3664{
3665 HII_DATABASE_PRIVATE_DATA *Private;
3666 EFI_STRING StringPtr;
3667 EFI_STRING ConfigRequest;
3668 UINTN Length;
3669 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
3670 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
3671 EFI_STATUS Status;
3672 LIST_ENTRY *Link;
3673 HII_DATABASE_RECORD *Database;
3674 UINT8 *DevicePathPkg;
3675 UINT8 *CurrentDevicePath;
3676 EFI_HANDLE DriverHandle;
3677 EFI_HII_HANDLE HiiHandle;
3678 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
3679 EFI_STRING AccessProgress;
3680 EFI_STRING AccessResults;
3681 EFI_STRING DefaultResults;
3682 BOOLEAN FirstElement;
3683 BOOLEAN IfrDataParsedFlag;
3684 BOOLEAN IsEfiVarStore;
3685 EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
3686 EFI_STRING ErrorPtr;
3687 UINTN DevicePathSize;
3688
3689 if (This == NULL || Progress == NULL || Results == NULL) {
3690 return EFI_INVALID_PARAMETER;
3691 }
3692
3693 if (Request == NULL) {
3694 *Progress = NULL;
3695 return EFI_INVALID_PARAMETER;
3696 }
3697
3698 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3699 StringPtr = Request;
3700 *Progress = StringPtr;
3701 DefaultResults = NULL;
3702 ConfigRequest = NULL;
3703 Status = EFI_SUCCESS;
3704 AccessResults = NULL;
3705 AccessProgress = NULL;
3706 DevicePath = NULL;
3707 IfrDataParsedFlag = FALSE;
3708 IsEfiVarStore = FALSE;
3709 EfiVarStoreInfo = NULL;
3710
3711 //
3712 // The first element of <MultiConfigRequest> should be
3713 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
3714 //
3715 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3716 return EFI_INVALID_PARAMETER;
3717 }
3718
3719 FirstElement = TRUE;
3720
3721 //
3722 // Allocate a fix length of memory to store Results. Reallocate memory for
3723 // Results if this fix length is insufficient.
3724 //
3725 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
3726 if (*Results == NULL) {
3727 return EFI_OUT_OF_RESOURCES;
3728 }
3729
3730 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
3731 //
3732 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
3733 // or most recent & before the error.
3734 //
3735 if (StringPtr == Request) {
3736 *Progress = StringPtr;
3737 } else {
3738 *Progress = StringPtr - 1;
3739 }
3740
3741 //
3742 // Process each <ConfigRequest> of <MultiConfigRequest>
3743 //
3744 Length = CalculateConfigStringLen (StringPtr);
3745 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
3746 if (ConfigRequest == NULL) {
3747 Status = EFI_OUT_OF_RESOURCES;
3748 goto Done;
3749 }
3750 *(ConfigRequest + Length) = 0;
3751
3752 //
3753 // Get the UEFI device path
3754 //
3755 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
3756 if (EFI_ERROR (Status)) {
3757 goto Done;
3758 }
3759
3760 //
3761 // Find driver which matches the routing data.
3762 //
3763 DriverHandle = NULL;
3764 HiiHandle = NULL;
3765 Database = NULL;
3766 for (Link = Private->DatabaseList.ForwardLink;
3767 Link != &Private->DatabaseList;
3768 Link = Link->ForwardLink
3769 ) {
3770 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
3771 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
3772 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
3773 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
3774 if ((CompareMem (DevicePath,CurrentDevicePath,DevicePathSize) == 0) && IsThisPackageList(Database, ConfigRequest)) {
3775 DriverHandle = Database->DriverHandle;
3776 HiiHandle = Database->Handle;
3777 break;
3778 }
3779 }
3780 }
3781
3782 //
3783 // Try to find driver handle by device path.
3784 //
3785 if (DriverHandle == NULL) {
3786 TempDevicePath = DevicePath;
3787 Status = gBS->LocateDevicePath (
3788 &gEfiDevicePathProtocolGuid,
3789 &TempDevicePath,
3790 &DriverHandle
3791 );
3792 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
3793 //
3794 // Routing data does not match any known driver.
3795 // Set Progress to the 'G' in "GUID" of the routing header.
3796 //
3797 *Progress = StringPtr;
3798 Status = EFI_NOT_FOUND;
3799 goto Done;
3800 }
3801 }
3802
3803 //
3804 // Validate ConfigRequest String.
3805 //
3806 ErrorPtr = ConfigRequestValidate(ConfigRequest);
3807 if (ErrorPtr != NULL) {
3808 *Progress = StrStr (StringPtr, ErrorPtr);
3809 Status = EFI_INVALID_PARAMETER;
3810 goto Done;
3811 }
3812
3813 //
3814 // Check whether ConfigRequest contains request string.
3815 //
3816 IfrDataParsedFlag = FALSE;
3817 if ((HiiHandle != NULL) && !GetElementsFromRequest(ConfigRequest)) {
3818 //
3819 // Get the full request string from IFR when HiiPackage is registered to HiiHandle
3820 //
3821 IfrDataParsedFlag = TRUE;
3822 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
3823 if (EFI_ERROR (Status)) {
3824 //
3825 // AccessProgress indicates the parsing progress on <ConfigRequest>.
3826 // Map it to the progress on <MultiConfigRequest> then return it.
3827 //
3828 ASSERT (AccessProgress != NULL);
3829 *Progress = StrStr (StringPtr, AccessProgress);
3830 goto Done;
3831 }
3832 //
3833 // Not any request block is found.
3834 //
3835 if (!GetElementsFromRequest(ConfigRequest)) {
3836 AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
3837 goto NextConfigString;
3838 }
3839 }
3840
3841 //
3842 // Check whether this ConfigRequest is search from Efi varstore type storage.
3843 //
3844 Status = GetVarStoreType(Database, ConfigRequest, &IsEfiVarStore, &EfiVarStoreInfo);
3845 if (EFI_ERROR (Status)) {
3846 goto Done;
3847 }
3848
3849 if (IsEfiVarStore) {
3850 //
3851 // Call the GetVariable function to extract settings.
3852 //
3853 Status = GetConfigRespFromEfiVarStore(This, EfiVarStoreInfo, ConfigRequest, &AccessResults, &AccessProgress);
3854 FreePool (EfiVarStoreInfo);
3855 } else {
3856 //
3857 // Call corresponding ConfigAccess protocol to extract settings
3858 //
3859 Status = gBS->HandleProtocol (
3860 DriverHandle,
3861 &gEfiHiiConfigAccessProtocolGuid,
3862 (VOID **) &ConfigAccess
3863 );
3864 ASSERT_EFI_ERROR (Status);
3865
3866 Status = ConfigAccess->ExtractConfig (
3867 ConfigAccess,
3868 ConfigRequest,
3869 &AccessProgress,
3870 &AccessResults
3871 );
3872 }
3873 if (EFI_ERROR (Status)) {
3874 //
3875 // AccessProgress indicates the parsing progress on <ConfigRequest>.
3876 // Map it to the progress on <MultiConfigRequest> then return it.
3877 //
3878 *Progress = StrStr (StringPtr, AccessProgress);
3879 goto Done;
3880 }
3881
3882 //
3883 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
3884 // which seperates the first <ConfigAltResp> and the following ones.
3885 //
3886 ASSERT (*AccessProgress == 0);
3887
3888 //
3889 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
3890 //
3891 if (!IfrDataParsedFlag && HiiHandle != NULL) {
3892 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
3893 ASSERT_EFI_ERROR (Status);
3894 }
3895
3896 FreePool (DevicePath);
3897 DevicePath = NULL;
3898
3899 if (DefaultResults != NULL) {
3900 Status = MergeDefaultString (&AccessResults, DefaultResults);
3901 ASSERT_EFI_ERROR (Status);
3902 FreePool (DefaultResults);
3903 DefaultResults = NULL;
3904 }
3905
3906NextConfigString:
3907 if (!FirstElement) {
3908 Status = AppendToMultiString (Results, L"&");
3909 ASSERT_EFI_ERROR (Status);
3910 }
3911
3912 Status = AppendToMultiString (Results, AccessResults);
3913 ASSERT_EFI_ERROR (Status);
3914
3915 FirstElement = FALSE;
3916
3917 FreePool (AccessResults);
3918 AccessResults = NULL;
3919 FreePool (ConfigRequest);
3920 ConfigRequest = NULL;
3921
3922 //
3923 // Go to next <ConfigRequest> (skip '&').
3924 //
3925 StringPtr += Length;
3926 if (*StringPtr == 0) {
3927 *Progress = StringPtr;
3928 break;
3929 }
3930
3931 StringPtr++;
3932 }
3933
3934Done:
3935 if (EFI_ERROR (Status)) {
3936 FreePool (*Results);
3937 *Results = NULL;
3938 }
3939
3940 if (ConfigRequest != NULL) {
3941 FreePool (ConfigRequest);
3942 }
3943
3944 if (AccessResults != NULL) {
3945 FreePool (AccessResults);
3946 }
3947
3948 if (DefaultResults != NULL) {
3949 FreePool (DefaultResults);
3950 }
3951
3952 if (DevicePath != NULL) {
3953 FreePool (DevicePath);
3954 }
3955
3956 return Status;
3957}
3958
3959
3960/**
3961 This function allows the caller to request the current configuration for the
3962 entirety of the current HII database and returns the data in a
3963 null-terminated Unicode string.
3964
3965 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3966 instance.
3967 @param Results Null-terminated Unicode string in
3968 <MultiConfigAltResp> format which has all values
3969 filled in for the entirety of the current HII
3970 database. String to be allocated by the called
3971 function. De-allocation is up to the caller.
3972
3973 @retval EFI_SUCCESS The Results string is filled with the values
3974 corresponding to all requested names.
3975 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
3976 results that must be stored awaiting possible
3977 future protocols.
3978 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
3979 parameter would result in this type of error.
3980
3981**/
3982EFI_STATUS
3983EFIAPI
3984HiiConfigRoutingExportConfig (
3985 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3986 OUT EFI_STRING *Results
3987 )
3988{
3989 EFI_STATUS Status;
3990 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
3991 EFI_STRING AccessResults;
3992 EFI_STRING Progress;
3993 EFI_STRING StringPtr;
3994 EFI_STRING ConfigRequest;
3995 UINTN Index;
3996 EFI_HANDLE *ConfigAccessHandles;
3997 UINTN NumberConfigAccessHandles;
3998 BOOLEAN FirstElement;
3999 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
4000 EFI_HII_HANDLE HiiHandle;
4001 EFI_STRING DefaultResults;
4002 HII_DATABASE_PRIVATE_DATA *Private;
4003 LIST_ENTRY *Link;
4004 HII_DATABASE_RECORD *Database;
4005 UINT8 *DevicePathPkg;
4006 UINT8 *CurrentDevicePath;
4007 BOOLEAN IfrDataParsedFlag;
4008
4009 if (This == NULL || Results == NULL) {
4010 return EFI_INVALID_PARAMETER;
4011 }
4012
4013 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4014
4015 //
4016 // Allocate a fix length of memory to store Results. Reallocate memory for
4017 // Results if this fix length is insufficient.
4018 //
4019 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
4020 if (*Results == NULL) {
4021 return EFI_OUT_OF_RESOURCES;
4022 }
4023
4024 NumberConfigAccessHandles = 0;
4025 Status = gBS->LocateHandleBuffer (
4026 ByProtocol,
4027 &gEfiHiiConfigAccessProtocolGuid,
4028 NULL,
4029 &NumberConfigAccessHandles,
4030 &ConfigAccessHandles
4031 );
4032 if (EFI_ERROR (Status)) {
4033 return Status;
4034 }
4035
4036 FirstElement = TRUE;
4037
4038 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
4039 Status = gBS->HandleProtocol (
4040 ConfigAccessHandles[Index],
4041 &gEfiHiiConfigAccessProtocolGuid,
4042 (VOID **) &ConfigAccess
4043 );
4044 if (EFI_ERROR (Status)) {
4045 continue;
4046 }
4047
4048 //
4049 // Get DevicePath and HiiHandle for this ConfigAccess driver handle
4050 //
4051 IfrDataParsedFlag = FALSE;
4052 Progress = NULL;
4053 HiiHandle = NULL;
4054 DefaultResults = NULL;
4055 Database = NULL;
4056 ConfigRequest = NULL;
4057 DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
4058 if (DevicePath != NULL) {
4059 for (Link = Private->DatabaseList.ForwardLink;
4060 Link != &Private->DatabaseList;
4061 Link = Link->ForwardLink
4062 ) {
4063 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
4064 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
4065 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
4066 if (CompareMem (
4067 DevicePath,
4068 CurrentDevicePath,
4069 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
4070 ) == 0) {
4071 HiiHandle = Database->Handle;
4072 break;
4073 }
4074 }
4075 }
4076 }
4077
4078 Status = ConfigAccess->ExtractConfig (
4079 ConfigAccess,
4080 NULL,
4081 &Progress,
4082 &AccessResults
4083 );
4084 if (EFI_ERROR (Status)) {
4085 //
4086 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
4087 //
4088 if (HiiHandle != NULL && DevicePath != NULL) {
4089 IfrDataParsedFlag = TRUE;
4090 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
4091 //
4092 // Get the full request string to get the Current setting again.
4093 //
4094 if (!EFI_ERROR (Status) && ConfigRequest != NULL) {
4095 Status = ConfigAccess->ExtractConfig (
4096 ConfigAccess,
4097 ConfigRequest,
4098 &Progress,
4099 &AccessResults
4100 );
4101 FreePool (ConfigRequest);
4102 } else {
4103 Status = EFI_NOT_FOUND;
4104 }
4105 }
4106 }
4107
4108 if (!EFI_ERROR (Status)) {
4109 //
4110 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
4111 //
4112 if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {
4113 StringPtr = StrStr (AccessResults, L"&GUID=");
4114 if (StringPtr != NULL) {
4115 *StringPtr = 0;
4116 }
4117 if (GetElementsFromRequest (AccessResults)) {
4118 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
4119 ASSERT_EFI_ERROR (Status);
4120 }
4121 if (StringPtr != NULL) {
4122 *StringPtr = L'&';
4123 }
4124 }
4125 //
4126 // Merge the default sting from IFR code into the got setting from driver.
4127 //
4128 if (DefaultResults != NULL) {
4129 Status = MergeDefaultString (&AccessResults, DefaultResults);
4130 ASSERT_EFI_ERROR (Status);
4131 FreePool (DefaultResults);
4132 DefaultResults = NULL;
4133 }
4134
4135 //
4136 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
4137 // which seperates the first <ConfigAltResp> and the following ones.
4138 //
4139 if (!FirstElement) {
4140 Status = AppendToMultiString (Results, L"&");
4141 ASSERT_EFI_ERROR (Status);
4142 }
4143
4144 Status = AppendToMultiString (Results, AccessResults);
4145 ASSERT_EFI_ERROR (Status);
4146
4147 FirstElement = FALSE;
4148
4149 FreePool (AccessResults);
4150 AccessResults = NULL;
4151 }
4152 }
4153 FreePool (ConfigAccessHandles);
4154
4155 return EFI_SUCCESS;
4156}
4157
4158
4159/**
4160 This function processes the results of processing forms and routes it to the
4161 appropriate handlers or storage.
4162
4163 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4164 instance.
4165 @param Configuration A null-terminated Unicode string in
4166 <MulltiConfigResp> format.
4167 @param Progress A pointer to a string filled in with the offset of
4168 the most recent & before the first failing name /
4169 value pair (or the beginning of the string if the
4170 failure is in the first name / value pair) or the
4171 terminating NULL if all was successful.
4172
4173 @retval EFI_SUCCESS The results have been distributed or are awaiting
4174 distribution.
4175 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
4176 results that must be stored awaiting possible
4177 future protocols.
4178 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
4179 would result in this type of error.
4180 @retval EFI_NOT_FOUND Target for the specified routing data was not
4181 found.
4182
4183**/
4184EFI_STATUS
4185EFIAPI
4186HiiConfigRoutingRouteConfig (
4187 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4188 IN CONST EFI_STRING Configuration,
4189 OUT EFI_STRING *Progress
4190 )
4191{
4192 HII_DATABASE_PRIVATE_DATA *Private;
4193 EFI_STRING StringPtr;
4194 EFI_STRING ConfigResp;
4195 UINTN Length;
4196 EFI_STATUS Status;
4197 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
4198 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
4199 LIST_ENTRY *Link;
4200 HII_DATABASE_RECORD *Database;
4201 UINT8 *DevicePathPkg;
4202 UINT8 *CurrentDevicePath;
4203 EFI_HANDLE DriverHandle;
4204 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
4205 EFI_STRING AccessProgress;
4206 EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
4207 BOOLEAN IsEfiVarstore;
4208 UINTN DevicePathSize;
4209
4210 if (This == NULL || Progress == NULL) {
4211 return EFI_INVALID_PARAMETER;
4212 }
4213
4214 if (Configuration == NULL) {
4215 *Progress = NULL;
4216 return EFI_INVALID_PARAMETER;
4217 }
4218
4219 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4220 StringPtr = Configuration;
4221 *Progress = StringPtr;
4222 Database = NULL;
4223 AccessProgress = NULL;
4224 EfiVarStoreInfo= NULL;
4225 IsEfiVarstore = FALSE;
4226
4227 //
4228 // The first element of <MultiConfigResp> should be
4229 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
4230 //
4231 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4232 return EFI_INVALID_PARAMETER;
4233 }
4234
4235 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
4236 //
4237 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
4238 // or most recent & before the error.
4239 //
4240 if (StringPtr == Configuration) {
4241 *Progress = StringPtr;
4242 } else {
4243 *Progress = StringPtr - 1;
4244 }
4245
4246 //
4247 // Process each <ConfigResp> of <MultiConfigResp>
4248 //
4249 Length = CalculateConfigStringLen (StringPtr);
4250 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
4251 if (ConfigResp == NULL) {
4252 return EFI_OUT_OF_RESOURCES;
4253 }
4254 //
4255 // Append '\0' to the end of ConfigRequest
4256 //
4257 *(ConfigResp + Length) = 0;
4258
4259 //
4260 // Get the UEFI device path
4261 //
4262 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
4263 if (EFI_ERROR (Status)) {
4264 FreePool (ConfigResp);
4265 return Status;
4266 }
4267
4268 //
4269 // Find driver which matches the routing data.
4270 //
4271 DriverHandle = NULL;
4272 for (Link = Private->DatabaseList.ForwardLink;
4273 Link != &Private->DatabaseList;
4274 Link = Link->ForwardLink
4275 ) {
4276 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
4277
4278 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
4279 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
4280 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
4281 if ((CompareMem (DevicePath,CurrentDevicePath,DevicePathSize) == 0) && IsThisPackageList(Database, ConfigResp)) {
4282 DriverHandle = Database->DriverHandle;
4283 break;
4284 }
4285 }
4286 }
4287
4288 //
4289 // Try to find driver handle by device path.
4290 //
4291 if (DriverHandle == NULL) {
4292 TempDevicePath = DevicePath;
4293 Status = gBS->LocateDevicePath (
4294 &gEfiDevicePathProtocolGuid,
4295 &TempDevicePath,
4296 &DriverHandle
4297 );
4298 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
4299 //
4300 // Routing data does not match any known driver.
4301 // Set Progress to the 'G' in "GUID" of the routing header.
4302 //
4303 FreePool (DevicePath);
4304 *Progress = StringPtr;
4305 FreePool (ConfigResp);
4306 return EFI_NOT_FOUND;
4307 }
4308 }
4309
4310 FreePool (DevicePath);
4311
4312 //
4313 // Check whether this ConfigRequest is search from Efi varstore type storage.
4314 //
4315 Status = GetVarStoreType(Database, ConfigResp, &IsEfiVarstore, &EfiVarStoreInfo);
4316 if (EFI_ERROR (Status)) {
4317 return Status;
4318 }
4319
4320 if (IsEfiVarstore) {
4321 //
4322 // Call the SetVariable function to route settings.
4323 //
4324 Status = RouteConfigRespForEfiVarStore(This, EfiVarStoreInfo, ConfigResp, &AccessProgress);
4325 FreePool (EfiVarStoreInfo);
4326 } else {
4327 //
4328 // Call corresponding ConfigAccess protocol to route settings
4329 //
4330 Status = gBS->HandleProtocol (
4331 DriverHandle,
4332 &gEfiHiiConfigAccessProtocolGuid,
4333 (VOID **) &ConfigAccess
4334 );
4335 ASSERT_EFI_ERROR (Status);
4336
4337 Status = ConfigAccess->RouteConfig (
4338 ConfigAccess,
4339 ConfigResp,
4340 &AccessProgress
4341 );
4342 }
4343 if (EFI_ERROR (Status)) {
4344 ASSERT (AccessProgress != NULL);
4345 //
4346 // AccessProgress indicates the parsing progress on <ConfigResp>.
4347 // Map it to the progress on <MultiConfigResp> then return it.
4348 //
4349 *Progress = StrStr (StringPtr, AccessProgress);
4350
4351 FreePool (ConfigResp);
4352 return Status;
4353 }
4354
4355 FreePool (ConfigResp);
4356 ConfigResp = NULL;
4357
4358 //
4359 // Go to next <ConfigResp> (skip '&').
4360 //
4361 StringPtr += Length;
4362 if (*StringPtr == 0) {
4363 *Progress = StringPtr;
4364 break;
4365 }
4366
4367 StringPtr++;
4368
4369 }
4370
4371 return EFI_SUCCESS;
4372}
4373
4374
4375/**
4376 This helper function is to be called by drivers to map configuration data
4377 stored in byte array ("block") formats such as UEFI Variables into current
4378 configuration strings.
4379
4380 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4381 instance.
4382 @param ConfigRequest A null-terminated Unicode string in
4383 <ConfigRequest> format.
4384 @param Block Array of bytes defining the block's configuration.
4385 @param BlockSize Length in bytes of Block.
4386 @param Config Filled-in configuration string. String allocated
4387 by the function. Returned only if call is
4388 successful. It is <ConfigResp> string format.
4389 @param Progress A pointer to a string filled in with the offset of
4390 the most recent & before the first failing
4391 name/value pair (or the beginning of the string if
4392 the failure is in the first name / value pair) or
4393 the terminating NULL if all was successful.
4394
4395 @retval EFI_SUCCESS The request succeeded. Progress points to the null
4396 terminator at the end of the ConfigRequest
4397 string.
4398 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
4399 points to the first character of ConfigRequest.
4400 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
4401 Block parameter would result in this type of
4402 error. Progress points to the first character of
4403 ConfigRequest.
4404 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
4405 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
4406 Block is left updated and Progress points at
4407 the "&" preceding the first non-<BlockName>.
4408
4409**/
4410EFI_STATUS
4411EFIAPI
4412HiiBlockToConfig (
4413 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4414 IN CONST EFI_STRING ConfigRequest,
4415 IN CONST UINT8 *Block,
4416 IN CONST UINTN BlockSize,
4417 OUT EFI_STRING *Config,
4418 OUT EFI_STRING *Progress
4419 )
4420{
4421 HII_DATABASE_PRIVATE_DATA *Private;
4422 EFI_STRING StringPtr;
4423 UINTN Length;
4424 EFI_STATUS Status;
4425 EFI_STRING TmpPtr;
4426 UINT8 *TmpBuffer;
4427 UINTN Offset;
4428 UINTN Width;
4429 UINT8 *Value;
4430 EFI_STRING ValueStr;
4431 EFI_STRING ConfigElement;
4432 UINTN Index;
4433 UINT8 *TemBuffer;
4434 CHAR16 *TemString;
4435 CHAR16 TemChar;
4436
4437 TmpBuffer = NULL;
4438
4439 if (This == NULL || Progress == NULL || Config == NULL) {
4440 return EFI_INVALID_PARAMETER;
4441 }
4442
4443 if (Block == NULL || ConfigRequest == NULL) {
4444 *Progress = ConfigRequest;
4445 return EFI_INVALID_PARAMETER;
4446 }
4447
4448
4449 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4450 ASSERT (Private != NULL);
4451
4452 StringPtr = ConfigRequest;
4453 ValueStr = NULL;
4454 Value = NULL;
4455 ConfigElement = NULL;
4456
4457 //
4458 // Allocate a fix length of memory to store Results. Reallocate memory for
4459 // Results if this fix length is insufficient.
4460 //
4461 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
4462 if (*Config == NULL) {
4463 return EFI_OUT_OF_RESOURCES;
4464 }
4465
4466 //
4467 // Jump <ConfigHdr>
4468 //
4469 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4470 *Progress = StringPtr;
4471 Status = EFI_INVALID_PARAMETER;
4472 goto Exit;
4473 }
4474 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
4475 StringPtr++;
4476 }
4477 if (*StringPtr == 0) {
4478 *Progress = StringPtr - 1;
4479 Status = EFI_INVALID_PARAMETER;
4480 goto Exit;
4481 }
4482
4483 while (*StringPtr != L'&' && *StringPtr != 0) {
4484 StringPtr++;
4485 }
4486 if (*StringPtr == 0) {
4487 *Progress = StringPtr;
4488
4489 AppendToMultiString(Config, ConfigRequest);
4490 HiiToLower (*Config);
4491
4492 return EFI_SUCCESS;
4493 }
4494 //
4495 // Skip '&'
4496 //
4497 StringPtr++;
4498
4499 //
4500 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
4501 //
4502 TemChar = *StringPtr;
4503 *StringPtr = '\0';
4504 AppendToMultiString(Config, ConfigRequest);
4505 *StringPtr = TemChar;
4506
4507 //
4508 // Parse each <RequestElement> if exists
4509 // Only <BlockName> format is supported by this help function.
4510 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
4511 //
4512 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
4513 //
4514 // Back up the header of one <BlockName>
4515 //
4516 TmpPtr = StringPtr;
4517
4518 StringPtr += StrLen (L"OFFSET=");
4519 //
4520 // Get Offset
4521 //
4522 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4523 if (EFI_ERROR (Status)) {
4524 *Progress = TmpPtr - 1;
4525 goto Exit;
4526 }
4527 Offset = 0;
4528 CopyMem (
4529 &Offset,
4530 TmpBuffer,
4531 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4532 );
4533 FreePool (TmpBuffer);
4534
4535 StringPtr += Length;
4536 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
4537 *Progress = TmpPtr - 1;
4538 Status = EFI_INVALID_PARAMETER;
4539 goto Exit;
4540 }
4541 StringPtr += StrLen (L"&WIDTH=");
4542
4543 //
4544 // Get Width
4545 //
4546 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4547 if (EFI_ERROR (Status)) {
4548 *Progress = TmpPtr - 1;
4549 goto Exit;
4550 }
4551 Width = 0;
4552 CopyMem (
4553 &Width,
4554 TmpBuffer,
4555 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4556 );
4557 FreePool (TmpBuffer);
4558
4559 StringPtr += Length;
4560 if (*StringPtr != 0 && *StringPtr != L'&') {
4561 *Progress = TmpPtr - 1;
4562 Status = EFI_INVALID_PARAMETER;
4563 goto Exit;
4564 }
4565
4566 //
4567 // Calculate Value and convert it to hex string.
4568 //
4569 if (Offset + Width > BlockSize) {
4570 *Progress = StringPtr;
4571 Status = EFI_DEVICE_ERROR;
4572 goto Exit;
4573 }
4574
4575 Value = (UINT8 *) AllocateZeroPool (Width);
4576 if (Value == NULL) {
4577 *Progress = ConfigRequest;
4578 Status = EFI_OUT_OF_RESOURCES;
4579 goto Exit;
4580 }
4581
4582 CopyMem (Value, (UINT8 *) Block + Offset, Width);
4583
4584 Length = Width * 2 + 1;
4585 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
4586 if (ValueStr == NULL) {
4587 *Progress = ConfigRequest;
4588 Status = EFI_OUT_OF_RESOURCES;
4589 goto Exit;
4590 }
4591
4592 TemString = ValueStr;
4593 TemBuffer = Value + Width - 1;
4594 for (Index = 0; Index < Width; Index ++, TemBuffer --) {
4595 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
4596 }
4597
4598 FreePool (Value);
4599 Value = NULL;
4600
4601 //
4602 // Build a ConfigElement
4603 //
4604 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
4605 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
4606 if (ConfigElement == NULL) {
4607 Status = EFI_OUT_OF_RESOURCES;
4608 goto Exit;
4609 }
4610 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
4611 if (*StringPtr == 0) {
4612 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
4613 }
4614 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
4615 StrCat (ConfigElement, L"VALUE=");
4616 StrCat (ConfigElement, ValueStr);
4617
4618 AppendToMultiString (Config, ConfigElement);
4619
4620 FreePool (ConfigElement);
4621 FreePool (ValueStr);
4622 ConfigElement = NULL;
4623 ValueStr = NULL;
4624
4625 //
4626 // If '\0', parsing is finished. Otherwise skip '&' to continue
4627 //
4628 if (*StringPtr == 0) {
4629 break;
4630 }
4631 AppendToMultiString (Config, L"&");
4632 StringPtr++;
4633
4634 }
4635
4636 if (*StringPtr != 0) {
4637 *Progress = StringPtr - 1;
4638 Status = EFI_INVALID_PARAMETER;
4639 goto Exit;
4640 }
4641
4642 HiiToLower (*Config);
4643 *Progress = StringPtr;
4644 return EFI_SUCCESS;
4645
4646Exit:
4647 if (*Config != NULL) {
4648 FreePool (*Config);
4649 *Config = NULL;
4650 }
4651 if (ValueStr != NULL) {
4652 FreePool (ValueStr);
4653 }
4654 if (Value != NULL) {
4655 FreePool (Value);
4656 }
4657 if (ConfigElement != NULL) {
4658 FreePool (ConfigElement);
4659 }
4660
4661 return Status;
4662
4663}
4664
4665
4666/**
4667 This helper function is to be called by drivers to map configuration strings
4668 to configurations stored in byte array ("block") formats such as UEFI Variables.
4669
4670 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4671 instance.
4672 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
4673 format.
4674 @param Block A possibly null array of bytes representing the
4675 current block. Only bytes referenced in the
4676 ConfigResp string in the block are modified. If
4677 this parameter is null or if the *BlockSize
4678 parameter is (on input) shorter than required by
4679 the Configuration string, only the BlockSize
4680 parameter is updated and an appropriate status
4681 (see below) is returned.
4682 @param BlockSize The length of the Block in units of UINT8. On
4683 input, this is the size of the Block. On output,
4684 if successful, contains the largest index of the
4685 modified byte in the Block, or the required buffer
4686 size if the Block is not large enough.
4687 @param Progress On return, points to an element of the ConfigResp
4688 string filled in with the offset of the most
4689 recent '&' before the first failing name / value
4690 pair (or the beginning of the string if the
4691 failure is in the first name / value pair) or the
4692 terminating NULL if all was successful.
4693
4694 @retval EFI_SUCCESS The request succeeded. Progress points to the null
4695 terminator at the end of the ConfigResp string.
4696 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
4697 points to the first character of ConfigResp.
4698 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
4699 Block parameter would result in this type of
4700 error. Progress points to the first character of
4701 ConfigResp.
4702 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
4703 value pair. Block is left updated and
4704 Progress points at the '&' preceding the first
4705 non-<BlockName>.
4706 @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined.
4707 BlockSize is updated with the required buffer size.
4708 @retval EFI_NOT_FOUND Target for the specified routing data was not found.
4709 Progress points to the "G" in "GUID" of the errant
4710 routing data.
4711
4712**/
4713EFI_STATUS
4714EFIAPI
4715HiiConfigToBlock (
4716 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4717 IN CONST EFI_STRING ConfigResp,
4718 IN OUT UINT8 *Block,
4719 IN OUT UINTN *BlockSize,
4720 OUT EFI_STRING *Progress
4721 )
4722{
4723 HII_DATABASE_PRIVATE_DATA *Private;
4724 EFI_STRING StringPtr;
4725 EFI_STRING TmpPtr;
4726 UINTN Length;
4727 EFI_STATUS Status;
4728 UINT8 *TmpBuffer;
4729 UINTN Offset;
4730 UINTN Width;
4731 UINT8 *Value;
4732 UINTN BufferSize;
4733 UINTN MaxBlockSize;
4734
4735 TmpBuffer = NULL;
4736
4737 if (This == NULL || BlockSize == NULL || Progress == NULL) {
4738 return EFI_INVALID_PARAMETER;
4739 }
4740
4741 *Progress = ConfigResp;
4742 if (ConfigResp == NULL) {
4743 return EFI_INVALID_PARAMETER;
4744 }
4745
4746 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4747 ASSERT (Private != NULL);
4748
4749 StringPtr = ConfigResp;
4750 BufferSize = *BlockSize;
4751 Value = NULL;
4752 MaxBlockSize = 0;
4753
4754 //
4755 // Jump <ConfigHdr>
4756 //
4757 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4758 *Progress = StringPtr;
4759 Status = EFI_INVALID_PARAMETER;
4760 goto Exit;
4761 }
4762 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
4763 StringPtr++;
4764 }
4765 if (*StringPtr == 0) {
4766 *Progress = StringPtr;
4767 Status = EFI_INVALID_PARAMETER;
4768 goto Exit;
4769 }
4770
4771 while (*StringPtr != L'&' && *StringPtr != 0) {
4772 StringPtr++;
4773 }
4774 if (*StringPtr == 0) {
4775 *Progress = StringPtr;
4776 Status = EFI_INVALID_PARAMETER;
4777 goto Exit;
4778 }
4779
4780 //
4781 // Parse each <ConfigElement> if exists
4782 // Only '&'<BlockConfig> format is supported by this help function.
4783 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
4784 //
4785 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
4786 TmpPtr = StringPtr;
4787 StringPtr += StrLen (L"&OFFSET=");
4788 //
4789 // Get Offset
4790 //
4791 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4792 if (EFI_ERROR (Status)) {
4793 *Progress = TmpPtr;
4794 goto Exit;
4795 }
4796 Offset = 0;
4797 CopyMem (
4798 &Offset,
4799 TmpBuffer,
4800 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4801 );
4802 FreePool (TmpBuffer);
4803
4804 StringPtr += Length;
4805 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
4806 *Progress = TmpPtr;
4807 Status = EFI_INVALID_PARAMETER;
4808 goto Exit;
4809 }
4810 StringPtr += StrLen (L"&WIDTH=");
4811
4812 //
4813 // Get Width
4814 //
4815 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
4816 if (EFI_ERROR (Status)) {
4817 *Progress = TmpPtr;
4818 goto Exit;
4819 }
4820 Width = 0;
4821 CopyMem (
4822 &Width,
4823 TmpBuffer,
4824 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
4825 );
4826 FreePool (TmpBuffer);
4827
4828 StringPtr += Length;
4829 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
4830 *Progress = TmpPtr;
4831 Status = EFI_INVALID_PARAMETER;
4832 goto Exit;
4833 }
4834 StringPtr += StrLen (L"&VALUE=");
4835
4836 //
4837 // Get Value
4838 //
4839 Status = GetValueOfNumber (StringPtr, &Value, &Length);
4840 if (EFI_ERROR (Status)) {
4841 *Progress = TmpPtr;
4842 goto Exit;
4843 }
4844
4845 StringPtr += Length;
4846 if (*StringPtr != 0 && *StringPtr != L'&') {
4847 *Progress = TmpPtr;
4848 Status = EFI_INVALID_PARAMETER;
4849 goto Exit;
4850 }
4851
4852 //
4853 // Update the Block with configuration info
4854 //
4855 if ((Block != NULL) && (Offset + Width <= BufferSize)) {
4856 CopyMem (Block + Offset, Value, Width);
4857 }
4858 if (Offset + Width > MaxBlockSize) {
4859 MaxBlockSize = Offset + Width;
4860 }
4861
4862 FreePool (Value);
4863 Value = NULL;
4864
4865 //
4866 // If '\0', parsing is finished.
4867 //
4868 if (*StringPtr == 0) {
4869 break;
4870 }
4871 }
4872
4873 //
4874 // The input string is not ConfigResp format, return error.
4875 //
4876 if (*StringPtr != 0) {
4877 *Progress = StringPtr;
4878 Status = EFI_INVALID_PARAMETER;
4879 goto Exit;
4880 }
4881
4882 *Progress = StringPtr + StrLen (StringPtr);
4883 *BlockSize = MaxBlockSize - 1;
4884
4885 if (MaxBlockSize > BufferSize) {
4886 *BlockSize = MaxBlockSize;
4887 if (Block != NULL) {
4888 return EFI_BUFFER_TOO_SMALL;
4889 }
4890 }
4891
4892 if (Block == NULL) {
4893 *Progress = ConfigResp;
4894 return EFI_INVALID_PARAMETER;
4895 }
4896
4897 return EFI_SUCCESS;
4898
4899Exit:
4900
4901 if (Value != NULL) {
4902 FreePool (Value);
4903 }
4904 return Status;
4905}
4906
4907
4908/**
4909 This helper function is to be called by drivers to extract portions of
4910 a larger configuration string.
4911
4912 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4913 instance.
4914 @param Configuration A null-terminated Unicode string in
4915 <MultiConfigAltResp> format.
4916 @param Guid A pointer to the GUID value to search for in the
4917 routing portion of the ConfigResp string when
4918 retrieving the requested data. If Guid is NULL,
4919 then all GUID values will be searched for.
4920 @param Name A pointer to the NAME value to search for in the
4921 routing portion of the ConfigResp string when
4922 retrieving the requested data. If Name is NULL,
4923 then all Name values will be searched for.
4924 @param DevicePath A pointer to the PATH value to search for in the
4925 routing portion of the ConfigResp string when
4926 retrieving the requested data. If DevicePath is
4927 NULL, then all DevicePath values will be searched
4928 for.
4929 @param AltCfgId A pointer to the ALTCFG value to search for in the
4930 routing portion of the ConfigResp string when
4931 retrieving the requested data. If this parameter
4932 is NULL, then the current setting will be
4933 retrieved.
4934 @param AltCfgResp A pointer to a buffer which will be allocated by
4935 the function which contains the retrieved string
4936 as requested. This buffer is only allocated if
4937 the call was successful. It is <ConfigResp> format.
4938
4939 @retval EFI_SUCCESS The request succeeded. The requested data was
4940 extracted and placed in the newly allocated
4941 AltCfgResp buffer.
4942 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
4943 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
4944 @retval EFI_NOT_FOUND Target for the specified routing data was not
4945 found.
4946
4947**/
4948EFI_STATUS
4949EFIAPI
4950HiiGetAltCfg (
4951 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4952 IN CONST EFI_STRING Configuration,
4953 IN CONST EFI_GUID *Guid,
4954 IN CONST EFI_STRING Name,
4955 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
4956 IN CONST UINT16 *AltCfgId,
4957 OUT EFI_STRING *AltCfgResp
4958 )
4959{
4960 EFI_STATUS Status;
4961 EFI_STRING StringPtr;
4962 EFI_STRING HdrStart;
4963 EFI_STRING HdrEnd;
4964 EFI_STRING TmpPtr;
4965 UINTN Length;
4966 EFI_STRING GuidStr;
4967 EFI_STRING NameStr;
4968 EFI_STRING PathStr;
4969 EFI_STRING AltIdStr;
4970 EFI_STRING Result;
4971 BOOLEAN GuidFlag;
4972 BOOLEAN NameFlag;
4973 BOOLEAN PathFlag;
4974
4975 HdrStart = NULL;
4976 HdrEnd = NULL;
4977 GuidStr = NULL;
4978 NameStr = NULL;
4979 PathStr = NULL;
4980 AltIdStr = NULL;
4981 Result = NULL;
4982 GuidFlag = FALSE;
4983 NameFlag = FALSE;
4984 PathFlag = FALSE;
4985
4986 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
4987 return EFI_INVALID_PARAMETER;
4988 }
4989
4990 StringPtr = Configuration;
4991 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4992 return EFI_INVALID_PARAMETER;
4993 }
4994
4995 //
4996 // Generate the sub string for later matching.
4997 //
4998 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
4999 GenerateSubStr (
5000 L"PATH=",
5001 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
5002 (VOID *) DevicePath,
5003 1,
5004 &PathStr
5005 );
5006 if (AltCfgId != NULL) {
5007 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
5008 }
5009 if (Name != NULL) {
5010 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
5011 } else {
5012 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
5013 }
5014
5015 while (*StringPtr != 0) {
5016 //
5017 // Try to match the GUID
5018 //
5019 if (!GuidFlag) {
5020 TmpPtr = StrStr (StringPtr, GuidStr);
5021 if (TmpPtr == NULL) {
5022 Status = EFI_NOT_FOUND;
5023 goto Exit;
5024 }
5025 HdrStart = TmpPtr;
5026
5027 //
5028 // Jump to <NameHdr>
5029 //
5030 if (Guid != NULL) {
5031 StringPtr = TmpPtr + StrLen (GuidStr);
5032 } else {
5033 StringPtr = StrStr (TmpPtr, L"NAME=");
5034 if (StringPtr == NULL) {
5035 Status = EFI_NOT_FOUND;
5036 goto Exit;
5037 }
5038 }
5039 GuidFlag = TRUE;
5040 }
5041
5042 //
5043 // Try to match the NAME
5044 //
5045 if (GuidFlag && !NameFlag) {
5046 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
5047 GuidFlag = FALSE;
5048 } else {
5049 //
5050 // Jump to <PathHdr>
5051 //
5052 if (Name != NULL) {
5053 StringPtr += StrLen (NameStr);
5054 } else {
5055 StringPtr = StrStr (StringPtr, L"PATH=");
5056 if (StringPtr == NULL) {
5057 Status = EFI_NOT_FOUND;
5058 goto Exit;
5059 }
5060 }
5061 NameFlag = TRUE;
5062 }
5063 }
5064
5065 //
5066 // Try to match the DevicePath
5067 //
5068 if (GuidFlag && NameFlag && !PathFlag) {
5069 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
5070 GuidFlag = FALSE;
5071 NameFlag = FALSE;
5072 } else {
5073 //
5074 // Jump to '&' before <DescHdr> or <ConfigBody>
5075 //
5076 if (DevicePath != NULL) {
5077 StringPtr += StrLen (PathStr);
5078 } else {
5079 StringPtr = StrStr (StringPtr, L"&");
5080 if (StringPtr == NULL) {
5081 Status = EFI_NOT_FOUND;
5082 goto Exit;
5083 }
5084 StringPtr ++;
5085 }
5086 PathFlag = TRUE;
5087 HdrEnd = StringPtr;
5088 }
5089 }
5090
5091 //
5092 // Try to match the AltCfgId
5093 //
5094 if (GuidFlag && NameFlag && PathFlag) {
5095 if (AltCfgId == NULL) {
5096 //
5097 // Return Current Setting when AltCfgId is NULL.
5098 //
5099 Status = OutputConfigBody (StringPtr, &Result);
5100 goto Exit;
5101 }
5102 //
5103 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
5104 //
5105 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
5106 GuidFlag = FALSE;
5107 NameFlag = FALSE;
5108 PathFlag = FALSE;
5109 } else {
5110 //
5111 // Skip AltIdStr and &
5112 //
5113 StringPtr = StringPtr + StrLen (AltIdStr);
5114 Status = OutputConfigBody (StringPtr, &Result);
5115 goto Exit;
5116 }
5117 }
5118 }
5119
5120 Status = EFI_NOT_FOUND;
5121
5122Exit:
5123 *AltCfgResp = NULL;
5124 if (!EFI_ERROR (Status) && (Result != NULL)) {
5125 //
5126 // Copy the <ConfigHdr> and <ConfigBody>
5127 //
5128 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
5129 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
5130 if (*AltCfgResp == NULL) {
5131 Status = EFI_OUT_OF_RESOURCES;
5132 } else {
5133 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
5134 StrCat (*AltCfgResp, Result);
5135 Status = EFI_SUCCESS;
5136 }
5137 }
5138
5139 if (GuidStr != NULL) {
5140 FreePool (GuidStr);
5141 }
5142 if (NameStr != NULL) {
5143 FreePool (NameStr);
5144 }
5145 if (PathStr != NULL) {
5146 FreePool (PathStr);
5147 }
5148 if (AltIdStr != NULL) {
5149 FreePool (AltIdStr);
5150 }
5151 if (Result != NULL) {
5152 FreePool (Result);
5153 }
5154
5155 return Status;
5156
5157}
5158
5159