]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
Add the missing logic in HiiConfigRouting ExtractConfig() to retrieves FALSE as defau...
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
1 /** @file
2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
3
4 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "HiiDatabase.h"
17 extern 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 **/
31 UINTN
32 CalculateConfigStringLen (
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 **/
73 EFI_STATUS
74 GetDevicePath (
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 **/
174 VOID
175 EFIAPI
176 HiiToLower (
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 **/
223 VOID
224 GenerateSubStr (
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 **/
322 EFI_STATUS
323 OutputConfigBody (
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 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
359 if (Result == NULL) {
360 return EFI_OUT_OF_RESOURCES;
361 }
362
363 *(Result + Length - 1) = 0;
364 *ConfigBody = Result;
365 return EFI_SUCCESS;
366 }
367
368 /**
369 Append a string to a multi-string format.
370
371 This is a internal function.
372
373 @param MultiString String in <MultiConfigRequest>,
374 <MultiConfigAltResp>, or <MultiConfigResp>. On
375 input, the buffer length of this string is
376 MAX_STRING_LENGTH. On output, the buffer length
377 might be updated.
378 @param AppendString NULL-terminated Unicode string.
379
380 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
381 @retval EFI_SUCCESS AppendString is append to the end of MultiString
382
383 **/
384 EFI_STATUS
385 AppendToMultiString (
386 IN OUT EFI_STRING *MultiString,
387 IN EFI_STRING AppendString
388 )
389 {
390 UINTN AppendStringSize;
391 UINTN MultiStringSize;
392
393 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
394 return EFI_INVALID_PARAMETER;
395 }
396
397 AppendStringSize = StrSize (AppendString);
398 MultiStringSize = StrSize (*MultiString);
399
400 //
401 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
402 //
403 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
404 MultiStringSize > MAX_STRING_LENGTH) {
405 *MultiString = (EFI_STRING) ReallocatePool (
406 MultiStringSize,
407 MultiStringSize + AppendStringSize,
408 (VOID *) (*MultiString)
409 );
410 ASSERT (*MultiString != NULL);
411 }
412 //
413 // Append the incoming string
414 //
415 StrCat (*MultiString, AppendString);
416
417 return EFI_SUCCESS;
418 }
419
420
421 /**
422 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
423 or WIDTH or VALUE.
424 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
425
426 This is a internal function.
427
428 @param StringPtr String in <BlockConfig> format and points to the
429 first character of <Number>.
430 @param Number The output value. Caller takes the responsibility
431 to free memory.
432 @param Len Length of the <Number>, in characters.
433
434 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
435 structures.
436 @retval EFI_SUCCESS Value of <Number> is outputted in Number
437 successfully.
438
439 **/
440 EFI_STATUS
441 GetValueOfNumber (
442 IN EFI_STRING StringPtr,
443 OUT UINT8 **Number,
444 OUT UINTN *Len
445 )
446 {
447 EFI_STRING TmpPtr;
448 UINTN Length;
449 EFI_STRING Str;
450 UINT8 *Buf;
451 EFI_STATUS Status;
452 UINT8 DigitUint8;
453 UINTN Index;
454 CHAR16 TemStr[2];
455
456 if (StringPtr == NULL || *StringPtr == L'\0' || Number == NULL || Len == NULL) {
457 return EFI_INVALID_PARAMETER;
458 }
459
460 Buf = NULL;
461
462 TmpPtr = StringPtr;
463 while (*StringPtr != L'\0' && *StringPtr != L'&') {
464 StringPtr++;
465 }
466 *Len = StringPtr - TmpPtr;
467 Length = *Len + 1;
468
469 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
470 if (Str == NULL) {
471 Status = EFI_OUT_OF_RESOURCES;
472 goto Exit;
473 }
474 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
475 *(Str + *Len) = L'\0';
476
477 Length = (Length + 1) / 2;
478 Buf = (UINT8 *) AllocateZeroPool (Length);
479 if (Buf == NULL) {
480 Status = EFI_OUT_OF_RESOURCES;
481 goto Exit;
482 }
483
484 Length = *Len;
485 ZeroMem (TemStr, sizeof (TemStr));
486 for (Index = 0; Index < Length; Index ++) {
487 TemStr[0] = Str[Length - Index - 1];
488 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
489 if ((Index & 1) == 0) {
490 Buf [Index/2] = DigitUint8;
491 } else {
492 Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
493 }
494 }
495
496 *Number = Buf;
497 Status = EFI_SUCCESS;
498
499 Exit:
500 if (Str != NULL) {
501 FreePool (Str);
502 }
503
504 return Status;
505 }
506
507 /**
508 This function merges DefaultAltCfgResp string into AltCfgResp string for
509 the missing AltCfgId in AltCfgResq.
510
511 @param AltCfgResp Pointer to a null-terminated Unicode string in
512 <ConfigAltResp> format. The default value string
513 will be merged into it.
514 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
515 <MultiConfigAltResp> format. The default value
516 string may contain more than one ConfigAltResp
517 string for the different varstore buffer.
518
519 @retval EFI_SUCCESS The merged string returns.
520 @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.
521 **/
522 EFI_STATUS
523 EFIAPI
524 MergeDefaultString (
525 IN OUT EFI_STRING *AltCfgResp,
526 IN EFI_STRING DefaultAltCfgResp
527 )
528 {
529 EFI_STRING StringPtrDefault;
530 EFI_STRING StringPtrEnd;
531 CHAR16 TempChar;
532 EFI_STRING StringPtr;
533 EFI_STRING AltConfigHdr;
534 UINTN HeaderLength;
535 UINTN SizeAltCfgResp;
536
537 if (*AltCfgResp == NULL) {
538 return EFI_INVALID_PARAMETER;
539 }
540
541 //
542 // Get the requestr ConfigHdr
543 //
544 SizeAltCfgResp = 0;
545 StringPtr = *AltCfgResp;
546
547 //
548 // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
549 //
550 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
551 return EFI_INVALID_PARAMETER;
552 }
553 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
554 StringPtr++;
555 }
556 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
557 StringPtr++;
558 }
559 if (*StringPtr == L'\0') {
560 return EFI_INVALID_PARAMETER;
561 }
562 StringPtr += StrLen (L"&PATH=");
563 while (*StringPtr != L'\0' && *StringPtr != L'&') {
564 StringPtr ++;
565 }
566 HeaderLength = StringPtr - *AltCfgResp;
567
568 //
569 // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"
570 // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
571 //
572 AltConfigHdr = AllocateZeroPool ((1 + HeaderLength + 8 + 4 + 1) * sizeof (CHAR16));
573 if (AltConfigHdr == NULL) {
574 return EFI_OUT_OF_RESOURCES;
575 }
576 StrCpy (AltConfigHdr, L"&");
577 StrnCat (AltConfigHdr, *AltCfgResp, HeaderLength);
578 StrCat (AltConfigHdr, L"&ALTCFG=");
579 HeaderLength = StrLen (AltConfigHdr);
580
581 StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
582 while (StringPtrDefault != NULL) {
583 //
584 // Get AltCfg Name
585 //
586 StrnCat (AltConfigHdr, StringPtrDefault + HeaderLength, 4);
587 StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
588
589 //
590 // Append the found default value string to the input AltCfgResp
591 //
592 if (StringPtr == NULL) {
593 StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");
594 SizeAltCfgResp = StrSize (*AltCfgResp);
595 if (StringPtrEnd == NULL) {
596 //
597 // No more default string is found.
598 //
599 *AltCfgResp = (EFI_STRING) ReallocatePool (
600 SizeAltCfgResp,
601 SizeAltCfgResp + StrSize (StringPtrDefault),
602 (VOID *) (*AltCfgResp)
603 );
604 if (*AltCfgResp == NULL) {
605 FreePool (AltConfigHdr);
606 return EFI_OUT_OF_RESOURCES;
607 }
608 StrCat (*AltCfgResp, StringPtrDefault);
609 break;
610 } else {
611 TempChar = *StringPtrEnd;
612 *StringPtrEnd = L'\0';
613 *AltCfgResp = (EFI_STRING) ReallocatePool (
614 SizeAltCfgResp,
615 SizeAltCfgResp + StrSize (StringPtrDefault),
616 (VOID *) (*AltCfgResp)
617 );
618 if (*AltCfgResp == NULL) {
619 FreePool (AltConfigHdr);
620 return EFI_OUT_OF_RESOURCES;
621 }
622 StrCat (*AltCfgResp, StringPtrDefault);
623 *StringPtrEnd = TempChar;
624 }
625 }
626
627 //
628 // Find next AltCfg String
629 //
630 *(AltConfigHdr + HeaderLength) = L'\0';
631 StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
632 }
633
634 FreePool (AltConfigHdr);
635 return EFI_SUCCESS;
636 }
637
638 /**
639 This function inserts new DefaultValueData into the BlockData DefaultValue array.
640
641 @param BlockData The BlockData is updated to add new default value.
642 @param DefaultValueData The DefaultValue is added.
643
644 **/
645 VOID
646 InsertDefaultValue (
647 IN IFR_BLOCK_DATA *BlockData,
648 IN IFR_DEFAULT_DATA *DefaultValueData
649 )
650 {
651 LIST_ENTRY *Link;
652 IFR_DEFAULT_DATA *DefaultValueArray;
653
654 for (Link = BlockData->DefaultValueEntry.ForwardLink; Link != &BlockData->DefaultValueEntry; Link = Link->ForwardLink) {
655 DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
656 if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
657 if (DefaultValueData->OpCode == EFI_IFR_DEFAULT_OP) {
658 //
659 // Update the default value array in BlockData.
660 //
661 DefaultValueArray->Value = DefaultValueData->Value;
662 } else if (DefaultValueArray->OpCode != EFI_IFR_DEFAULT_OP) {
663 //
664 // Update the default value array in BlockData.
665 //
666 DefaultValueArray->Value = DefaultValueData->Value;
667 }
668 FreePool (DefaultValueData);
669 return;
670 } else if (DefaultValueArray->DefaultId > DefaultValueData->DefaultId) {
671 //
672 // Insert new default value data in the front of this default value array.
673 //
674 InsertTailList (Link, &DefaultValueData->Entry);
675 return;
676 }
677 }
678
679 //
680 // Insert new default value data in tail.
681 //
682 InsertTailList (Link, &DefaultValueData->Entry);
683 return;
684 }
685
686 /**
687 This function inserts new BlockData into the block link
688
689 @param BlockLink The list entry points to block array.
690 @param BlockData The point to BlockData is added.
691
692 **/
693 VOID
694 InsertBlockData (
695 IN LIST_ENTRY *BlockLink,
696 IN IFR_BLOCK_DATA **BlockData
697 )
698 {
699 LIST_ENTRY *Link;
700 IFR_BLOCK_DATA *BlockArray;
701 IFR_BLOCK_DATA *BlockSingleData;
702
703 BlockSingleData = *BlockData;
704
705 //
706 // Insert block data in its Offset and Width order.
707 //
708 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
709 BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
710 if (BlockArray->Offset == BlockSingleData->Offset) {
711 if (BlockArray->Width > BlockSingleData->Width) {
712 //
713 // Insert this block data in the front of block array
714 //
715 InsertTailList (Link, &BlockSingleData->Entry);
716 return;
717 }
718
719 if (BlockArray->Width == BlockSingleData->Width) {
720 //
721 // The same block array has been added.
722 //
723 FreePool (BlockSingleData);
724 *BlockData = BlockArray;
725 return;
726 }
727 } else if (BlockArray->Offset > BlockSingleData->Offset) {
728 //
729 // Insert new block data in the front of block array
730 //
731 InsertTailList (Link, &BlockSingleData->Entry);
732 return;
733 }
734 }
735
736 //
737 // Add new block data into the tail.
738 //
739 InsertTailList (Link, &BlockSingleData->Entry);
740 return;
741 }
742
743 /**
744 This function checks VarOffset and VarWidth is in the block range.
745
746 @param RequestBlockArray The block array is to be checked.
747 @param VarOffset Offset of var to the structure
748 @param VarWidth Width of var.
749
750 @retval TRUE This Var is in the block range.
751 @retval FALSE This Var is not in the block range.
752 **/
753 BOOLEAN
754 BlockArrayCheck (
755 IN IFR_BLOCK_DATA *RequestBlockArray,
756 IN UINT16 VarOffset,
757 IN UINT16 VarWidth
758 )
759 {
760 LIST_ENTRY *Link;
761 IFR_BLOCK_DATA *BlockData;
762
763 //
764 // No Request Block array, all vars are got.
765 //
766 if (RequestBlockArray == NULL) {
767 return TRUE;
768 }
769
770 //
771 // Check the input var is in the request block range.
772 //
773 for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
774 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
775 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
776 return TRUE;
777 }
778 }
779
780 return FALSE;
781 }
782
783 /**
784 This function parses Form Package to get the block array and the default
785 value array according to the request ConfigHdr.
786
787 @param Package Pointer to the form package data.
788 @param PackageLength Length of the pacakge.
789 @param ConfigHdr Request string ConfigHdr. If it is NULL,
790 the first found varstore will be as ConfigHdr.
791 @param RequestBlockArray The block array is retrieved from the request string.
792 @param VarStorageData VarStorage structure contains the got block and default value.
793 @param PIfrDefaultIdArray Point to the got default id and default name array.
794
795 @retval EFI_SUCCESS The block array and the default value array are got.
796 @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges
797 are conflicted.
798 @retval EFI_OUT_OF_RESOURCES No enough memory.
799 **/
800 EFI_STATUS
801 EFIAPI
802 ParseIfrData (
803 IN UINT8 *Package,
804 IN UINT32 PackageLength,
805 IN EFI_STRING ConfigHdr,
806 IN IFR_BLOCK_DATA *RequestBlockArray,
807 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
808 OUT IFR_DEFAULT_DATA *DefaultIdArray
809 )
810 {
811 EFI_STATUS Status;
812 UINTN IfrOffset;
813 EFI_IFR_VARSTORE *IfrVarStore;
814 EFI_IFR_OP_HEADER *IfrOpHdr;
815 EFI_IFR_ONE_OF *IfrOneOf;
816 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
817 EFI_IFR_DEFAULT *IfrDefault;
818 EFI_IFR_ORDERED_LIST *IfrOrderedList;
819 EFI_IFR_CHECKBOX *IfrCheckBox;
820 EFI_IFR_PASSWORD *IfrPassword;
821 EFI_IFR_STRING *IfrString;
822 IFR_DEFAULT_DATA *DefaultData;
823 IFR_BLOCK_DATA *BlockData;
824 CHAR16 *VarStoreName;
825 UINT16 VarOffset;
826 UINT16 VarWidth;
827 EFI_STRING_ID VarDefaultName;
828 UINT16 VarDefaultId;
829 EFI_STRING GuidStr;
830 EFI_STRING NameStr;
831 EFI_STRING TempStr;
832 UINTN LengthString;
833 BOOLEAN FirstOneOfOption;
834
835 LengthString = 0;
836 Status = EFI_SUCCESS;
837 GuidStr = NULL;
838 NameStr = NULL;
839 TempStr = NULL;
840 BlockData = NULL;
841 DefaultData = NULL;
842 VarDefaultName = 0;
843 FirstOneOfOption = FALSE;
844
845 //
846 // Go through the form package to parse OpCode one by one.
847 //
848 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
849 while (IfrOffset < PackageLength) {
850 IfrOpHdr = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);
851
852 switch (IfrOpHdr->OpCode) {
853 case EFI_IFR_VARSTORE_OP:
854 //
855 // VarStore is found. Don't need to search any more.
856 //
857 if (VarStorageData->Size != 0) {
858 break;
859 }
860
861 //
862 // Get the requied varstore information
863 // Add varstore by Guid and Name in ConfigHdr
864 // Make sure Offset is in varstore size and varstoreid
865 //
866 IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
867 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
868 if (VarStoreName == NULL) {
869 Status = EFI_OUT_OF_RESOURCES;
870 goto Done;
871 }
872 AsciiStrToUnicodeStr ((CHAR8 *) IfrVarStore->Name, VarStoreName);
873
874 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrVarStore->Guid, 1, &GuidStr);
875 GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);
876 LengthString = StrLen (GuidStr);
877 LengthString = LengthString + StrLen (NameStr) + 1;
878 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
879 if (TempStr == NULL) {
880 FreePool (GuidStr);
881 FreePool (NameStr);
882 FreePool (VarStoreName);
883 Status = EFI_OUT_OF_RESOURCES;
884 goto Done;
885 }
886 StrCpy (TempStr, GuidStr);
887 StrCat (TempStr, NameStr);
888 if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
889 //
890 // Find the matched VarStore
891 //
892 CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);
893 VarStorageData->VarStoreId = IfrVarStore->VarStoreId;
894 VarStorageData->Size = IfrVarStore->Size;
895 VarStorageData->Name = VarStoreName;
896 } else {
897 //
898 // No found, free the allocated memory
899 //
900 FreePool (VarStoreName);
901 }
902 //
903 // Free alllocated temp string.
904 //
905 FreePool (GuidStr);
906 FreePool (NameStr);
907 FreePool (TempStr);
908 break;
909
910 case EFI_IFR_DEFAULTSTORE_OP:
911 //
912 // Add new the map between default id and default name.
913 //
914 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
915 if (DefaultData == NULL) {
916 Status = EFI_OUT_OF_RESOURCES;
917 goto Done;
918 }
919 DefaultData->DefaultId = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
920 InsertTailList (&DefaultIdArray->Entry, &DefaultData->Entry);
921 DefaultData = NULL;
922 break;
923
924 case EFI_IFR_FORM_OP:
925 case EFI_IFR_FORM_MAP_OP:
926 //
927 // No matched varstore is found and directly return.
928 //
929 if (VarStorageData->Size == 0) {
930 Status = EFI_SUCCESS;
931 goto Done;
932 }
933 break;
934
935 case EFI_IFR_ONE_OF_OP:
936 case EFI_IFR_NUMERIC_OP:
937 //
938 // Numeric and OneOf has the same opcode structure.
939 //
940
941 //
942 // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
943 //
944 if (VarStorageData->Size == 0) {
945 Status = EFI_INVALID_PARAMETER;
946 goto Done;
947 }
948 //
949 // Check whether this question is for the requested varstore.
950 //
951 IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
952 if (IfrOneOf->Question.VarStoreId != VarStorageData->VarStoreId) {
953 break;
954 }
955
956 //
957 // Get Offset/Width by Question header and OneOf Flags
958 //
959 VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
960 VarWidth = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
961 //
962 // Check whether this question is in requested block array.
963 //
964 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
965 //
966 // This question is not in the requested string. Skip it.
967 //
968 break;
969 }
970
971 //
972 // Check this var question is in the var storage
973 //
974 if ((VarOffset + VarWidth) > VarStorageData->Size) {
975 Status = EFI_INVALID_PARAMETER;
976 goto Done;
977 }
978
979 //
980 // Set Block Data
981 //
982 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
983 if (BlockData == NULL) {
984 Status = EFI_OUT_OF_RESOURCES;
985 goto Done;
986 }
987 BlockData->Offset = VarOffset;
988 BlockData->Width = VarWidth;
989 BlockData->QuestionId = IfrOneOf->Question.QuestionId;
990 BlockData->OpCode = IfrOpHdr->OpCode;
991 BlockData->Scope = IfrOpHdr->Scope;
992 InitializeListHead (&BlockData->DefaultValueEntry);
993 //
994 // Add Block Data into VarStorageData BlockEntry
995 //
996 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
997
998 if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
999 //
1000 // Set this flag to TRUE for the first oneof option.
1001 //
1002 FirstOneOfOption = TRUE;
1003 } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
1004 //
1005 // Numeric minimum value will be used as default value when no default is specified.
1006 //
1007
1008 //
1009 // Set standard ID
1010 //
1011 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1012 //
1013 // Prepare new DefaultValue
1014 //
1015 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1016 if (DefaultData == NULL) {
1017 Status = EFI_OUT_OF_RESOURCES;
1018 goto Done;
1019 }
1020 DefaultData->OpCode = IfrOpHdr->OpCode;
1021 DefaultData->DefaultId = VarDefaultId;
1022
1023 switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
1024 case EFI_IFR_NUMERIC_SIZE_1:
1025 DefaultData->Value = (UINT64) IfrOneOf->data.u8.MinValue;
1026 break;
1027
1028 case EFI_IFR_NUMERIC_SIZE_2:
1029 CopyMem (&DefaultData->Value, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
1030 break;
1031
1032 case EFI_IFR_NUMERIC_SIZE_4:
1033 CopyMem (&DefaultData->Value, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
1034 break;
1035
1036 case EFI_IFR_NUMERIC_SIZE_8:
1037 CopyMem (&DefaultData->Value, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
1038 break;
1039 }
1040 //
1041 // Add DefaultValue into current BlockData
1042 //
1043 InsertDefaultValue (BlockData, DefaultData);
1044 }
1045 break;
1046
1047 case EFI_IFR_ORDERED_LIST_OP:
1048 //
1049 // offset by question header
1050 // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
1051 // no default value and default id, how to define its default value?
1052 //
1053
1054 //
1055 // OrderedList question is not in IFR Form. This IFR form is not valid.
1056 //
1057 if (VarStorageData->Size == 0) {
1058 Status = EFI_INVALID_PARAMETER;
1059 goto Done;
1060 }
1061 //
1062 // Check whether this question is for the requested varstore.
1063 //
1064 IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;
1065 if (IfrOrderedList->Question.VarStoreId != VarStorageData->VarStoreId) {
1066 BlockData = NULL;
1067 break;
1068 }
1069
1070 //
1071 // Get Offset/Width by Question header and OneOf Flags
1072 //
1073 VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset;
1074 VarWidth = IfrOrderedList->MaxContainers;
1075
1076 //
1077 // Set Block Data
1078 //
1079 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1080 if (BlockData == NULL) {
1081 Status = EFI_OUT_OF_RESOURCES;
1082 goto Done;
1083 }
1084 BlockData->Offset = VarOffset;
1085 BlockData->Width = VarWidth;
1086 BlockData->QuestionId = IfrOrderedList->Question.QuestionId;
1087 BlockData->OpCode = IfrOpHdr->OpCode;
1088 BlockData->Scope = IfrOpHdr->Scope;
1089 InitializeListHead (&BlockData->DefaultValueEntry);
1090 break;
1091
1092 case EFI_IFR_CHECKBOX_OP:
1093 //
1094 // EFI_IFR_DEFAULT_OP
1095 // offset by question header
1096 // width is 1 sizeof (BOOLEAN)
1097 // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
1098 // value by DefaultOption
1099 // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
1100 //
1101
1102 //
1103 // CheckBox question is not in IFR Form. This IFR form is not valid.
1104 //
1105 if (VarStorageData->Size == 0) {
1106 Status = EFI_INVALID_PARAMETER;
1107 goto Done;
1108 }
1109 //
1110 // Check whether this question is for the requested varstore.
1111 //
1112 IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1113 if (IfrCheckBox->Question.VarStoreId != VarStorageData->VarStoreId) {
1114 break;
1115 }
1116
1117 //
1118 // Get Offset/Width by Question header and OneOf Flags
1119 //
1120 VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1121 VarWidth = (UINT16) sizeof (BOOLEAN);
1122
1123 //
1124 // Check whether this question is in requested block array.
1125 //
1126 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1127 //
1128 // This question is not in the requested string. Skip it.
1129 //
1130 break;
1131 }
1132
1133 //
1134 // Check this var question is in the var storage
1135 //
1136 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1137 Status = EFI_INVALID_PARAMETER;
1138 goto Done;
1139 }
1140
1141 //
1142 // Set Block Data
1143 //
1144 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1145 if (BlockData == NULL) {
1146 Status = EFI_OUT_OF_RESOURCES;
1147 goto Done;
1148 }
1149 BlockData->Offset = VarOffset;
1150 BlockData->Width = VarWidth;
1151 BlockData->QuestionId = IfrCheckBox->Question.QuestionId;
1152 BlockData->OpCode = IfrOpHdr->OpCode;
1153 BlockData->Scope = IfrOpHdr->Scope;
1154 InitializeListHead (&BlockData->DefaultValueEntry);
1155 //
1156 // Add Block Data into VarStorageData BlockEntry
1157 //
1158 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1159
1160 //
1161 // Add default value for standard ID by CheckBox Flag
1162 //
1163 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1164 //
1165 // Prepare new DefaultValue
1166 //
1167 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1168 if (DefaultData == NULL) {
1169 Status = EFI_OUT_OF_RESOURCES;
1170 goto Done;
1171 }
1172 DefaultData->OpCode = IfrOpHdr->OpCode;
1173 DefaultData->DefaultId = VarDefaultId;
1174 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
1175 //
1176 // When flag is set, defautl value is TRUE.
1177 //
1178 DefaultData->Value = 1;
1179 } else {
1180 //
1181 // When flag is not set, defautl value is FASLE.
1182 //
1183 DefaultData->Value = 0;
1184 }
1185 //
1186 // Add DefaultValue into current BlockData
1187 //
1188 InsertDefaultValue (BlockData, DefaultData);
1189
1190 //
1191 // Add default value for Manufacture ID by CheckBox Flag
1192 //
1193 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1194 //
1195 // Prepare new DefaultValue
1196 //
1197 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1198 if (DefaultData == NULL) {
1199 Status = EFI_OUT_OF_RESOURCES;
1200 goto Done;
1201 }
1202 DefaultData->OpCode = IfrOpHdr->OpCode;
1203 DefaultData->DefaultId = VarDefaultId;
1204 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
1205 //
1206 // When flag is set, defautl value is TRUE.
1207 //
1208 DefaultData->Value = 1;
1209 } else {
1210 //
1211 // When flag is not set, defautl value is FASLE.
1212 //
1213 DefaultData->Value = 0;
1214 }
1215 //
1216 // Add DefaultValue into current BlockData
1217 //
1218 InsertDefaultValue (BlockData, DefaultData);
1219 break;
1220
1221 case EFI_IFR_STRING_OP:
1222 //
1223 // offset by question header
1224 // width MaxSize * sizeof (CHAR16)
1225 // no default value, only block array
1226 //
1227
1228 //
1229 // String question is not in IFR Form. This IFR form is not valid.
1230 //
1231 if (VarStorageData->Size == 0) {
1232 Status = EFI_INVALID_PARAMETER;
1233 goto Done;
1234 }
1235 //
1236 // Check whether this question is for the requested varstore.
1237 //
1238 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1239 if (IfrString->Question.VarStoreId != VarStorageData->VarStoreId) {
1240 break;
1241 }
1242
1243 //
1244 // Get Offset/Width by Question header and OneOf Flags
1245 //
1246 VarOffset = IfrString->Question.VarStoreInfo.VarOffset;
1247 VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1248
1249 //
1250 // Check whether this question is in requested block array.
1251 //
1252 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1253 //
1254 // This question is not in the requested string. Skip it.
1255 //
1256 break;
1257 }
1258
1259 //
1260 // Check this var question is in the var storage
1261 //
1262 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1263 Status = EFI_INVALID_PARAMETER;
1264 goto Done;
1265 }
1266
1267 //
1268 // Set Block Data
1269 //
1270 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1271 if (BlockData == NULL) {
1272 Status = EFI_OUT_OF_RESOURCES;
1273 goto Done;
1274 }
1275 BlockData->Offset = VarOffset;
1276 BlockData->Width = VarWidth;
1277 BlockData->QuestionId = IfrString->Question.QuestionId;
1278 BlockData->OpCode = IfrOpHdr->OpCode;
1279 InitializeListHead (&BlockData->DefaultValueEntry);
1280
1281 //
1282 // Add Block Data into VarStorageData BlockEntry
1283 //
1284 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1285
1286 //
1287 // No default value for string.
1288 //
1289 BlockData = NULL;
1290 break;
1291
1292 case EFI_IFR_PASSWORD_OP:
1293 //
1294 // offset by question header
1295 // width MaxSize * sizeof (CHAR16)
1296 // no default value, only block array
1297 //
1298
1299 //
1300 // Password question is not in IFR Form. This IFR form is not valid.
1301 //
1302 if (VarStorageData->Size == 0) {
1303 Status = EFI_INVALID_PARAMETER;
1304 goto Done;
1305 }
1306 //
1307 // Check whether this question is for the requested varstore.
1308 //
1309 IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
1310 if (IfrPassword->Question.VarStoreId != VarStorageData->VarStoreId) {
1311 break;
1312 }
1313
1314 //
1315 // Get Offset/Width by Question header and OneOf Flags
1316 //
1317 VarOffset = IfrPassword->Question.VarStoreInfo.VarOffset;
1318 VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
1319
1320 //
1321 // Check whether this question is in requested block array.
1322 //
1323 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1324 //
1325 // This question is not in the requested string. Skip it.
1326 //
1327 break;
1328 }
1329
1330 //
1331 // Check this var question is in the var storage
1332 //
1333 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1334 Status = EFI_INVALID_PARAMETER;
1335 goto Done;
1336 }
1337
1338 //
1339 // Set Block Data
1340 //
1341 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1342 if (BlockData == NULL) {
1343 Status = EFI_OUT_OF_RESOURCES;
1344 goto Done;
1345 }
1346 BlockData->Offset = VarOffset;
1347 BlockData->Width = VarWidth;
1348 BlockData->QuestionId = IfrPassword->Question.QuestionId;
1349 BlockData->OpCode = IfrOpHdr->OpCode;
1350 InitializeListHead (&BlockData->DefaultValueEntry);
1351
1352 //
1353 // Add Block Data into VarStorageData BlockEntry
1354 //
1355 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1356
1357 //
1358 // No default value for string.
1359 //
1360 BlockData = NULL;
1361 break;
1362
1363 case EFI_IFR_ONE_OF_OPTION_OP:
1364 //
1365 // No matched block data is ignored.
1366 //
1367 if (BlockData == NULL || BlockData->Scope == 0) {
1368 break;
1369 }
1370
1371 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1372 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1373 //
1374 // Get ordered list option data type.
1375 //
1376 if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
1377 VarWidth = 1;
1378 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
1379 VarWidth = 2;
1380 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
1381 VarWidth = 4;
1382 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
1383 VarWidth = 8;
1384 } else {
1385 //
1386 // Invalid ordered list option data type.
1387 //
1388 Status = EFI_INVALID_PARAMETER;
1389 FreePool (BlockData);
1390 goto Done;
1391 }
1392
1393 //
1394 // Calculate Ordered list QuestionId width.
1395 //
1396 BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
1397 //
1398 // Check whether this question is in requested block array.
1399 //
1400 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width)) {
1401 //
1402 // This question is not in the requested string. Skip it.
1403 //
1404 FreePool (BlockData);
1405 BlockData = NULL;
1406 break;
1407 }
1408 //
1409 // Check this var question is in the var storage
1410 //
1411 if ((BlockData->Offset + BlockData->Width) > VarStorageData->Size) {
1412 Status = EFI_INVALID_PARAMETER;
1413 FreePool (BlockData);
1414 goto Done;
1415 }
1416 //
1417 // Add Block Data into VarStorageData BlockEntry
1418 //
1419 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1420 //
1421 // No default data for OrderedList.
1422 //
1423 BlockData = NULL;
1424 break;
1425 }
1426
1427 if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
1428 (BlockData->OpCode == EFI_IFR_ONE_OF_OP && FirstOneOfOption)) {
1429 //
1430 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
1431 // The first oneof option value will be used as default value when no default value is specified.
1432 //
1433 FirstOneOfOption = FALSE;
1434 //
1435 // Set standard ID to Manufacture ID
1436 //
1437 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1438 //
1439 // Prepare new DefaultValue
1440 //
1441 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1442 if (DefaultData == NULL) {
1443 Status = EFI_OUT_OF_RESOURCES;
1444 goto Done;
1445 }
1446 DefaultData->OpCode = IfrOpHdr->OpCode;
1447 DefaultData->DefaultId = VarDefaultId;
1448 DefaultData->Value = IfrOneOfOption->Value.u64;
1449 //
1450 // Add DefaultValue into current BlockData
1451 //
1452 InsertDefaultValue (BlockData, DefaultData);
1453 }
1454
1455 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
1456 //
1457 // Set default ID to Manufacture ID
1458 //
1459 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1460 //
1461 // Prepare new DefaultValue
1462 //
1463 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1464 if (DefaultData == NULL) {
1465 Status = EFI_OUT_OF_RESOURCES;
1466 goto Done;
1467 }
1468 DefaultData->OpCode = IfrOpHdr->OpCode;
1469 DefaultData->DefaultId = VarDefaultId;
1470 DefaultData->Value = IfrOneOfOption->Value.u64;
1471 //
1472 // Add DefaultValue into current BlockData
1473 //
1474 InsertDefaultValue (BlockData, DefaultData);
1475 }
1476 break;
1477
1478 case EFI_IFR_DEFAULT_OP:
1479 //
1480 // Update Current BlockData to the default value.
1481 //
1482 if (BlockData == NULL || BlockData->Scope == 0) {
1483 //
1484 // No matched block data is ignored.
1485 //
1486 break;
1487 }
1488
1489 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1490 //
1491 // OrderedList Opcode is no default value.
1492 //
1493 break;
1494 }
1495 //
1496 // Get the DefaultId
1497 //
1498 IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
1499 VarDefaultId = IfrDefault->DefaultId;
1500 //
1501 // Prepare new DefaultValue
1502 //
1503 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1504 if (DefaultData == NULL) {
1505 Status = EFI_OUT_OF_RESOURCES;
1506 goto Done;
1507 }
1508 DefaultData->OpCode = IfrOpHdr->OpCode;
1509 DefaultData->DefaultId = VarDefaultId;
1510 DefaultData->Value = IfrDefault->Value.u64;
1511 //
1512 // Add DefaultValue into current BlockData
1513 //
1514 InsertDefaultValue (BlockData, DefaultData);
1515 break;
1516 case EFI_IFR_END_OP:
1517 //
1518 // End Opcode is for Var question.
1519 //
1520 if (BlockData != NULL && BlockData->Scope > 0) {
1521 BlockData->Scope--;
1522 }
1523 break;
1524 default:
1525 if (BlockData != NULL && BlockData->Scope > 0) {
1526 BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);
1527 }
1528 break;
1529 }
1530
1531 IfrOffset += IfrOpHdr->Length;
1532 }
1533
1534 Done:
1535 return Status;
1536 }
1537
1538 /**
1539 This function gets the full request string and full default value string by
1540 parsing IFR data in HII form packages.
1541
1542 When Request points to NULL string, the request string and default value string
1543 for each varstore in form package will return.
1544
1545 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1546 @param DevicePath Device Path which Hii Config Access Protocol is registered.
1547 @param Request Pointer to a null-terminated Unicode string in
1548 <ConfigRequest> format. When it doesn't contain
1549 any RequestElement, it will be updated to return
1550 the full RequestElement retrieved from IFR data.
1551 If it points to NULL, the request string for the first
1552 varstore in form package will be merged into a
1553 <MultiConfigRequest> format string and return.
1554 @param AltCfgResp Pointer to a null-terminated Unicode string in
1555 <ConfigAltResp> format. When the pointer is to NULL,
1556 the full default value string retrieved from IFR data
1557 will return. When the pinter is to a string, the
1558 full default value string retrieved from IFR data
1559 will be merged into the input string and return.
1560 When Request points to NULL, the default value string
1561 for each varstore in form package will be merged into
1562 a <MultiConfigAltResp> format string and return.
1563 @param PointerProgress Optional parameter, it can be be NULL.
1564 When it is not NULL, if Request is NULL, it returns NULL.
1565 On return, points to a character in the Request
1566 string. Points to the string's null terminator if
1567 request was successful. Points to the most recent
1568 & before the first failing name / value pair (or
1569 the beginning of the string if the failure is in
1570 the first name / value pair) if the request was
1571 not successful.
1572 @retval EFI_SUCCESS The Results string is set to the full request string.
1573 And AltCfgResp contains all default value string.
1574 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
1575 @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
1576 can't be found in Form package.
1577 @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
1578 @retval EFI_INVALID_PARAMETER Request points to NULL.
1579
1580 **/
1581 EFI_STATUS
1582 EFIAPI
1583 GetFullStringFromHiiFormPackages (
1584 IN HII_DATABASE_RECORD *DataBaseRecord,
1585 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1586 IN OUT EFI_STRING *Request,
1587 IN OUT EFI_STRING *AltCfgResp,
1588 OUT EFI_STRING *PointerProgress OPTIONAL
1589 )
1590 {
1591 EFI_STATUS Status;
1592 UINT8 *HiiFormPackage;
1593 UINTN PackageSize;
1594 UINTN ResultSize;
1595 IFR_BLOCK_DATA *RequestBlockArray;
1596 IFR_BLOCK_DATA *BlockData;
1597 IFR_BLOCK_DATA *NextBlockData;
1598 IFR_DEFAULT_DATA *DefaultValueData;
1599 IFR_DEFAULT_DATA *DefaultId;
1600 IFR_DEFAULT_DATA *DefaultIdArray;
1601 IFR_VARSTORAGE_DATA *VarStorageData;
1602 EFI_STRING DefaultAltCfgResp;
1603 EFI_STRING FullConfigRequest;
1604 EFI_STRING ConfigHdr;
1605 EFI_STRING GuidStr;
1606 EFI_STRING NameStr;
1607 EFI_STRING PathStr;
1608 EFI_STRING StringPtr;
1609 EFI_STRING Progress;
1610 UINTN Length;
1611 UINT8 *TmpBuffer;
1612 UINT16 Offset;
1613 UINT16 Width;
1614 LIST_ENTRY *Link;
1615 LIST_ENTRY *LinkData;
1616 LIST_ENTRY *LinkDefault;
1617 BOOLEAN DataExist;
1618
1619 if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {
1620 return EFI_INVALID_PARAMETER;
1621 }
1622
1623 //
1624 // Initialize the local variables.
1625 //
1626 RequestBlockArray = NULL;
1627 DefaultIdArray = NULL;
1628 VarStorageData = NULL;
1629 DefaultAltCfgResp = NULL;
1630 FullConfigRequest = NULL;
1631 ConfigHdr = NULL;
1632 GuidStr = NULL;
1633 NameStr = NULL;
1634 PathStr = NULL;
1635 HiiFormPackage = NULL;
1636 ResultSize = 0;
1637 PackageSize = 0;
1638 DataExist = FALSE;
1639 Progress = *Request;
1640
1641 //
1642 // 0. Get Hii Form Package by HiiHandle
1643 //
1644 Status = ExportFormPackages (
1645 &mPrivate,
1646 DataBaseRecord->Handle,
1647 DataBaseRecord->PackageList,
1648 0,
1649 PackageSize,
1650 HiiFormPackage,
1651 &ResultSize
1652 );
1653 if (EFI_ERROR (Status)) {
1654 return Status;
1655 }
1656
1657 HiiFormPackage = AllocatePool (ResultSize);
1658 if (HiiFormPackage == NULL) {
1659 Status = EFI_OUT_OF_RESOURCES;
1660 goto Done;
1661 }
1662
1663 //
1664 // Get HiiFormPackage by HiiHandle
1665 //
1666 PackageSize = ResultSize;
1667 ResultSize = 0;
1668 Status = ExportFormPackages (
1669 &mPrivate,
1670 DataBaseRecord->Handle,
1671 DataBaseRecord->PackageList,
1672 0,
1673 PackageSize,
1674 HiiFormPackage,
1675 &ResultSize
1676 );
1677 if (EFI_ERROR (Status)) {
1678 goto Done;
1679 }
1680
1681 //
1682 // 1. Get the request block array by Request String when Request string containts the block array.
1683 //
1684 StringPtr = NULL;
1685 if (*Request != NULL) {
1686 StringPtr = *Request;
1687 //
1688 // Jump <ConfigHdr>
1689 //
1690 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1691 Status = EFI_INVALID_PARAMETER;
1692 goto Done;
1693 }
1694 StringPtr += StrLen (L"GUID=");
1695 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
1696 StringPtr++;
1697 }
1698 if (*StringPtr == L'\0') {
1699 Status = EFI_INVALID_PARAMETER;
1700 goto Done;
1701 }
1702 StringPtr += StrLen (L"&NAME=");
1703 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
1704 StringPtr++;
1705 }
1706 if (*StringPtr == L'\0') {
1707 Status = EFI_INVALID_PARAMETER;
1708 goto Done;
1709 }
1710 StringPtr += StrLen (L"&PATH=");
1711 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1712 StringPtr ++;
1713 }
1714 //
1715 // Check the following string &OFFSET=
1716 //
1717 if (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
1718 Progress = StringPtr;
1719 Status = EFI_INVALID_PARAMETER;
1720 goto Done;
1721 } else if (*StringPtr == L'\0') {
1722 //
1723 // No request block is found.
1724 //
1725 StringPtr = NULL;
1726 }
1727 }
1728 if (StringPtr != NULL) {
1729 //
1730 // Init RequestBlockArray
1731 //
1732 RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1733 if (RequestBlockArray == NULL) {
1734 Status = EFI_OUT_OF_RESOURCES;
1735 goto Done;
1736 }
1737 InitializeListHead (&RequestBlockArray->Entry);
1738
1739 //
1740 // Get the request Block array from the request string
1741 // Offset and Width
1742 //
1743
1744 //
1745 // Parse each <RequestElement> if exists
1746 // Only <BlockName> format is supported by this help function.
1747 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
1748 //
1749 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
1750 //
1751 // Skip the OFFSET string
1752 //
1753 Progress = StringPtr;
1754 StringPtr += StrLen (L"&OFFSET=");
1755 //
1756 // Get Offset
1757 //
1758 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1759 if (EFI_ERROR (Status)) {
1760 goto Done;
1761 }
1762 Offset = 0;
1763 CopyMem (
1764 &Offset,
1765 TmpBuffer,
1766 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1767 );
1768 FreePool (TmpBuffer);
1769
1770 StringPtr += Length;
1771 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1772 Status = EFI_INVALID_PARAMETER;
1773 goto Done;
1774 }
1775 StringPtr += StrLen (L"&WIDTH=");
1776
1777 //
1778 // Get Width
1779 //
1780 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1781 if (EFI_ERROR (Status)) {
1782 goto Done;
1783 }
1784 Width = 0;
1785 CopyMem (
1786 &Width,
1787 TmpBuffer,
1788 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1789 );
1790 FreePool (TmpBuffer);
1791
1792 StringPtr += Length;
1793 if (*StringPtr != 0 && *StringPtr != L'&') {
1794 Status = EFI_INVALID_PARAMETER;
1795 goto Done;
1796 }
1797
1798 //
1799 // Set Block Data
1800 //
1801 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1802 if (BlockData == NULL) {
1803 Status = EFI_OUT_OF_RESOURCES;
1804 goto Done;
1805 }
1806 BlockData->Offset = Offset;
1807 BlockData->Width = Width;
1808 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
1809
1810 //
1811 // Skip &VALUE string if &VALUE does exists.
1812 //
1813 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
1814 StringPtr += StrLen (L"&VALUE=");
1815
1816 //
1817 // Get Value
1818 //
1819 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1820 if (EFI_ERROR (Status)) {
1821 Status = EFI_INVALID_PARAMETER;
1822 goto Done;
1823 }
1824
1825 StringPtr += Length;
1826 if (*StringPtr != 0 && *StringPtr != L'&') {
1827 Status = EFI_INVALID_PARAMETER;
1828 goto Done;
1829 }
1830 }
1831 //
1832 // If '\0', parsing is finished.
1833 //
1834 if (*StringPtr == 0) {
1835 break;
1836 }
1837 }
1838
1839 //
1840 // Merge the requested block data.
1841 //
1842 Link = RequestBlockArray->Entry.ForwardLink;
1843 while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
1844 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1845 NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
1846 if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
1847 if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
1848 BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
1849 }
1850 RemoveEntryList (Link->ForwardLink);
1851 FreePool (NextBlockData);
1852 continue;
1853 }
1854 Link = Link->ForwardLink;
1855 }
1856 }
1857
1858 //
1859 // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
1860 //
1861
1862 //
1863 // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
1864 //
1865 DefaultIdArray = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1866 if (DefaultIdArray == NULL) {
1867 Status = EFI_OUT_OF_RESOURCES;
1868 goto Done;
1869 }
1870 InitializeListHead (&DefaultIdArray->Entry);
1871
1872 //
1873 // Initialize VarStorageData to store the var store Block and Default value information.
1874 //
1875 VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
1876 if (VarStorageData == NULL) {
1877 Status = EFI_OUT_OF_RESOURCES;
1878 goto Done;
1879 }
1880 InitializeListHead (&VarStorageData->Entry);
1881 InitializeListHead (&VarStorageData->BlockEntry);
1882
1883 //
1884 // Parse the opcode in form pacakge to get the default setting.
1885 //
1886 Status = ParseIfrData (HiiFormPackage, (UINT32) PackageSize, *Request, RequestBlockArray, VarStorageData, DefaultIdArray);
1887 if (EFI_ERROR (Status)) {
1888 goto Done;
1889 }
1890
1891 //
1892 // No requested varstore in IFR data and directly return
1893 //
1894 if (VarStorageData->Size == 0) {
1895 Status = EFI_SUCCESS;
1896 goto Done;
1897 }
1898
1899 //
1900 // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
1901 //
1902
1903 //
1904 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
1905 //
1906 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);
1907 GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);
1908 GenerateSubStr (
1909 L"PATH=",
1910 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1911 (VOID *) DevicePath,
1912 1,
1913 &PathStr
1914 );
1915 Length = StrLen (GuidStr);
1916 Length = Length + StrLen (NameStr);
1917 Length = Length + StrLen (PathStr) + 1;
1918 ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
1919 if (ConfigHdr == NULL) {
1920 Status = EFI_OUT_OF_RESOURCES;
1921 goto Done;
1922 }
1923 StrCpy (ConfigHdr, GuidStr);
1924 StrCat (ConfigHdr, NameStr);
1925 StrCat (ConfigHdr, PathStr);
1926
1927 //
1928 // Remove the last character L'&'
1929 //
1930 *(ConfigHdr + StrLen (ConfigHdr) - 1) = L'\0';
1931
1932 if (RequestBlockArray == NULL) {
1933 //
1934 // Append VarStorageData BlockEntry into *Request string
1935 // Now support only one varstore in a form package.
1936 //
1937
1938 //
1939 // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
1940 // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
1941 //
1942
1943 //
1944 // Compute the length of the entire request starting with <ConfigHdr> and a
1945 // Null-terminator
1946 //
1947 DataExist = FALSE;
1948 Length = StrLen (ConfigHdr) + 1;
1949
1950 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
1951 //
1952 // Add <BlockName> length for each Offset/Width pair
1953 //
1954 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
1955 // | 8 | 4 | 7 | 4 |
1956 //
1957 DataExist = TRUE;
1958 Length = Length + (8 + 4 + 7 + 4);
1959 }
1960
1961 //
1962 // No any request block data is found. The request string can't be constructed.
1963 //
1964 if (!DataExist) {
1965 Status = EFI_SUCCESS;
1966 goto Done;
1967 }
1968
1969 //
1970 // Allocate buffer for the entire <ConfigRequest>
1971 //
1972 FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
1973 if (FullConfigRequest == NULL) {
1974 Status = EFI_OUT_OF_RESOURCES;
1975 goto Done;
1976 }
1977 StringPtr = FullConfigRequest;
1978
1979 //
1980 // Start with <ConfigHdr>
1981 //
1982 StrCpy (StringPtr, ConfigHdr);
1983 StringPtr += StrLen (StringPtr);
1984
1985 //
1986 // Loop through all the Offset/Width pairs and append them to ConfigRequest
1987 //
1988 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
1989 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1990 //
1991 // Append &OFFSET=XXXX&WIDTH=YYYY\0
1992 //
1993 UnicodeSPrint (
1994 StringPtr,
1995 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
1996 L"&OFFSET=%04X&WIDTH=%04X",
1997 BlockData->Offset,
1998 BlockData->Width
1999 );
2000 StringPtr += StrLen (StringPtr);
2001 }
2002 //
2003 // Set to the got full request string.
2004 //
2005 HiiToLower (FullConfigRequest);
2006 if (*Request != NULL) {
2007 FreePool (*Request);
2008 }
2009 *Request = FullConfigRequest;
2010 }
2011
2012 //
2013 // 4. Construct Default Value string in AltResp according to request element.
2014 // Go through all VarStorageData Entry and get the DefaultId array for each one
2015 // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
2016 //
2017 DataExist = FALSE;
2018 //
2019 // Add length for <ConfigHdr> + '\0'
2020 //
2021 Length = StrLen (ConfigHdr) + 1;
2022
2023 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2024 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2025 //
2026 // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
2027 // |1| StrLen (ConfigHdr) | 8 | 4 |
2028 //
2029 Length += (1 + StrLen (ConfigHdr) + 8 + 4);
2030
2031 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2032 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2033 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {
2034 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2035 if (DefaultValueData->DefaultId == DefaultId->DefaultId) {
2036 //
2037 // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
2038 // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
2039 //
2040 Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
2041 DataExist = TRUE;
2042 }
2043 }
2044 }
2045 }
2046
2047 //
2048 // No default value is found. The default string doesn't exist.
2049 //
2050 if (!DataExist) {
2051 Status = EFI_SUCCESS;
2052 goto Done;
2053 }
2054
2055 //
2056 // Allocate buffer for the entire <DefaultAltCfgResp>
2057 //
2058 DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
2059 if (DefaultAltCfgResp == NULL) {
2060 Status = EFI_OUT_OF_RESOURCES;
2061 goto Done;
2062 }
2063 StringPtr = DefaultAltCfgResp;
2064
2065 //
2066 // Start with <ConfigHdr>
2067 //
2068 StrCpy (StringPtr, ConfigHdr);
2069 StringPtr += StrLen (StringPtr);
2070
2071 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2072 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2073 //
2074 // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
2075 // |1| StrLen (ConfigHdr) | 8 | 4 |
2076 //
2077 UnicodeSPrint (
2078 StringPtr,
2079 (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
2080 L"&%s&ALTCFG=%04X",
2081 ConfigHdr,
2082 DefaultId->DefaultId
2083 );
2084 StringPtr += StrLen (StringPtr);
2085
2086 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2087 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2088 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {
2089 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2090 if (DefaultValueData->DefaultId == DefaultId->DefaultId) {
2091 //
2092 // Add <BlockConfig>
2093 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
2094 //
2095 UnicodeSPrint (
2096 StringPtr,
2097 (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
2098 L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
2099 BlockData->Offset,
2100 BlockData->Width
2101 );
2102 StringPtr += StrLen (StringPtr);
2103
2104 //
2105 // Convert Value to a hex string in "%x" format
2106 // NOTE: This is in the opposite byte that GUID and PATH use
2107 //
2108 Width = BlockData->Width;
2109 TmpBuffer = (UINT8 *) &(DefaultValueData->Value);
2110 for (; Width > 0; Width--) {
2111 StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2);
2112 }
2113 }
2114 }
2115 }
2116 }
2117 HiiToLower (DefaultAltCfgResp);
2118
2119 //
2120 // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL.
2121 //
2122 if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {
2123 Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
2124 FreePool (DefaultAltCfgResp);
2125 } else if (*AltCfgResp == NULL) {
2126 *AltCfgResp = DefaultAltCfgResp;
2127 }
2128
2129 Done:
2130 if (RequestBlockArray != NULL) {
2131 //
2132 // Free Link Array RequestBlockArray
2133 //
2134 while (!IsListEmpty (&RequestBlockArray->Entry)) {
2135 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2136 RemoveEntryList (&BlockData->Entry);
2137 FreePool (BlockData);
2138 }
2139
2140 FreePool (RequestBlockArray);
2141 }
2142
2143 if (VarStorageData != NULL) {
2144 //
2145 // Free link array VarStorageData
2146 //
2147 while (!IsListEmpty (&VarStorageData->BlockEntry)) {
2148 BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
2149 RemoveEntryList (&BlockData->Entry);
2150 //
2151 // Free default value link array
2152 //
2153 while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
2154 DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
2155 RemoveEntryList (&DefaultValueData->Entry);
2156 FreePool (DefaultValueData);
2157 }
2158 FreePool (BlockData);
2159 }
2160 FreePool (VarStorageData);
2161 }
2162
2163 if (DefaultIdArray != NULL) {
2164 //
2165 // Free DefaultId Array
2166 //
2167 while (!IsListEmpty (&DefaultIdArray->Entry)) {
2168 DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
2169 RemoveEntryList (&DefaultId->Entry);
2170 FreePool (DefaultId);
2171 }
2172 FreePool (DefaultIdArray);
2173 }
2174
2175 //
2176 // Free the allocated string
2177 //
2178 if (GuidStr != NULL) {
2179 FreePool (GuidStr);
2180 }
2181 if (NameStr != NULL) {
2182 FreePool (NameStr);
2183 }
2184 if (PathStr != NULL) {
2185 FreePool (PathStr);
2186 }
2187 if (ConfigHdr != NULL) {
2188 FreePool (ConfigHdr);
2189 }
2190
2191 //
2192 // Free Pacakge data
2193 //
2194 if (HiiFormPackage != NULL) {
2195 FreePool (HiiFormPackage);
2196 }
2197
2198 if (PointerProgress != NULL) {
2199 if (*Request == NULL) {
2200 *PointerProgress = NULL;
2201 } else if (EFI_ERROR (Status)) {
2202 *PointerProgress = Progress;
2203 } else {
2204 *PointerProgress = *Request + StrLen (*Request);
2205 }
2206 }
2207
2208 return Status;
2209 }
2210
2211 /**
2212 This function allows a caller to extract the current configuration
2213 for one or more named elements from one or more drivers.
2214
2215 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2216 instance.
2217 @param Request A null-terminated Unicode string in
2218 <MultiConfigRequest> format.
2219 @param Progress On return, points to a character in the Request
2220 string. Points to the string's null terminator if
2221 request was successful. Points to the most recent
2222 & before the first failing name / value pair (or
2223 the beginning of the string if the failure is in
2224 the first name / value pair) if the request was
2225 not successful.
2226 @param Results Null-terminated Unicode string in
2227 <MultiConfigAltResp> format which has all values
2228 filled in for the names in the Request string.
2229 String to be allocated by the called function.
2230
2231 @retval EFI_SUCCESS The Results string is filled with the values
2232 corresponding to all requested names.
2233 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2234 results that must be stored awaiting possible
2235 future protocols.
2236 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
2237 Progress set to the "G" in "GUID" of the routing
2238 header that doesn't match. Note: There is no
2239 requirement that all routing data be validated
2240 before any configuration extraction.
2241 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
2242 parameter would result in this type of error. The
2243 Progress parameter is set to NULL.
2244 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
2245 before the error or the beginning of the string.
2246 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
2247 name in question.
2248
2249 **/
2250 EFI_STATUS
2251 EFIAPI
2252 HiiConfigRoutingExtractConfig (
2253 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2254 IN CONST EFI_STRING Request,
2255 OUT EFI_STRING *Progress,
2256 OUT EFI_STRING *Results
2257 )
2258 {
2259 HII_DATABASE_PRIVATE_DATA *Private;
2260 EFI_STRING StringPtr;
2261 EFI_STRING ConfigRequest;
2262 UINTN Length;
2263 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2264 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2265 EFI_STATUS Status;
2266 LIST_ENTRY *Link;
2267 HII_DATABASE_RECORD *Database;
2268 UINT8 *DevicePathPkg;
2269 UINT8 *CurrentDevicePath;
2270 EFI_HANDLE DriverHandle;
2271 EFI_HII_HANDLE HiiHandle;
2272 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2273 EFI_STRING AccessProgress;
2274 EFI_STRING AccessResults;
2275 EFI_STRING DefaultResults;
2276 BOOLEAN FirstElement;
2277 BOOLEAN IfrDataParsedFlag;
2278
2279 if (This == NULL || Progress == NULL || Results == NULL) {
2280 return EFI_INVALID_PARAMETER;
2281 }
2282
2283 if (Request == NULL) {
2284 *Progress = NULL;
2285 return EFI_INVALID_PARAMETER;
2286 }
2287
2288 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2289 StringPtr = Request;
2290 *Progress = StringPtr;
2291 DefaultResults = NULL;
2292 ConfigRequest = NULL;
2293 Status = EFI_SUCCESS;
2294 AccessResults = NULL;
2295 DevicePath = NULL;
2296 IfrDataParsedFlag = FALSE;
2297
2298 //
2299 // The first element of <MultiConfigRequest> should be
2300 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
2301 //
2302 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2303 return EFI_INVALID_PARAMETER;
2304 }
2305
2306 FirstElement = TRUE;
2307
2308 //
2309 // Allocate a fix length of memory to store Results. Reallocate memory for
2310 // Results if this fix length is insufficient.
2311 //
2312 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2313 if (*Results == NULL) {
2314 return EFI_OUT_OF_RESOURCES;
2315 }
2316
2317 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
2318 //
2319 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
2320 // or most recent & before the error.
2321 //
2322 if (StringPtr == Request) {
2323 *Progress = StringPtr;
2324 } else {
2325 *Progress = StringPtr - 1;
2326 }
2327
2328 //
2329 // Process each <ConfigRequest> of <MultiConfigRequest>
2330 //
2331 Length = CalculateConfigStringLen (StringPtr);
2332 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
2333 if (ConfigRequest == NULL) {
2334 Status = EFI_OUT_OF_RESOURCES;
2335 goto Done;
2336 }
2337 *(ConfigRequest + Length) = 0;
2338
2339 //
2340 // Get the UEFI device path
2341 //
2342 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
2343 if (EFI_ERROR (Status)) {
2344 goto Done;
2345 }
2346
2347 //
2348 // Find driver which matches the routing data.
2349 //
2350 DriverHandle = NULL;
2351 HiiHandle = NULL;
2352 Database = NULL;
2353 for (Link = Private->DatabaseList.ForwardLink;
2354 Link != &Private->DatabaseList;
2355 Link = Link->ForwardLink
2356 ) {
2357 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2358 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2359 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2360 if (CompareMem (
2361 DevicePath,
2362 CurrentDevicePath,
2363 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2364 ) == 0) {
2365 DriverHandle = Database->DriverHandle;
2366 HiiHandle = Database->Handle;
2367 break;
2368 }
2369 }
2370 }
2371
2372 //
2373 // Try to find driver handle by device path.
2374 //
2375 if (DriverHandle == NULL) {
2376 TempDevicePath = DevicePath;
2377 Status = gBS->LocateDevicePath (
2378 &gEfiDevicePathProtocolGuid,
2379 &TempDevicePath,
2380 &DriverHandle
2381 );
2382 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2383 //
2384 // Routing data does not match any known driver.
2385 // Set Progress to the 'G' in "GUID" of the routing header.
2386 //
2387 *Progress = StringPtr;
2388 Status = EFI_NOT_FOUND;
2389 goto Done;
2390 }
2391 }
2392
2393 //
2394 // Check whether ConfigRequest contains request string OFFSET/WIDTH
2395 //
2396 IfrDataParsedFlag = FALSE;
2397 if ((HiiHandle != NULL) && (StrStr (ConfigRequest, L"&OFFSET=") == NULL)) {
2398 //
2399 // Get the full request string from IFR when HiiPackage is registered to HiiHandle
2400 //
2401 IfrDataParsedFlag = TRUE;
2402 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
2403 if (EFI_ERROR (Status)) {
2404 //
2405 // AccessProgress indicates the parsing progress on <ConfigRequest>.
2406 // Map it to the progress on <MultiConfigRequest> then return it.
2407 //
2408 *Progress = StrStr (StringPtr, AccessProgress);
2409 goto Done;
2410 }
2411 //
2412 // Not any request block is found.
2413 //
2414 if (StrStr (ConfigRequest, L"&OFFSET=") == NULL) {
2415 AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
2416 goto NextConfigString;
2417 }
2418 }
2419
2420 //
2421 // Call corresponding ConfigAccess protocol to extract settings
2422 //
2423 Status = gBS->HandleProtocol (
2424 DriverHandle,
2425 &gEfiHiiConfigAccessProtocolGuid,
2426 (VOID **) &ConfigAccess
2427 );
2428 ASSERT_EFI_ERROR (Status);
2429
2430 Status = ConfigAccess->ExtractConfig (
2431 ConfigAccess,
2432 ConfigRequest,
2433 &AccessProgress,
2434 &AccessResults
2435 );
2436 if (EFI_ERROR (Status)) {
2437 //
2438 // AccessProgress indicates the parsing progress on <ConfigRequest>.
2439 // Map it to the progress on <MultiConfigRequest> then return it.
2440 //
2441 *Progress = StrStr (StringPtr, AccessProgress);
2442 goto Done;
2443 }
2444
2445 //
2446 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
2447 // which seperates the first <ConfigAltResp> and the following ones.
2448 //
2449 ASSERT (*AccessProgress == 0);
2450
2451 //
2452 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2453 //
2454 if (!IfrDataParsedFlag && HiiHandle != NULL) {
2455 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
2456 ASSERT_EFI_ERROR (Status);
2457 }
2458
2459 FreePool (DevicePath);
2460 DevicePath = NULL;
2461
2462 if (DefaultResults != NULL) {
2463 Status = MergeDefaultString (&AccessResults, DefaultResults);
2464 ASSERT_EFI_ERROR (Status);
2465 FreePool (DefaultResults);
2466 DefaultResults = NULL;
2467 }
2468
2469 NextConfigString:
2470 if (!FirstElement) {
2471 Status = AppendToMultiString (Results, L"&");
2472 ASSERT_EFI_ERROR (Status);
2473 }
2474
2475 Status = AppendToMultiString (Results, AccessResults);
2476 ASSERT_EFI_ERROR (Status);
2477
2478 FirstElement = FALSE;
2479
2480 FreePool (AccessResults);
2481 AccessResults = NULL;
2482 FreePool (ConfigRequest);
2483 ConfigRequest = NULL;
2484
2485 //
2486 // Go to next <ConfigRequest> (skip '&').
2487 //
2488 StringPtr += Length;
2489 if (*StringPtr == 0) {
2490 *Progress = StringPtr;
2491 break;
2492 }
2493
2494 StringPtr++;
2495 }
2496
2497 Done:
2498 if (EFI_ERROR (Status)) {
2499 FreePool (*Results);
2500 *Results = NULL;
2501 }
2502
2503 if (ConfigRequest != NULL) {
2504 FreePool (ConfigRequest);
2505 }
2506
2507 if (AccessResults != NULL) {
2508 FreePool (AccessResults);
2509 }
2510
2511 if (DefaultResults != NULL) {
2512 FreePool (DefaultResults);
2513 }
2514
2515 if (DevicePath != NULL) {
2516 FreePool (DevicePath);
2517 }
2518
2519 return Status;
2520 }
2521
2522
2523 /**
2524 This function allows the caller to request the current configuration for the
2525 entirety of the current HII database and returns the data in a
2526 null-terminated Unicode string.
2527
2528 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2529 instance.
2530 @param Results Null-terminated Unicode string in
2531 <MultiConfigAltResp> format which has all values
2532 filled in for the names in the Request string.
2533 String to be allocated by the called function.
2534 De-allocation is up to the caller.
2535
2536 @retval EFI_SUCCESS The Results string is filled with the values
2537 corresponding to all requested names.
2538 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2539 results that must be stored awaiting possible
2540 future protocols.
2541 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
2542 parameter would result in this type of error.
2543
2544 **/
2545 EFI_STATUS
2546 EFIAPI
2547 HiiConfigRoutingExportConfig (
2548 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2549 OUT EFI_STRING *Results
2550 )
2551 {
2552 EFI_STATUS Status;
2553 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2554 EFI_STRING AccessResults;
2555 EFI_STRING Progress;
2556 EFI_STRING StringPtr;
2557 EFI_STRING ConfigRequest;
2558 UINTN Index;
2559 EFI_HANDLE *ConfigAccessHandles;
2560 UINTN NumberConfigAccessHandles;
2561 BOOLEAN FirstElement;
2562 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2563 EFI_HII_HANDLE HiiHandle;
2564 EFI_STRING DefaultResults;
2565 HII_DATABASE_PRIVATE_DATA *Private;
2566 LIST_ENTRY *Link;
2567 HII_DATABASE_RECORD *Database;
2568 UINT8 *DevicePathPkg;
2569 UINT8 *CurrentDevicePath;
2570 BOOLEAN IfrDataParsedFlag;
2571
2572 if (This == NULL || Results == NULL) {
2573 return EFI_INVALID_PARAMETER;
2574 }
2575
2576 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2577
2578 //
2579 // Allocate a fix length of memory to store Results. Reallocate memory for
2580 // Results if this fix length is insufficient.
2581 //
2582 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2583 if (*Results == NULL) {
2584 return EFI_OUT_OF_RESOURCES;
2585 }
2586
2587 NumberConfigAccessHandles = 0;
2588 Status = gBS->LocateHandleBuffer (
2589 ByProtocol,
2590 &gEfiHiiConfigAccessProtocolGuid,
2591 NULL,
2592 &NumberConfigAccessHandles,
2593 &ConfigAccessHandles
2594 );
2595 if (EFI_ERROR (Status)) {
2596 return Status;
2597 }
2598
2599 FirstElement = TRUE;
2600
2601 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
2602 Status = gBS->HandleProtocol (
2603 ConfigAccessHandles[Index],
2604 &gEfiHiiConfigAccessProtocolGuid,
2605 (VOID **) &ConfigAccess
2606 );
2607 if (EFI_ERROR (Status)) {
2608 continue;
2609 }
2610
2611 //
2612 // Get DevicePath and HiiHandle for this ConfigAccess driver handle
2613 //
2614 IfrDataParsedFlag = FALSE;
2615 Progress = NULL;
2616 HiiHandle = NULL;
2617 DefaultResults = NULL;
2618 Database = NULL;
2619 ConfigRequest = NULL;
2620 DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
2621 if (DevicePath != NULL) {
2622 for (Link = Private->DatabaseList.ForwardLink;
2623 Link != &Private->DatabaseList;
2624 Link = Link->ForwardLink
2625 ) {
2626 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2627 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2628 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2629 if (CompareMem (
2630 DevicePath,
2631 CurrentDevicePath,
2632 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2633 ) == 0) {
2634 HiiHandle = Database->Handle;
2635 break;
2636 }
2637 }
2638 }
2639 }
2640
2641 Status = ConfigAccess->ExtractConfig (
2642 ConfigAccess,
2643 NULL,
2644 &Progress,
2645 &AccessResults
2646 );
2647 if (EFI_ERROR (Status)) {
2648 //
2649 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2650 //
2651 if (HiiHandle != NULL && DevicePath != NULL) {
2652 IfrDataParsedFlag = TRUE;
2653 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
2654 //
2655 // Get the full request string to get the Current setting again.
2656 //
2657 if (!EFI_ERROR (Status) && ConfigRequest != NULL) {
2658 Status = ConfigAccess->ExtractConfig (
2659 ConfigAccess,
2660 ConfigRequest,
2661 &Progress,
2662 &AccessResults
2663 );
2664 FreePool (ConfigRequest);
2665 } else {
2666 Status = EFI_NOT_FOUND;
2667 }
2668 }
2669 }
2670
2671 if (!EFI_ERROR (Status)) {
2672 //
2673 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2674 //
2675 if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {
2676 StringPtr = StrStr (AccessResults, L"&GUID=");
2677 if (StringPtr != NULL) {
2678 *StringPtr = 0;
2679 }
2680 if (StrStr (AccessResults, L"&OFFSET=") != NULL) {
2681 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
2682 ASSERT_EFI_ERROR (Status);
2683 }
2684 if (StringPtr != NULL) {
2685 *StringPtr = L'&';
2686 }
2687 }
2688 //
2689 // Merge the default sting from IFR code into the got setting from driver.
2690 //
2691 if (DefaultResults != NULL) {
2692 Status = MergeDefaultString (&AccessResults, DefaultResults);
2693 ASSERT_EFI_ERROR (Status);
2694 FreePool (DefaultResults);
2695 DefaultResults = NULL;
2696 }
2697
2698 //
2699 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
2700 // which seperates the first <ConfigAltResp> and the following ones.
2701 //
2702 if (!FirstElement) {
2703 Status = AppendToMultiString (Results, L"&");
2704 ASSERT_EFI_ERROR (Status);
2705 }
2706
2707 Status = AppendToMultiString (Results, AccessResults);
2708 ASSERT_EFI_ERROR (Status);
2709
2710 FirstElement = FALSE;
2711
2712 FreePool (AccessResults);
2713 AccessResults = NULL;
2714 }
2715 }
2716 FreePool (ConfigAccessHandles);
2717
2718 return EFI_SUCCESS;
2719 }
2720
2721
2722 /**
2723 This function processes the results of processing forms and routes it to the
2724 appropriate handlers or storage.
2725
2726 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2727 instance.
2728 @param Configuration A null-terminated Unicode string in
2729 <MulltiConfigResp> format.
2730 @param Progress A pointer to a string filled in with the offset of
2731 the most recent & before the first failing name /
2732 value pair (or the beginning of the string if the
2733 failure is in the first name / value pair) or the
2734 terminating NULL if all was successful.
2735
2736 @retval EFI_SUCCESS The results have been distributed or are awaiting
2737 distribution.
2738 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2739 results that must be stored awaiting possible
2740 future protocols.
2741 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
2742 would result in this type of error.
2743 @retval EFI_NOT_FOUND Target for the specified routing data was not
2744 found.
2745
2746 **/
2747 EFI_STATUS
2748 EFIAPI
2749 HiiConfigRoutingRouteConfig (
2750 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2751 IN CONST EFI_STRING Configuration,
2752 OUT EFI_STRING *Progress
2753 )
2754 {
2755 HII_DATABASE_PRIVATE_DATA *Private;
2756 EFI_STRING StringPtr;
2757 EFI_STRING ConfigResp;
2758 UINTN Length;
2759 EFI_STATUS Status;
2760 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2761 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2762 LIST_ENTRY *Link;
2763 HII_DATABASE_RECORD *Database;
2764 UINT8 *DevicePathPkg;
2765 UINT8 *CurrentDevicePath;
2766 EFI_HANDLE DriverHandle;
2767 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2768 EFI_STRING AccessProgress;
2769
2770 if (This == NULL || Progress == NULL) {
2771 return EFI_INVALID_PARAMETER;
2772 }
2773
2774 if (Configuration == NULL) {
2775 *Progress = NULL;
2776 return EFI_INVALID_PARAMETER;
2777 }
2778
2779 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2780 StringPtr = Configuration;
2781 *Progress = StringPtr;
2782
2783 //
2784 // The first element of <MultiConfigResp> should be
2785 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
2786 //
2787 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2788 return EFI_INVALID_PARAMETER;
2789 }
2790
2791 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
2792 //
2793 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
2794 // or most recent & before the error.
2795 //
2796 if (StringPtr == Configuration) {
2797 *Progress = StringPtr;
2798 } else {
2799 *Progress = StringPtr - 1;
2800 }
2801
2802 //
2803 // Process each <ConfigResp> of <MultiConfigResp>
2804 //
2805 Length = CalculateConfigStringLen (StringPtr);
2806 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
2807 if (ConfigResp == NULL) {
2808 return EFI_OUT_OF_RESOURCES;
2809 }
2810 //
2811 // Append '\0' to the end of ConfigRequest
2812 //
2813 *(ConfigResp + Length) = 0;
2814
2815 //
2816 // Get the UEFI device path
2817 //
2818 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
2819 if (EFI_ERROR (Status)) {
2820 FreePool (ConfigResp);
2821 return Status;
2822 }
2823
2824 //
2825 // Find driver which matches the routing data.
2826 //
2827 DriverHandle = NULL;
2828 for (Link = Private->DatabaseList.ForwardLink;
2829 Link != &Private->DatabaseList;
2830 Link = Link->ForwardLink
2831 ) {
2832 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2833
2834 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2835 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2836 if (CompareMem (
2837 DevicePath,
2838 CurrentDevicePath,
2839 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2840 ) == 0) {
2841 DriverHandle = Database->DriverHandle;
2842 break;
2843 }
2844 }
2845 }
2846
2847 //
2848 // Try to find driver handle by device path.
2849 //
2850 if (DriverHandle == NULL) {
2851 TempDevicePath = DevicePath;
2852 Status = gBS->LocateDevicePath (
2853 &gEfiDevicePathProtocolGuid,
2854 &TempDevicePath,
2855 &DriverHandle
2856 );
2857 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2858 //
2859 // Routing data does not match any known driver.
2860 // Set Progress to the 'G' in "GUID" of the routing header.
2861 //
2862 FreePool (DevicePath);
2863 *Progress = StringPtr;
2864 FreePool (ConfigResp);
2865 return EFI_NOT_FOUND;
2866 }
2867 }
2868
2869 FreePool (DevicePath);
2870
2871 //
2872 // Call corresponding ConfigAccess protocol to route settings
2873 //
2874 Status = gBS->HandleProtocol (
2875 DriverHandle,
2876 &gEfiHiiConfigAccessProtocolGuid,
2877 (VOID **) &ConfigAccess
2878 );
2879 ASSERT_EFI_ERROR (Status);
2880
2881 Status = ConfigAccess->RouteConfig (
2882 ConfigAccess,
2883 ConfigResp,
2884 &AccessProgress
2885 );
2886
2887 if (EFI_ERROR (Status)) {
2888 //
2889 // AccessProgress indicates the parsing progress on <ConfigResp>.
2890 // Map it to the progress on <MultiConfigResp> then return it.
2891 //
2892 *Progress = StrStr (StringPtr, AccessProgress);
2893
2894 FreePool (ConfigResp);
2895 return Status;
2896 }
2897
2898 FreePool (ConfigResp);
2899 ConfigResp = NULL;
2900
2901 //
2902 // Go to next <ConfigResp> (skip '&').
2903 //
2904 StringPtr += Length;
2905 if (*StringPtr == 0) {
2906 *Progress = StringPtr;
2907 break;
2908 }
2909
2910 StringPtr++;
2911
2912 }
2913
2914 return EFI_SUCCESS;
2915 }
2916
2917
2918 /**
2919 This helper function is to be called by drivers to map configuration data
2920 stored in byte array ("block") formats such as UEFI Variables into current
2921 configuration strings.
2922
2923 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2924 instance.
2925 @param ConfigRequest A null-terminated Unicode string in
2926 <ConfigRequest> format.
2927 @param Block Array of bytes defining the block's configuration.
2928 @param BlockSize Length in bytes of Block.
2929 @param Config Filled-in configuration string. String allocated
2930 by the function. Returned only if call is
2931 successful. It is <ConfigResp> string format.
2932 @param Progress A pointer to a string filled in with the offset of
2933 the most recent & before the first failing
2934 name/value pair (or the beginning of the string if
2935 the failure is in the first name / value pair) or
2936 the terminating NULL if all was successful.
2937
2938 @retval EFI_SUCCESS The request succeeded. Progress points to the null
2939 terminator at the end of the ConfigRequest
2940 string.
2941 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
2942 points to the first character of ConfigRequest.
2943 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
2944 Block parameter would result in this type of
2945 error. Progress points to the first character of
2946 ConfigRequest.
2947 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
2948 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
2949 Block is left updated and Progress points at
2950 the "&" preceding the first non-<BlockName>.
2951
2952 **/
2953 EFI_STATUS
2954 EFIAPI
2955 HiiBlockToConfig (
2956 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2957 IN CONST EFI_STRING ConfigRequest,
2958 IN CONST UINT8 *Block,
2959 IN CONST UINTN BlockSize,
2960 OUT EFI_STRING *Config,
2961 OUT EFI_STRING *Progress
2962 )
2963 {
2964 HII_DATABASE_PRIVATE_DATA *Private;
2965 EFI_STRING StringPtr;
2966 UINTN Length;
2967 EFI_STATUS Status;
2968 EFI_STRING TmpPtr;
2969 UINT8 *TmpBuffer;
2970 UINTN Offset;
2971 UINTN Width;
2972 UINT8 *Value;
2973 EFI_STRING ValueStr;
2974 EFI_STRING ConfigElement;
2975 UINTN Index;
2976 UINT8 *TemBuffer;
2977 CHAR16 *TemString;
2978
2979 if (This == NULL || Progress == NULL || Config == NULL) {
2980 return EFI_INVALID_PARAMETER;
2981 }
2982
2983 if (Block == NULL || ConfigRequest == NULL) {
2984 *Progress = ConfigRequest;
2985 return EFI_INVALID_PARAMETER;
2986 }
2987
2988
2989 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2990 ASSERT (Private != NULL);
2991
2992 StringPtr = ConfigRequest;
2993 ValueStr = NULL;
2994 Value = NULL;
2995 ConfigElement = NULL;
2996
2997 //
2998 // Allocate a fix length of memory to store Results. Reallocate memory for
2999 // Results if this fix length is insufficient.
3000 //
3001 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
3002 if (*Config == NULL) {
3003 return EFI_OUT_OF_RESOURCES;
3004 }
3005
3006 //
3007 // Jump <ConfigHdr>
3008 //
3009 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3010 *Progress = StringPtr;
3011 Status = EFI_INVALID_PARAMETER;
3012 goto Exit;
3013 }
3014 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3015 StringPtr++;
3016 }
3017 if (*StringPtr == 0) {
3018 *Progress = StringPtr - 1;
3019 Status = EFI_INVALID_PARAMETER;
3020 goto Exit;
3021 }
3022
3023 while (*StringPtr != L'&' && *StringPtr != 0) {
3024 StringPtr++;
3025 }
3026 if (*StringPtr == 0) {
3027 *Progress = StringPtr - 1;
3028 Status = EFI_INVALID_PARAMETER;
3029 goto Exit;
3030 }
3031 //
3032 // Skip '&'
3033 //
3034 StringPtr++;
3035
3036 //
3037 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
3038 //
3039 Length = StringPtr - ConfigRequest;
3040 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
3041
3042 //
3043 // Parse each <RequestElement> if exists
3044 // Only <BlockName> format is supported by this help function.
3045 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
3046 //
3047 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3048 //
3049 // Back up the header of one <BlockName>
3050 //
3051 TmpPtr = StringPtr;
3052
3053 StringPtr += StrLen (L"OFFSET=");
3054 //
3055 // Get Offset
3056 //
3057 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3058 if (EFI_ERROR (Status)) {
3059 *Progress = ConfigRequest;
3060 goto Exit;
3061 }
3062 Offset = 0;
3063 CopyMem (
3064 &Offset,
3065 TmpBuffer,
3066 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3067 );
3068 FreePool (TmpBuffer);
3069
3070 StringPtr += Length;
3071 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3072 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3073 Status = EFI_INVALID_PARAMETER;
3074 goto Exit;
3075 }
3076 StringPtr += StrLen (L"&WIDTH=");
3077
3078 //
3079 // Get Width
3080 //
3081 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3082 if (EFI_ERROR (Status)) {
3083 *Progress = ConfigRequest;
3084 goto Exit;
3085 }
3086 Width = 0;
3087 CopyMem (
3088 &Width,
3089 TmpBuffer,
3090 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3091 );
3092 FreePool (TmpBuffer);
3093
3094 StringPtr += Length;
3095 if (*StringPtr != 0 && *StringPtr != L'&') {
3096 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3097 Status = EFI_INVALID_PARAMETER;
3098 goto Exit;
3099 }
3100
3101 //
3102 // Calculate Value and convert it to hex string.
3103 //
3104 if (Offset + Width > BlockSize) {
3105 *Progress = StringPtr;
3106 Status = EFI_DEVICE_ERROR;
3107 goto Exit;
3108 }
3109
3110 Value = (UINT8 *) AllocateZeroPool (Width);
3111 if (Value == NULL) {
3112 *Progress = ConfigRequest;
3113 Status = EFI_OUT_OF_RESOURCES;
3114 goto Exit;
3115 }
3116
3117 CopyMem (Value, (UINT8 *) Block + Offset, Width);
3118
3119 Length = Width * 2 + 1;
3120 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
3121 if (ValueStr == NULL) {
3122 *Progress = ConfigRequest;
3123 Status = EFI_OUT_OF_RESOURCES;
3124 goto Exit;
3125 }
3126
3127 TemString = ValueStr;
3128 TemBuffer = Value + Width - 1;
3129 for (Index = 0; Index < Width; Index ++, TemBuffer --) {
3130 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
3131 }
3132
3133 FreePool (Value);
3134 Value = NULL;
3135
3136 //
3137 // Build a ConfigElement
3138 //
3139 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
3140 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
3141 if (ConfigElement == NULL) {
3142 Status = EFI_OUT_OF_RESOURCES;
3143 goto Exit;
3144 }
3145 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
3146 if (*StringPtr == 0) {
3147 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
3148 }
3149 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
3150 StrCat (ConfigElement, L"VALUE=");
3151 StrCat (ConfigElement, ValueStr);
3152
3153 AppendToMultiString (Config, ConfigElement);
3154
3155 FreePool (ConfigElement);
3156 FreePool (ValueStr);
3157 ConfigElement = NULL;
3158 ValueStr = NULL;
3159
3160 //
3161 // If '\0', parsing is finished. Otherwise skip '&' to continue
3162 //
3163 if (*StringPtr == 0) {
3164 break;
3165 }
3166 AppendToMultiString (Config, L"&");
3167 StringPtr++;
3168
3169 }
3170
3171 if (*StringPtr != 0) {
3172 *Progress = StringPtr - 1;
3173 Status = EFI_INVALID_PARAMETER;
3174 goto Exit;
3175 }
3176
3177 HiiToLower (*Config);
3178 *Progress = StringPtr;
3179 return EFI_SUCCESS;
3180
3181 Exit:
3182 if (*Config != NULL) {
3183 FreePool (*Config);
3184 *Config = NULL;
3185 }
3186 if (ValueStr != NULL) {
3187 FreePool (ValueStr);
3188 }
3189 if (Value != NULL) {
3190 FreePool (Value);
3191 }
3192 if (ConfigElement != NULL) {
3193 FreePool (ConfigElement);
3194 }
3195
3196 return Status;
3197
3198 }
3199
3200
3201 /**
3202 This helper function is to be called by drivers to map configuration strings
3203 to configurations stored in byte array ("block") formats such as UEFI Variables.
3204
3205 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3206 instance.
3207 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
3208 format.
3209 @param Block A possibly null array of bytes representing the
3210 current block. Only bytes referenced in the
3211 ConfigResp string in the block are modified. If
3212 this parameter is null or if the *BlockSize
3213 parameter is (on input) shorter than required by
3214 the Configuration string, only the BlockSize
3215 parameter is updated and an appropriate status
3216 (see below) is returned.
3217 @param BlockSize The length of the Block in units of UINT8. On
3218 input, this is the size of the Block. On output,
3219 if successful, contains the index of the last
3220 modified byte in the Block.
3221 @param Progress On return, points to an element of the ConfigResp
3222 string filled in with the offset of the most
3223 recent '&' before the first failing name / value
3224 pair (or the beginning of the string if the
3225 failure is in the first name / value pair) or the
3226 terminating NULL if all was successful.
3227
3228 @retval EFI_SUCCESS The request succeeded. Progress points to the null
3229 terminator at the end of the ConfigResp string.
3230 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
3231 points to the first character of ConfigResp.
3232 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
3233 Block parameter would result in this type of
3234 error. Progress points to the first character of
3235 ConfigResp.
3236 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
3237 value pair. Block is left updated and
3238 Progress points at the '&' preceding the first
3239 non-<BlockName>.
3240 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
3241 @retval EFI_NOT_FOUND Target for the specified routing data was not found.
3242 Progress points to the "G" in "GUID" of the errant
3243 routing data.
3244
3245 **/
3246 EFI_STATUS
3247 EFIAPI
3248 HiiConfigToBlock (
3249 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3250 IN CONST EFI_STRING ConfigResp,
3251 IN OUT UINT8 *Block,
3252 IN OUT UINTN *BlockSize,
3253 OUT EFI_STRING *Progress
3254 )
3255 {
3256 HII_DATABASE_PRIVATE_DATA *Private;
3257 EFI_STRING StringPtr;
3258 UINTN Length;
3259 EFI_STATUS Status;
3260 UINT8 *TmpBuffer;
3261 UINTN Offset;
3262 UINTN Width;
3263 UINT8 *Value;
3264 UINTN BufferSize;
3265 UINTN MaxBlockSize;
3266
3267 if (This == NULL || BlockSize == NULL || Progress == NULL) {
3268 return EFI_INVALID_PARAMETER;
3269 }
3270
3271 *Progress = ConfigResp;
3272 if (ConfigResp == NULL) {
3273 return EFI_INVALID_PARAMETER;
3274 }
3275
3276 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3277 ASSERT (Private != NULL);
3278
3279 StringPtr = ConfigResp;
3280 BufferSize = *BlockSize;
3281 Value = NULL;
3282 MaxBlockSize = 0;
3283
3284 //
3285 // Jump <ConfigHdr>
3286 //
3287 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3288 *Progress = StringPtr;
3289 Status = EFI_INVALID_PARAMETER;
3290 goto Exit;
3291 }
3292 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3293 StringPtr++;
3294 }
3295 if (*StringPtr == 0) {
3296 *Progress = StringPtr;
3297 Status = EFI_INVALID_PARAMETER;
3298 goto Exit;
3299 }
3300
3301 while (*StringPtr != L'&' && *StringPtr != 0) {
3302 StringPtr++;
3303 }
3304 if (*StringPtr == 0) {
3305 *Progress = StringPtr;
3306 Status = EFI_INVALID_PARAMETER;
3307 goto Exit;
3308 }
3309 //
3310 // Skip '&'
3311 //
3312 StringPtr++;
3313
3314 //
3315 // Parse each <ConfigElement> if exists
3316 // Only <BlockConfig> format is supported by this help function.
3317 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
3318 //
3319 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3320 StringPtr += StrLen (L"OFFSET=");
3321 //
3322 // Get Offset
3323 //
3324 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3325 if (EFI_ERROR (Status)) {
3326 *Progress = ConfigResp;
3327 goto Exit;
3328 }
3329 Offset = 0;
3330 CopyMem (
3331 &Offset,
3332 TmpBuffer,
3333 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3334 );
3335 FreePool (TmpBuffer);
3336
3337 StringPtr += Length;
3338 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3339 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3340 Status = EFI_INVALID_PARAMETER;
3341 goto Exit;
3342 }
3343 StringPtr += StrLen (L"&WIDTH=");
3344
3345 //
3346 // Get Width
3347 //
3348 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3349 if (EFI_ERROR (Status)) {
3350 *Progress = ConfigResp;
3351 goto Exit;
3352 }
3353 Width = 0;
3354 CopyMem (
3355 &Width,
3356 TmpBuffer,
3357 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3358 );
3359 FreePool (TmpBuffer);
3360
3361 StringPtr += Length;
3362 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
3363 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3364 Status = EFI_INVALID_PARAMETER;
3365 goto Exit;
3366 }
3367 StringPtr += StrLen (L"&VALUE=");
3368
3369 //
3370 // Get Value
3371 //
3372 Status = GetValueOfNumber (StringPtr, &Value, &Length);
3373 if (EFI_ERROR (Status)) {
3374 *Progress = ConfigResp;
3375 goto Exit;
3376 }
3377
3378 StringPtr += Length;
3379 if (*StringPtr != 0 && *StringPtr != L'&') {
3380 *Progress = StringPtr - Length - 7;
3381 Status = EFI_INVALID_PARAMETER;
3382 goto Exit;
3383 }
3384
3385 //
3386 // Update the Block with configuration info
3387 //
3388 if ((Block != NULL) && (Offset + Width <= BufferSize)) {
3389 CopyMem (Block + Offset, Value, Width);
3390 }
3391 if (Offset + Width > MaxBlockSize) {
3392 MaxBlockSize = Offset + Width;
3393 }
3394
3395 FreePool (Value);
3396 Value = NULL;
3397
3398 //
3399 // If '\0', parsing is finished. Otherwise skip '&' to continue
3400 //
3401 if (*StringPtr == 0) {
3402 break;
3403 }
3404
3405 StringPtr++;
3406 }
3407
3408 //
3409 // The input string is ConfigAltResp format.
3410 //
3411 if ((*StringPtr != 0) && (StrnCmp (StringPtr, L"&GUID=", StrLen (L"&GUID=")) != 0)) {
3412 *Progress = StringPtr - 1;
3413 Status = EFI_INVALID_PARAMETER;
3414 goto Exit;
3415 }
3416
3417 *Progress = StringPtr + StrLen (StringPtr);
3418 *BlockSize = MaxBlockSize - 1;
3419
3420 if (MaxBlockSize > BufferSize) {
3421 *BlockSize = MaxBlockSize;
3422 if (Block != NULL) {
3423 return EFI_DEVICE_ERROR;
3424 }
3425 }
3426
3427 if (Block == NULL) {
3428 *Progress = ConfigResp;
3429 return EFI_INVALID_PARAMETER;
3430 }
3431
3432 return EFI_SUCCESS;
3433
3434 Exit:
3435
3436 if (Value != NULL) {
3437 FreePool (Value);
3438 }
3439 return Status;
3440 }
3441
3442
3443 /**
3444 This helper function is to be called by drivers to extract portions of
3445 a larger configuration string.
3446
3447 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3448 instance.
3449 @param Configuration A null-terminated Unicode string in
3450 <MultiConfigAltResp> format.
3451 @param Guid A pointer to the GUID value to search for in the
3452 routing portion of the ConfigResp string when
3453 retrieving the requested data. If Guid is NULL,
3454 then all GUID values will be searched for.
3455 @param Name A pointer to the NAME value to search for in the
3456 routing portion of the ConfigResp string when
3457 retrieving the requested data. If Name is NULL,
3458 then all Name values will be searched for.
3459 @param DevicePath A pointer to the PATH value to search for in the
3460 routing portion of the ConfigResp string when
3461 retrieving the requested data. If DevicePath is
3462 NULL, then all DevicePath values will be searched
3463 for.
3464 @param AltCfgId A pointer to the ALTCFG value to search for in the
3465 routing portion of the ConfigResp string when
3466 retrieving the requested data. If this parameter
3467 is NULL, then the current setting will be
3468 retrieved.
3469 @param AltCfgResp A pointer to a buffer which will be allocated by
3470 the function which contains the retrieved string
3471 as requested. This buffer is only allocated if
3472 the call was successful. It is <ConfigResp> format.
3473
3474 @retval EFI_SUCCESS The request succeeded. The requested data was
3475 extracted and placed in the newly allocated
3476 AltCfgResp buffer.
3477 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
3478 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
3479 @retval EFI_NOT_FOUND Target for the specified routing data was not
3480 found.
3481
3482 **/
3483 EFI_STATUS
3484 EFIAPI
3485 HiiGetAltCfg (
3486 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3487 IN CONST EFI_STRING Configuration,
3488 IN CONST EFI_GUID *Guid,
3489 IN CONST EFI_STRING Name,
3490 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3491 IN CONST UINT16 *AltCfgId,
3492 OUT EFI_STRING *AltCfgResp
3493 )
3494 {
3495 EFI_STATUS Status;
3496 EFI_STRING StringPtr;
3497 EFI_STRING HdrStart;
3498 EFI_STRING HdrEnd;
3499 EFI_STRING TmpPtr;
3500 UINTN Length;
3501 EFI_STRING GuidStr;
3502 EFI_STRING NameStr;
3503 EFI_STRING PathStr;
3504 EFI_STRING AltIdStr;
3505 EFI_STRING Result;
3506 BOOLEAN GuidFlag;
3507 BOOLEAN NameFlag;
3508 BOOLEAN PathFlag;
3509
3510 HdrStart = NULL;
3511 HdrEnd = NULL;
3512 GuidStr = NULL;
3513 NameStr = NULL;
3514 PathStr = NULL;
3515 AltIdStr = NULL;
3516 Result = NULL;
3517 GuidFlag = FALSE;
3518 NameFlag = FALSE;
3519 PathFlag = FALSE;
3520
3521 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
3522 return EFI_INVALID_PARAMETER;
3523 }
3524
3525 StringPtr = Configuration;
3526 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3527 return EFI_INVALID_PARAMETER;
3528 }
3529
3530 //
3531 // Generate the sub string for later matching.
3532 //
3533 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
3534 GenerateSubStr (
3535 L"PATH=",
3536 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
3537 (VOID *) DevicePath,
3538 1,
3539 &PathStr
3540 );
3541 if (AltCfgId != NULL) {
3542 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
3543 }
3544 if (Name != NULL) {
3545 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
3546 } else {
3547 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
3548 }
3549
3550 while (*StringPtr != 0) {
3551 //
3552 // Try to match the GUID
3553 //
3554 if (!GuidFlag) {
3555 TmpPtr = StrStr (StringPtr, GuidStr);
3556 if (TmpPtr == NULL) {
3557 Status = EFI_NOT_FOUND;
3558 goto Exit;
3559 }
3560 HdrStart = TmpPtr;
3561
3562 //
3563 // Jump to <NameHdr>
3564 //
3565 if (Guid != NULL) {
3566 StringPtr = TmpPtr + StrLen (GuidStr);
3567 } else {
3568 StringPtr = StrStr (TmpPtr, L"NAME=");
3569 if (StringPtr == NULL) {
3570 Status = EFI_NOT_FOUND;
3571 goto Exit;
3572 }
3573 }
3574 GuidFlag = TRUE;
3575 }
3576
3577 //
3578 // Try to match the NAME
3579 //
3580 if (GuidFlag && !NameFlag) {
3581 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
3582 GuidFlag = FALSE;
3583 } else {
3584 //
3585 // Jump to <PathHdr>
3586 //
3587 if (Name != NULL) {
3588 StringPtr += StrLen (NameStr);
3589 } else {
3590 StringPtr = StrStr (StringPtr, L"PATH=");
3591 if (StringPtr == NULL) {
3592 Status = EFI_NOT_FOUND;
3593 goto Exit;
3594 }
3595 }
3596 NameFlag = TRUE;
3597 }
3598 }
3599
3600 //
3601 // Try to match the DevicePath
3602 //
3603 if (GuidFlag && NameFlag && !PathFlag) {
3604 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
3605 GuidFlag = FALSE;
3606 NameFlag = FALSE;
3607 } else {
3608 //
3609 // Jump to '&' before <DescHdr> or <ConfigBody>
3610 //
3611 if (DevicePath != NULL) {
3612 StringPtr += StrLen (PathStr);
3613 } else {
3614 StringPtr = StrStr (StringPtr, L"&");
3615 if (StringPtr == NULL) {
3616 Status = EFI_NOT_FOUND;
3617 goto Exit;
3618 }
3619 StringPtr ++;
3620 }
3621 PathFlag = TRUE;
3622 HdrEnd = StringPtr;
3623 }
3624 }
3625
3626 //
3627 // Try to match the AltCfgId
3628 //
3629 if (GuidFlag && NameFlag && PathFlag) {
3630 if (AltCfgId == NULL) {
3631 //
3632 // Return Current Setting when AltCfgId is NULL.
3633 //
3634 Status = OutputConfigBody (StringPtr, &Result);
3635 goto Exit;
3636 }
3637 //
3638 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
3639 //
3640 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
3641 GuidFlag = FALSE;
3642 NameFlag = FALSE;
3643 PathFlag = FALSE;
3644 } else {
3645 //
3646 // Skip AltIdStr and &
3647 //
3648 StringPtr = StringPtr + StrLen (AltIdStr);
3649 Status = OutputConfigBody (StringPtr, &Result);
3650 goto Exit;
3651 }
3652 }
3653 }
3654
3655 Status = EFI_NOT_FOUND;
3656
3657 Exit:
3658 *AltCfgResp = NULL;
3659 if (!EFI_ERROR (Status) && (Result != NULL)) {
3660 //
3661 // Copy the <ConfigHdr> and <ConfigBody>
3662 //
3663 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
3664 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
3665 if (*AltCfgResp == NULL) {
3666 Status = EFI_OUT_OF_RESOURCES;
3667 } else {
3668 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
3669 StrCat (*AltCfgResp, Result);
3670 Status = EFI_SUCCESS;
3671 }
3672 }
3673
3674 if (GuidStr != NULL) {
3675 FreePool (GuidStr);
3676 }
3677 if (NameStr != NULL) {
3678 FreePool (NameStr);
3679 }
3680 if (PathStr != NULL) {
3681 FreePool (PathStr);
3682 }
3683 if (AltIdStr != NULL) {
3684 FreePool (AltIdStr);
3685 }
3686 if (Result != NULL) {
3687 FreePool (Result);
3688 }
3689
3690 return Status;
3691
3692 }
3693
3694