]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
Update ALTCFG reference from default name token to default ID.
[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 by CheckBox Flags
1162 //
1163 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
1164 //
1165 // Set standard ID to Manufacture ID
1166 //
1167 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1168 //
1169 // Prepare new DefaultValue
1170 //
1171 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1172 if (DefaultData == NULL) {
1173 Status = EFI_OUT_OF_RESOURCES;
1174 goto Done;
1175 }
1176 DefaultData->OpCode = IfrOpHdr->OpCode;
1177 DefaultData->DefaultId = VarDefaultId;
1178 DefaultData->Value = 1;
1179 //
1180 // Add DefaultValue into current BlockData
1181 //
1182 InsertDefaultValue (BlockData, DefaultData);
1183 }
1184
1185 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
1186 //
1187 // Set standard ID to Manufacture ID
1188 //
1189 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1190 //
1191 // Prepare new DefaultValue
1192 //
1193 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1194 if (DefaultData == NULL) {
1195 Status = EFI_OUT_OF_RESOURCES;
1196 goto Done;
1197 }
1198 DefaultData->OpCode = IfrOpHdr->OpCode;
1199 DefaultData->DefaultId = VarDefaultId;
1200 DefaultData->Value = 1;
1201 //
1202 // Add DefaultValue into current BlockData
1203 //
1204 InsertDefaultValue (BlockData, DefaultData);
1205 }
1206 break;
1207
1208 case EFI_IFR_STRING_OP:
1209 //
1210 // offset by question header
1211 // width MaxSize * sizeof (CHAR16)
1212 // no default value, only block array
1213 //
1214
1215 //
1216 // String question is not in IFR Form. This IFR form is not valid.
1217 //
1218 if (VarStorageData->Size == 0) {
1219 Status = EFI_INVALID_PARAMETER;
1220 goto Done;
1221 }
1222 //
1223 // Check whether this question is for the requested varstore.
1224 //
1225 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1226 if (IfrString->Question.VarStoreId != VarStorageData->VarStoreId) {
1227 break;
1228 }
1229
1230 //
1231 // Get Offset/Width by Question header and OneOf Flags
1232 //
1233 VarOffset = IfrString->Question.VarStoreInfo.VarOffset;
1234 VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1235
1236 //
1237 // Check whether this question is in requested block array.
1238 //
1239 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1240 //
1241 // This question is not in the requested string. Skip it.
1242 //
1243 break;
1244 }
1245
1246 //
1247 // Check this var question is in the var storage
1248 //
1249 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1250 Status = EFI_INVALID_PARAMETER;
1251 goto Done;
1252 }
1253
1254 //
1255 // Set Block Data
1256 //
1257 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1258 if (BlockData == NULL) {
1259 Status = EFI_OUT_OF_RESOURCES;
1260 goto Done;
1261 }
1262 BlockData->Offset = VarOffset;
1263 BlockData->Width = VarWidth;
1264 BlockData->QuestionId = IfrString->Question.QuestionId;
1265 BlockData->OpCode = IfrOpHdr->OpCode;
1266 InitializeListHead (&BlockData->DefaultValueEntry);
1267
1268 //
1269 // Add Block Data into VarStorageData BlockEntry
1270 //
1271 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1272
1273 //
1274 // No default value for string.
1275 //
1276 BlockData = NULL;
1277 break;
1278
1279 case EFI_IFR_PASSWORD_OP:
1280 //
1281 // offset by question header
1282 // width MaxSize * sizeof (CHAR16)
1283 // no default value, only block array
1284 //
1285
1286 //
1287 // Password question is not in IFR Form. This IFR form is not valid.
1288 //
1289 if (VarStorageData->Size == 0) {
1290 Status = EFI_INVALID_PARAMETER;
1291 goto Done;
1292 }
1293 //
1294 // Check whether this question is for the requested varstore.
1295 //
1296 IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
1297 if (IfrPassword->Question.VarStoreId != VarStorageData->VarStoreId) {
1298 break;
1299 }
1300
1301 //
1302 // Get Offset/Width by Question header and OneOf Flags
1303 //
1304 VarOffset = IfrPassword->Question.VarStoreInfo.VarOffset;
1305 VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
1306
1307 //
1308 // Check whether this question is in requested block array.
1309 //
1310 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1311 //
1312 // This question is not in the requested string. Skip it.
1313 //
1314 break;
1315 }
1316
1317 //
1318 // Check this var question is in the var storage
1319 //
1320 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1321 Status = EFI_INVALID_PARAMETER;
1322 goto Done;
1323 }
1324
1325 //
1326 // Set Block Data
1327 //
1328 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1329 if (BlockData == NULL) {
1330 Status = EFI_OUT_OF_RESOURCES;
1331 goto Done;
1332 }
1333 BlockData->Offset = VarOffset;
1334 BlockData->Width = VarWidth;
1335 BlockData->QuestionId = IfrPassword->Question.QuestionId;
1336 BlockData->OpCode = IfrOpHdr->OpCode;
1337 InitializeListHead (&BlockData->DefaultValueEntry);
1338
1339 //
1340 // Add Block Data into VarStorageData BlockEntry
1341 //
1342 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1343
1344 //
1345 // No default value for string.
1346 //
1347 BlockData = NULL;
1348 break;
1349
1350 case EFI_IFR_ONE_OF_OPTION_OP:
1351 //
1352 // No matched block data is ignored.
1353 //
1354 if (BlockData == NULL || BlockData->Scope == 0) {
1355 break;
1356 }
1357
1358 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1359 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1360 //
1361 // Get ordered list option data type.
1362 //
1363 if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
1364 VarWidth = 1;
1365 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
1366 VarWidth = 2;
1367 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
1368 VarWidth = 4;
1369 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
1370 VarWidth = 8;
1371 } else {
1372 //
1373 // Invalid ordered list option data type.
1374 //
1375 Status = EFI_INVALID_PARAMETER;
1376 FreePool (BlockData);
1377 goto Done;
1378 }
1379
1380 //
1381 // Calculate Ordered list QuestionId width.
1382 //
1383 BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
1384 //
1385 // Check whether this question is in requested block array.
1386 //
1387 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width)) {
1388 //
1389 // This question is not in the requested string. Skip it.
1390 //
1391 FreePool (BlockData);
1392 BlockData = NULL;
1393 break;
1394 }
1395 //
1396 // Check this var question is in the var storage
1397 //
1398 if ((BlockData->Offset + BlockData->Width) > VarStorageData->Size) {
1399 Status = EFI_INVALID_PARAMETER;
1400 FreePool (BlockData);
1401 goto Done;
1402 }
1403 //
1404 // Add Block Data into VarStorageData BlockEntry
1405 //
1406 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1407 //
1408 // No default data for OrderedList.
1409 //
1410 BlockData = NULL;
1411 break;
1412 }
1413
1414 if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
1415 (BlockData->OpCode == EFI_IFR_ONE_OF_OP && FirstOneOfOption)) {
1416 //
1417 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
1418 // The first oneof option value will be used as default value when no default value is specified.
1419 //
1420 FirstOneOfOption = FALSE;
1421 //
1422 // Set standard ID to Manufacture ID
1423 //
1424 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1425 //
1426 // Prepare new DefaultValue
1427 //
1428 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1429 if (DefaultData == NULL) {
1430 Status = EFI_OUT_OF_RESOURCES;
1431 goto Done;
1432 }
1433 DefaultData->OpCode = IfrOpHdr->OpCode;
1434 DefaultData->DefaultId = VarDefaultId;
1435 DefaultData->Value = IfrOneOfOption->Value.u64;
1436 //
1437 // Add DefaultValue into current BlockData
1438 //
1439 InsertDefaultValue (BlockData, DefaultData);
1440 }
1441
1442 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
1443 //
1444 // Set default ID to Manufacture ID
1445 //
1446 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1447 //
1448 // Prepare new DefaultValue
1449 //
1450 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1451 if (DefaultData == NULL) {
1452 Status = EFI_OUT_OF_RESOURCES;
1453 goto Done;
1454 }
1455 DefaultData->OpCode = IfrOpHdr->OpCode;
1456 DefaultData->DefaultId = VarDefaultId;
1457 DefaultData->Value = IfrOneOfOption->Value.u64;
1458 //
1459 // Add DefaultValue into current BlockData
1460 //
1461 InsertDefaultValue (BlockData, DefaultData);
1462 }
1463 break;
1464
1465 case EFI_IFR_DEFAULT_OP:
1466 //
1467 // Update Current BlockData to the default value.
1468 //
1469 if (BlockData == NULL || BlockData->Scope == 0) {
1470 //
1471 // No matched block data is ignored.
1472 //
1473 break;
1474 }
1475
1476 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1477 //
1478 // OrderedList Opcode is no default value.
1479 //
1480 break;
1481 }
1482 //
1483 // Get the DefaultId
1484 //
1485 IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
1486 VarDefaultId = IfrDefault->DefaultId;
1487 //
1488 // Prepare new DefaultValue
1489 //
1490 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1491 if (DefaultData == NULL) {
1492 Status = EFI_OUT_OF_RESOURCES;
1493 goto Done;
1494 }
1495 DefaultData->OpCode = IfrOpHdr->OpCode;
1496 DefaultData->DefaultId = VarDefaultId;
1497 DefaultData->Value = IfrDefault->Value.u64;
1498 //
1499 // Add DefaultValue into current BlockData
1500 //
1501 InsertDefaultValue (BlockData, DefaultData);
1502 break;
1503 case EFI_IFR_END_OP:
1504 //
1505 // End Opcode is for Var question.
1506 //
1507 if (BlockData != NULL && BlockData->Scope > 0) {
1508 BlockData->Scope--;
1509 }
1510 break;
1511 default:
1512 if (BlockData != NULL && BlockData->Scope > 0) {
1513 BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);
1514 }
1515 break;
1516 }
1517
1518 IfrOffset += IfrOpHdr->Length;
1519 }
1520
1521 Done:
1522 return Status;
1523 }
1524
1525 /**
1526 This function gets the full request string and full default value string by
1527 parsing IFR data in HII form packages.
1528
1529 When Request points to NULL string, the request string and default value string
1530 for each varstore in form package will return.
1531
1532 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1533 @param DevicePath Device Path which Hii Config Access Protocol is registered.
1534 @param Request Pointer to a null-terminated Unicode string in
1535 <ConfigRequest> format. When it doesn't contain
1536 any RequestElement, it will be updated to return
1537 the full RequestElement retrieved from IFR data.
1538 If it points to NULL, the request string for the first
1539 varstore in form package will be merged into a
1540 <MultiConfigRequest> format string and return.
1541 @param AltCfgResp Pointer to a null-terminated Unicode string in
1542 <ConfigAltResp> format. When the pointer is to NULL,
1543 the full default value string retrieved from IFR data
1544 will return. When the pinter is to a string, the
1545 full default value string retrieved from IFR data
1546 will be merged into the input string and return.
1547 When Request points to NULL, the default value string
1548 for each varstore in form package will be merged into
1549 a <MultiConfigAltResp> format string and return.
1550 @param PointerProgress Optional parameter, it can be be NULL.
1551 When it is not NULL, if Request is NULL, it returns NULL.
1552 On return, points to a character in the Request
1553 string. Points to the string's null terminator if
1554 request was successful. Points to the most recent
1555 & before the first failing name / value pair (or
1556 the beginning of the string if the failure is in
1557 the first name / value pair) if the request was
1558 not successful.
1559 @retval EFI_SUCCESS The Results string is set to the full request string.
1560 And AltCfgResp contains all default value string.
1561 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
1562 @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
1563 can't be found in Form package.
1564 @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
1565 @retval EFI_INVALID_PARAMETER Request points to NULL.
1566
1567 **/
1568 EFI_STATUS
1569 EFIAPI
1570 GetFullStringFromHiiFormPackages (
1571 IN HII_DATABASE_RECORD *DataBaseRecord,
1572 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1573 IN OUT EFI_STRING *Request,
1574 IN OUT EFI_STRING *AltCfgResp,
1575 OUT EFI_STRING *PointerProgress OPTIONAL
1576 )
1577 {
1578 EFI_STATUS Status;
1579 UINT8 *HiiFormPackage;
1580 UINTN PackageSize;
1581 UINTN ResultSize;
1582 IFR_BLOCK_DATA *RequestBlockArray;
1583 IFR_BLOCK_DATA *BlockData;
1584 IFR_BLOCK_DATA *NextBlockData;
1585 IFR_DEFAULT_DATA *DefaultValueData;
1586 IFR_DEFAULT_DATA *DefaultId;
1587 IFR_DEFAULT_DATA *DefaultIdArray;
1588 IFR_VARSTORAGE_DATA *VarStorageData;
1589 EFI_STRING DefaultAltCfgResp;
1590 EFI_STRING FullConfigRequest;
1591 EFI_STRING ConfigHdr;
1592 EFI_STRING GuidStr;
1593 EFI_STRING NameStr;
1594 EFI_STRING PathStr;
1595 EFI_STRING StringPtr;
1596 EFI_STRING Progress;
1597 UINTN Length;
1598 UINT8 *TmpBuffer;
1599 UINT16 Offset;
1600 UINT16 Width;
1601 LIST_ENTRY *Link;
1602 LIST_ENTRY *LinkData;
1603 LIST_ENTRY *LinkDefault;
1604 BOOLEAN DataExist;
1605
1606 if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {
1607 return EFI_INVALID_PARAMETER;
1608 }
1609
1610 //
1611 // Initialize the local variables.
1612 //
1613 RequestBlockArray = NULL;
1614 DefaultIdArray = NULL;
1615 VarStorageData = NULL;
1616 DefaultAltCfgResp = NULL;
1617 FullConfigRequest = NULL;
1618 ConfigHdr = NULL;
1619 GuidStr = NULL;
1620 NameStr = NULL;
1621 PathStr = NULL;
1622 HiiFormPackage = NULL;
1623 ResultSize = 0;
1624 PackageSize = 0;
1625 DataExist = FALSE;
1626 Progress = *Request;
1627
1628 //
1629 // 0. Get Hii Form Package by HiiHandle
1630 //
1631 Status = ExportFormPackages (
1632 &mPrivate,
1633 DataBaseRecord->Handle,
1634 DataBaseRecord->PackageList,
1635 0,
1636 PackageSize,
1637 HiiFormPackage,
1638 &ResultSize
1639 );
1640 if (EFI_ERROR (Status)) {
1641 return Status;
1642 }
1643
1644 HiiFormPackage = AllocatePool (ResultSize);
1645 if (HiiFormPackage == NULL) {
1646 Status = EFI_OUT_OF_RESOURCES;
1647 goto Done;
1648 }
1649
1650 //
1651 // Get HiiFormPackage by HiiHandle
1652 //
1653 PackageSize = ResultSize;
1654 ResultSize = 0;
1655 Status = ExportFormPackages (
1656 &mPrivate,
1657 DataBaseRecord->Handle,
1658 DataBaseRecord->PackageList,
1659 0,
1660 PackageSize,
1661 HiiFormPackage,
1662 &ResultSize
1663 );
1664 if (EFI_ERROR (Status)) {
1665 goto Done;
1666 }
1667
1668 //
1669 // 1. Get the request block array by Request String when Request string containts the block array.
1670 //
1671 StringPtr = NULL;
1672 if (*Request != NULL) {
1673 StringPtr = *Request;
1674 //
1675 // Jump <ConfigHdr>
1676 //
1677 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1678 Status = EFI_INVALID_PARAMETER;
1679 goto Done;
1680 }
1681 StringPtr += StrLen (L"GUID=");
1682 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
1683 StringPtr++;
1684 }
1685 if (*StringPtr == L'\0') {
1686 Status = EFI_INVALID_PARAMETER;
1687 goto Done;
1688 }
1689 StringPtr += StrLen (L"&NAME=");
1690 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
1691 StringPtr++;
1692 }
1693 if (*StringPtr == L'\0') {
1694 Status = EFI_INVALID_PARAMETER;
1695 goto Done;
1696 }
1697 StringPtr += StrLen (L"&PATH=");
1698 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1699 StringPtr ++;
1700 }
1701 //
1702 // Check the following string &OFFSET=
1703 //
1704 if (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
1705 Progress = StringPtr;
1706 Status = EFI_INVALID_PARAMETER;
1707 goto Done;
1708 } else if (*StringPtr == L'\0') {
1709 //
1710 // No request block is found.
1711 //
1712 StringPtr = NULL;
1713 }
1714 }
1715 if (StringPtr != NULL) {
1716 //
1717 // Init RequestBlockArray
1718 //
1719 RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1720 if (RequestBlockArray == NULL) {
1721 Status = EFI_OUT_OF_RESOURCES;
1722 goto Done;
1723 }
1724 InitializeListHead (&RequestBlockArray->Entry);
1725
1726 //
1727 // Get the request Block array from the request string
1728 // Offset and Width
1729 //
1730
1731 //
1732 // Parse each <RequestElement> if exists
1733 // Only <BlockName> format is supported by this help function.
1734 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
1735 //
1736 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
1737 //
1738 // Skip the OFFSET string
1739 //
1740 Progress = StringPtr;
1741 StringPtr += StrLen (L"&OFFSET=");
1742 //
1743 // Get Offset
1744 //
1745 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1746 if (EFI_ERROR (Status)) {
1747 goto Done;
1748 }
1749 Offset = 0;
1750 CopyMem (
1751 &Offset,
1752 TmpBuffer,
1753 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1754 );
1755 FreePool (TmpBuffer);
1756
1757 StringPtr += Length;
1758 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1759 Status = EFI_INVALID_PARAMETER;
1760 goto Done;
1761 }
1762 StringPtr += StrLen (L"&WIDTH=");
1763
1764 //
1765 // Get Width
1766 //
1767 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1768 if (EFI_ERROR (Status)) {
1769 goto Done;
1770 }
1771 Width = 0;
1772 CopyMem (
1773 &Width,
1774 TmpBuffer,
1775 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1776 );
1777 FreePool (TmpBuffer);
1778
1779 StringPtr += Length;
1780 if (*StringPtr != 0 && *StringPtr != L'&') {
1781 Status = EFI_INVALID_PARAMETER;
1782 goto Done;
1783 }
1784
1785 //
1786 // Set Block Data
1787 //
1788 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1789 if (BlockData == NULL) {
1790 Status = EFI_OUT_OF_RESOURCES;
1791 goto Done;
1792 }
1793 BlockData->Offset = Offset;
1794 BlockData->Width = Width;
1795 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
1796
1797 //
1798 // Skip &VALUE string if &VALUE does exists.
1799 //
1800 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
1801 StringPtr += StrLen (L"&VALUE=");
1802
1803 //
1804 // Get Value
1805 //
1806 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1807 if (EFI_ERROR (Status)) {
1808 Status = EFI_INVALID_PARAMETER;
1809 goto Done;
1810 }
1811
1812 StringPtr += Length;
1813 if (*StringPtr != 0 && *StringPtr != L'&') {
1814 Status = EFI_INVALID_PARAMETER;
1815 goto Done;
1816 }
1817 }
1818 //
1819 // If '\0', parsing is finished.
1820 //
1821 if (*StringPtr == 0) {
1822 break;
1823 }
1824 }
1825
1826 //
1827 // Merge the requested block data.
1828 //
1829 Link = RequestBlockArray->Entry.ForwardLink;
1830 while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
1831 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1832 NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
1833 if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
1834 if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
1835 BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
1836 }
1837 RemoveEntryList (Link->ForwardLink);
1838 FreePool (NextBlockData);
1839 continue;
1840 }
1841 Link = Link->ForwardLink;
1842 }
1843 }
1844
1845 //
1846 // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
1847 //
1848
1849 //
1850 // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
1851 //
1852 DefaultIdArray = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1853 if (DefaultIdArray == NULL) {
1854 Status = EFI_OUT_OF_RESOURCES;
1855 goto Done;
1856 }
1857 InitializeListHead (&DefaultIdArray->Entry);
1858
1859 //
1860 // Initialize VarStorageData to store the var store Block and Default value information.
1861 //
1862 VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
1863 if (VarStorageData == NULL) {
1864 Status = EFI_OUT_OF_RESOURCES;
1865 goto Done;
1866 }
1867 InitializeListHead (&VarStorageData->Entry);
1868 InitializeListHead (&VarStorageData->BlockEntry);
1869
1870 //
1871 // Parse the opcode in form pacakge to get the default setting.
1872 //
1873 Status = ParseIfrData (HiiFormPackage, (UINT32) PackageSize, *Request, RequestBlockArray, VarStorageData, DefaultIdArray);
1874 if (EFI_ERROR (Status)) {
1875 goto Done;
1876 }
1877
1878 //
1879 // No requested varstore in IFR data and directly return
1880 //
1881 if (VarStorageData->Size == 0) {
1882 Status = EFI_SUCCESS;
1883 goto Done;
1884 }
1885
1886 //
1887 // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
1888 //
1889
1890 //
1891 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
1892 //
1893 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);
1894 GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);
1895 GenerateSubStr (
1896 L"PATH=",
1897 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1898 (VOID *) DevicePath,
1899 1,
1900 &PathStr
1901 );
1902 Length = StrLen (GuidStr);
1903 Length = Length + StrLen (NameStr);
1904 Length = Length + StrLen (PathStr) + 1;
1905 ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
1906 if (ConfigHdr == NULL) {
1907 Status = EFI_OUT_OF_RESOURCES;
1908 goto Done;
1909 }
1910 StrCpy (ConfigHdr, GuidStr);
1911 StrCat (ConfigHdr, NameStr);
1912 StrCat (ConfigHdr, PathStr);
1913
1914 //
1915 // Remove the last character L'&'
1916 //
1917 *(ConfigHdr + StrLen (ConfigHdr) - 1) = L'\0';
1918
1919 if (RequestBlockArray == NULL) {
1920 //
1921 // Append VarStorageData BlockEntry into *Request string
1922 // Now support only one varstore in a form package.
1923 //
1924
1925 //
1926 // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
1927 // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
1928 //
1929
1930 //
1931 // Compute the length of the entire request starting with <ConfigHdr> and a
1932 // Null-terminator
1933 //
1934 DataExist = FALSE;
1935 Length = StrLen (ConfigHdr) + 1;
1936
1937 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
1938 //
1939 // Add <BlockName> length for each Offset/Width pair
1940 //
1941 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
1942 // | 8 | 4 | 7 | 4 |
1943 //
1944 DataExist = TRUE;
1945 Length = Length + (8 + 4 + 7 + 4);
1946 }
1947
1948 //
1949 // No any request block data is found. The request string can't be constructed.
1950 //
1951 if (!DataExist) {
1952 Status = EFI_SUCCESS;
1953 goto Done;
1954 }
1955
1956 //
1957 // Allocate buffer for the entire <ConfigRequest>
1958 //
1959 FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
1960 if (FullConfigRequest == NULL) {
1961 Status = EFI_OUT_OF_RESOURCES;
1962 goto Done;
1963 }
1964 StringPtr = FullConfigRequest;
1965
1966 //
1967 // Start with <ConfigHdr>
1968 //
1969 StrCpy (StringPtr, ConfigHdr);
1970 StringPtr += StrLen (StringPtr);
1971
1972 //
1973 // Loop through all the Offset/Width pairs and append them to ConfigRequest
1974 //
1975 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
1976 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1977 //
1978 // Append &OFFSET=XXXX&WIDTH=YYYY\0
1979 //
1980 UnicodeSPrint (
1981 StringPtr,
1982 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
1983 L"&OFFSET=%04X&WIDTH=%04X",
1984 BlockData->Offset,
1985 BlockData->Width
1986 );
1987 StringPtr += StrLen (StringPtr);
1988 }
1989 //
1990 // Set to the got full request string.
1991 //
1992 HiiToLower (FullConfigRequest);
1993 if (*Request != NULL) {
1994 FreePool (*Request);
1995 }
1996 *Request = FullConfigRequest;
1997 }
1998
1999 //
2000 // 4. Construct Default Value string in AltResp according to request element.
2001 // Go through all VarStorageData Entry and get the DefaultId array for each one
2002 // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
2003 //
2004 DataExist = FALSE;
2005 //
2006 // Add length for <ConfigHdr> + '\0'
2007 //
2008 Length = StrLen (ConfigHdr) + 1;
2009
2010 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2011 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2012 //
2013 // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
2014 // |1| StrLen (ConfigHdr) | 8 | 4 |
2015 //
2016 Length += (1 + StrLen (ConfigHdr) + 8 + 4);
2017
2018 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2019 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2020 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {
2021 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2022 if (DefaultValueData->DefaultId == DefaultId->DefaultId) {
2023 //
2024 // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
2025 // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
2026 //
2027 Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
2028 DataExist = TRUE;
2029 }
2030 }
2031 }
2032 }
2033
2034 //
2035 // No default value is found. The default string doesn't exist.
2036 //
2037 if (!DataExist) {
2038 Status = EFI_SUCCESS;
2039 goto Done;
2040 }
2041
2042 //
2043 // Allocate buffer for the entire <DefaultAltCfgResp>
2044 //
2045 DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
2046 if (DefaultAltCfgResp == NULL) {
2047 Status = EFI_OUT_OF_RESOURCES;
2048 goto Done;
2049 }
2050 StringPtr = DefaultAltCfgResp;
2051
2052 //
2053 // Start with <ConfigHdr>
2054 //
2055 StrCpy (StringPtr, ConfigHdr);
2056 StringPtr += StrLen (StringPtr);
2057
2058 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2059 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2060 //
2061 // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
2062 // |1| StrLen (ConfigHdr) | 8 | 4 |
2063 //
2064 UnicodeSPrint (
2065 StringPtr,
2066 (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
2067 L"&%s&ALTCFG=%04X",
2068 ConfigHdr,
2069 DefaultId->DefaultId
2070 );
2071 StringPtr += StrLen (StringPtr);
2072
2073 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2074 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2075 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {
2076 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2077 if (DefaultValueData->DefaultId == DefaultId->DefaultId) {
2078 //
2079 // Add <BlockConfig>
2080 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
2081 //
2082 UnicodeSPrint (
2083 StringPtr,
2084 (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
2085 L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
2086 BlockData->Offset,
2087 BlockData->Width
2088 );
2089 StringPtr += StrLen (StringPtr);
2090
2091 //
2092 // Convert Value to a hex string in "%x" format
2093 // NOTE: This is in the opposite byte that GUID and PATH use
2094 //
2095 Width = BlockData->Width;
2096 TmpBuffer = (UINT8 *) &(DefaultValueData->Value);
2097 for (; Width > 0; Width--) {
2098 StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2);
2099 }
2100 }
2101 }
2102 }
2103 }
2104 HiiToLower (DefaultAltCfgResp);
2105
2106 //
2107 // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL.
2108 //
2109 if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {
2110 Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
2111 FreePool (DefaultAltCfgResp);
2112 } else if (*AltCfgResp == NULL) {
2113 *AltCfgResp = DefaultAltCfgResp;
2114 }
2115
2116 Done:
2117 if (RequestBlockArray != NULL) {
2118 //
2119 // Free Link Array RequestBlockArray
2120 //
2121 while (!IsListEmpty (&RequestBlockArray->Entry)) {
2122 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2123 RemoveEntryList (&BlockData->Entry);
2124 FreePool (BlockData);
2125 }
2126
2127 FreePool (RequestBlockArray);
2128 }
2129
2130 if (VarStorageData != NULL) {
2131 //
2132 // Free link array VarStorageData
2133 //
2134 while (!IsListEmpty (&VarStorageData->BlockEntry)) {
2135 BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
2136 RemoveEntryList (&BlockData->Entry);
2137 //
2138 // Free default value link array
2139 //
2140 while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
2141 DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
2142 RemoveEntryList (&DefaultValueData->Entry);
2143 FreePool (DefaultValueData);
2144 }
2145 FreePool (BlockData);
2146 }
2147 FreePool (VarStorageData);
2148 }
2149
2150 if (DefaultIdArray != NULL) {
2151 //
2152 // Free DefaultId Array
2153 //
2154 while (!IsListEmpty (&DefaultIdArray->Entry)) {
2155 DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
2156 RemoveEntryList (&DefaultId->Entry);
2157 FreePool (DefaultId);
2158 }
2159 FreePool (DefaultIdArray);
2160 }
2161
2162 //
2163 // Free the allocated string
2164 //
2165 if (GuidStr != NULL) {
2166 FreePool (GuidStr);
2167 }
2168 if (NameStr != NULL) {
2169 FreePool (NameStr);
2170 }
2171 if (PathStr != NULL) {
2172 FreePool (PathStr);
2173 }
2174 if (ConfigHdr != NULL) {
2175 FreePool (ConfigHdr);
2176 }
2177
2178 //
2179 // Free Pacakge data
2180 //
2181 if (HiiFormPackage != NULL) {
2182 FreePool (HiiFormPackage);
2183 }
2184
2185 if (PointerProgress != NULL) {
2186 if (*Request == NULL) {
2187 *PointerProgress = NULL;
2188 } else if (EFI_ERROR (Status)) {
2189 *PointerProgress = Progress;
2190 } else {
2191 *PointerProgress = *Request + StrLen (*Request);
2192 }
2193 }
2194
2195 return Status;
2196 }
2197
2198 /**
2199 This function allows a caller to extract the current configuration
2200 for one or more named elements from one or more drivers.
2201
2202 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2203 instance.
2204 @param Request A null-terminated Unicode string in
2205 <MultiConfigRequest> format.
2206 @param Progress On return, points to a character in the Request
2207 string. Points to the string's null terminator if
2208 request was successful. Points to the most recent
2209 & before the first failing name / value pair (or
2210 the beginning of the string if the failure is in
2211 the first name / value pair) if the request was
2212 not successful.
2213 @param Results Null-terminated Unicode string in
2214 <MultiConfigAltResp> format which has all values
2215 filled in for the names in the Request string.
2216 String to be allocated by the called function.
2217
2218 @retval EFI_SUCCESS The Results string is filled with the values
2219 corresponding to all requested names.
2220 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2221 results that must be stored awaiting possible
2222 future protocols.
2223 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
2224 Progress set to the "G" in "GUID" of the routing
2225 header that doesn't match. Note: There is no
2226 requirement that all routing data be validated
2227 before any configuration extraction.
2228 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
2229 parameter would result in this type of error. The
2230 Progress parameter is set to NULL.
2231 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
2232 before the error or the beginning of the string.
2233 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
2234 name in question.
2235
2236 **/
2237 EFI_STATUS
2238 EFIAPI
2239 HiiConfigRoutingExtractConfig (
2240 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2241 IN CONST EFI_STRING Request,
2242 OUT EFI_STRING *Progress,
2243 OUT EFI_STRING *Results
2244 )
2245 {
2246 HII_DATABASE_PRIVATE_DATA *Private;
2247 EFI_STRING StringPtr;
2248 EFI_STRING ConfigRequest;
2249 UINTN Length;
2250 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2251 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2252 EFI_STATUS Status;
2253 LIST_ENTRY *Link;
2254 HII_DATABASE_RECORD *Database;
2255 UINT8 *DevicePathPkg;
2256 UINT8 *CurrentDevicePath;
2257 EFI_HANDLE DriverHandle;
2258 EFI_HII_HANDLE HiiHandle;
2259 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2260 EFI_STRING AccessProgress;
2261 EFI_STRING AccessResults;
2262 EFI_STRING DefaultResults;
2263 BOOLEAN FirstElement;
2264 BOOLEAN IfrDataParsedFlag;
2265
2266 if (This == NULL || Progress == NULL || Results == NULL) {
2267 return EFI_INVALID_PARAMETER;
2268 }
2269
2270 if (Request == NULL) {
2271 *Progress = NULL;
2272 return EFI_INVALID_PARAMETER;
2273 }
2274
2275 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2276 StringPtr = Request;
2277 *Progress = StringPtr;
2278 DefaultResults = NULL;
2279 ConfigRequest = NULL;
2280 Status = EFI_SUCCESS;
2281 AccessResults = NULL;
2282 DevicePath = NULL;
2283 IfrDataParsedFlag = FALSE;
2284
2285 //
2286 // The first element of <MultiConfigRequest> should be
2287 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
2288 //
2289 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2290 return EFI_INVALID_PARAMETER;
2291 }
2292
2293 FirstElement = TRUE;
2294
2295 //
2296 // Allocate a fix length of memory to store Results. Reallocate memory for
2297 // Results if this fix length is insufficient.
2298 //
2299 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2300 if (*Results == NULL) {
2301 return EFI_OUT_OF_RESOURCES;
2302 }
2303
2304 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
2305 //
2306 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
2307 // or most recent & before the error.
2308 //
2309 if (StringPtr == Request) {
2310 *Progress = StringPtr;
2311 } else {
2312 *Progress = StringPtr - 1;
2313 }
2314
2315 //
2316 // Process each <ConfigRequest> of <MultiConfigRequest>
2317 //
2318 Length = CalculateConfigStringLen (StringPtr);
2319 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
2320 if (ConfigRequest == NULL) {
2321 Status = EFI_OUT_OF_RESOURCES;
2322 goto Done;
2323 }
2324 *(ConfigRequest + Length) = 0;
2325
2326 //
2327 // Get the UEFI device path
2328 //
2329 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
2330 if (EFI_ERROR (Status)) {
2331 goto Done;
2332 }
2333
2334 //
2335 // Find driver which matches the routing data.
2336 //
2337 DriverHandle = NULL;
2338 HiiHandle = NULL;
2339 Database = NULL;
2340 for (Link = Private->DatabaseList.ForwardLink;
2341 Link != &Private->DatabaseList;
2342 Link = Link->ForwardLink
2343 ) {
2344 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2345 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2346 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2347 if (CompareMem (
2348 DevicePath,
2349 CurrentDevicePath,
2350 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2351 ) == 0) {
2352 DriverHandle = Database->DriverHandle;
2353 HiiHandle = Database->Handle;
2354 break;
2355 }
2356 }
2357 }
2358
2359 //
2360 // Try to find driver handle by device path.
2361 //
2362 if (DriverHandle == NULL) {
2363 TempDevicePath = DevicePath;
2364 Status = gBS->LocateDevicePath (
2365 &gEfiDevicePathProtocolGuid,
2366 &TempDevicePath,
2367 &DriverHandle
2368 );
2369 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2370 //
2371 // Routing data does not match any known driver.
2372 // Set Progress to the 'G' in "GUID" of the routing header.
2373 //
2374 *Progress = StringPtr;
2375 Status = EFI_NOT_FOUND;
2376 goto Done;
2377 }
2378 }
2379
2380 //
2381 // Check whether ConfigRequest contains request string OFFSET/WIDTH
2382 //
2383 IfrDataParsedFlag = FALSE;
2384 if ((HiiHandle != NULL) && (StrStr (ConfigRequest, L"&OFFSET=") == NULL)) {
2385 //
2386 // Get the full request string from IFR when HiiPackage is registered to HiiHandle
2387 //
2388 IfrDataParsedFlag = TRUE;
2389 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
2390 if (EFI_ERROR (Status)) {
2391 //
2392 // AccessProgress indicates the parsing progress on <ConfigRequest>.
2393 // Map it to the progress on <MultiConfigRequest> then return it.
2394 //
2395 *Progress = StrStr (StringPtr, AccessProgress);
2396 goto Done;
2397 }
2398 //
2399 // Not any request block is found.
2400 //
2401 if (StrStr (ConfigRequest, L"&OFFSET=") == NULL) {
2402 AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
2403 goto NextConfigString;
2404 }
2405 }
2406
2407 //
2408 // Call corresponding ConfigAccess protocol to extract settings
2409 //
2410 Status = gBS->HandleProtocol (
2411 DriverHandle,
2412 &gEfiHiiConfigAccessProtocolGuid,
2413 (VOID **) &ConfigAccess
2414 );
2415 ASSERT_EFI_ERROR (Status);
2416
2417 Status = ConfigAccess->ExtractConfig (
2418 ConfigAccess,
2419 ConfigRequest,
2420 &AccessProgress,
2421 &AccessResults
2422 );
2423 if (EFI_ERROR (Status)) {
2424 //
2425 // AccessProgress indicates the parsing progress on <ConfigRequest>.
2426 // Map it to the progress on <MultiConfigRequest> then return it.
2427 //
2428 *Progress = StrStr (StringPtr, AccessProgress);
2429 goto Done;
2430 }
2431
2432 //
2433 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
2434 // which seperates the first <ConfigAltResp> and the following ones.
2435 //
2436 ASSERT (*AccessProgress == 0);
2437
2438 //
2439 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2440 //
2441 if (!IfrDataParsedFlag && HiiHandle != NULL) {
2442 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
2443 ASSERT_EFI_ERROR (Status);
2444 }
2445
2446 FreePool (DevicePath);
2447 DevicePath = NULL;
2448
2449 if (DefaultResults != NULL) {
2450 Status = MergeDefaultString (&AccessResults, DefaultResults);
2451 ASSERT_EFI_ERROR (Status);
2452 FreePool (DefaultResults);
2453 DefaultResults = NULL;
2454 }
2455
2456 NextConfigString:
2457 if (!FirstElement) {
2458 Status = AppendToMultiString (Results, L"&");
2459 ASSERT_EFI_ERROR (Status);
2460 }
2461
2462 Status = AppendToMultiString (Results, AccessResults);
2463 ASSERT_EFI_ERROR (Status);
2464
2465 FirstElement = FALSE;
2466
2467 FreePool (AccessResults);
2468 AccessResults = NULL;
2469 FreePool (ConfigRequest);
2470 ConfigRequest = NULL;
2471
2472 //
2473 // Go to next <ConfigRequest> (skip '&').
2474 //
2475 StringPtr += Length;
2476 if (*StringPtr == 0) {
2477 *Progress = StringPtr;
2478 break;
2479 }
2480
2481 StringPtr++;
2482 }
2483
2484 Done:
2485 if (EFI_ERROR (Status)) {
2486 FreePool (*Results);
2487 *Results = NULL;
2488 }
2489
2490 if (ConfigRequest != NULL) {
2491 FreePool (ConfigRequest);
2492 }
2493
2494 if (AccessResults != NULL) {
2495 FreePool (AccessResults);
2496 }
2497
2498 if (DefaultResults != NULL) {
2499 FreePool (DefaultResults);
2500 }
2501
2502 if (DevicePath != NULL) {
2503 FreePool (DevicePath);
2504 }
2505
2506 return Status;
2507 }
2508
2509
2510 /**
2511 This function allows the caller to request the current configuration for the
2512 entirety of the current HII database and returns the data in a
2513 null-terminated Unicode string.
2514
2515 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2516 instance.
2517 @param Results Null-terminated Unicode string in
2518 <MultiConfigAltResp> format which has all values
2519 filled in for the names in the Request string.
2520 String to be allocated by the called function.
2521 De-allocation is up to the caller.
2522
2523 @retval EFI_SUCCESS The Results string is filled with the values
2524 corresponding to all requested names.
2525 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2526 results that must be stored awaiting possible
2527 future protocols.
2528 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
2529 parameter would result in this type of error.
2530
2531 **/
2532 EFI_STATUS
2533 EFIAPI
2534 HiiConfigRoutingExportConfig (
2535 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2536 OUT EFI_STRING *Results
2537 )
2538 {
2539 EFI_STATUS Status;
2540 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2541 EFI_STRING AccessResults;
2542 EFI_STRING Progress;
2543 EFI_STRING StringPtr;
2544 EFI_STRING ConfigRequest;
2545 UINTN Index;
2546 EFI_HANDLE *ConfigAccessHandles;
2547 UINTN NumberConfigAccessHandles;
2548 BOOLEAN FirstElement;
2549 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2550 EFI_HII_HANDLE HiiHandle;
2551 EFI_STRING DefaultResults;
2552 HII_DATABASE_PRIVATE_DATA *Private;
2553 LIST_ENTRY *Link;
2554 HII_DATABASE_RECORD *Database;
2555 UINT8 *DevicePathPkg;
2556 UINT8 *CurrentDevicePath;
2557 BOOLEAN IfrDataParsedFlag;
2558
2559 if (This == NULL || Results == NULL) {
2560 return EFI_INVALID_PARAMETER;
2561 }
2562
2563 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2564
2565 //
2566 // Allocate a fix length of memory to store Results. Reallocate memory for
2567 // Results if this fix length is insufficient.
2568 //
2569 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2570 if (*Results == NULL) {
2571 return EFI_OUT_OF_RESOURCES;
2572 }
2573
2574 NumberConfigAccessHandles = 0;
2575 Status = gBS->LocateHandleBuffer (
2576 ByProtocol,
2577 &gEfiHiiConfigAccessProtocolGuid,
2578 NULL,
2579 &NumberConfigAccessHandles,
2580 &ConfigAccessHandles
2581 );
2582 if (EFI_ERROR (Status)) {
2583 return Status;
2584 }
2585
2586 FirstElement = TRUE;
2587
2588 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
2589 Status = gBS->HandleProtocol (
2590 ConfigAccessHandles[Index],
2591 &gEfiHiiConfigAccessProtocolGuid,
2592 (VOID **) &ConfigAccess
2593 );
2594 if (EFI_ERROR (Status)) {
2595 continue;
2596 }
2597
2598 //
2599 // Get DevicePath and HiiHandle for this ConfigAccess driver handle
2600 //
2601 IfrDataParsedFlag = FALSE;
2602 Progress = NULL;
2603 HiiHandle = NULL;
2604 DefaultResults = NULL;
2605 Database = NULL;
2606 ConfigRequest = NULL;
2607 DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
2608 if (DevicePath != NULL) {
2609 for (Link = Private->DatabaseList.ForwardLink;
2610 Link != &Private->DatabaseList;
2611 Link = Link->ForwardLink
2612 ) {
2613 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2614 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2615 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2616 if (CompareMem (
2617 DevicePath,
2618 CurrentDevicePath,
2619 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2620 ) == 0) {
2621 HiiHandle = Database->Handle;
2622 break;
2623 }
2624 }
2625 }
2626 }
2627
2628 Status = ConfigAccess->ExtractConfig (
2629 ConfigAccess,
2630 NULL,
2631 &Progress,
2632 &AccessResults
2633 );
2634 if (EFI_ERROR (Status)) {
2635 //
2636 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2637 //
2638 if (HiiHandle != NULL && DevicePath != NULL) {
2639 IfrDataParsedFlag = TRUE;
2640 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
2641 //
2642 // Get the full request string to get the Current setting again.
2643 //
2644 if (!EFI_ERROR (Status) && ConfigRequest != NULL) {
2645 Status = ConfigAccess->ExtractConfig (
2646 ConfigAccess,
2647 ConfigRequest,
2648 &Progress,
2649 &AccessResults
2650 );
2651 FreePool (ConfigRequest);
2652 } else {
2653 Status = EFI_NOT_FOUND;
2654 }
2655 }
2656 }
2657
2658 if (!EFI_ERROR (Status)) {
2659 //
2660 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2661 //
2662 if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {
2663 StringPtr = StrStr (AccessResults, L"&GUID=");
2664 if (StringPtr != NULL) {
2665 *StringPtr = 0;
2666 }
2667 if (StrStr (AccessResults, L"&OFFSET=") != NULL) {
2668 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
2669 ASSERT_EFI_ERROR (Status);
2670 }
2671 if (StringPtr != NULL) {
2672 *StringPtr = L'&';
2673 }
2674 }
2675 //
2676 // Merge the default sting from IFR code into the got setting from driver.
2677 //
2678 if (DefaultResults != NULL) {
2679 Status = MergeDefaultString (&AccessResults, DefaultResults);
2680 ASSERT_EFI_ERROR (Status);
2681 FreePool (DefaultResults);
2682 DefaultResults = NULL;
2683 }
2684
2685 //
2686 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
2687 // which seperates the first <ConfigAltResp> and the following ones.
2688 //
2689 if (!FirstElement) {
2690 Status = AppendToMultiString (Results, L"&");
2691 ASSERT_EFI_ERROR (Status);
2692 }
2693
2694 Status = AppendToMultiString (Results, AccessResults);
2695 ASSERT_EFI_ERROR (Status);
2696
2697 FirstElement = FALSE;
2698
2699 FreePool (AccessResults);
2700 AccessResults = NULL;
2701 }
2702 }
2703 FreePool (ConfigAccessHandles);
2704
2705 return EFI_SUCCESS;
2706 }
2707
2708
2709 /**
2710 This function processes the results of processing forms and routes it to the
2711 appropriate handlers or storage.
2712
2713 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2714 instance.
2715 @param Configuration A null-terminated Unicode string in
2716 <MulltiConfigResp> format.
2717 @param Progress A pointer to a string filled in with the offset of
2718 the most recent & before the first failing name /
2719 value pair (or the beginning of the string if the
2720 failure is in the first name / value pair) or the
2721 terminating NULL if all was successful.
2722
2723 @retval EFI_SUCCESS The results have been distributed or are awaiting
2724 distribution.
2725 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2726 results that must be stored awaiting possible
2727 future protocols.
2728 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
2729 would result in this type of error.
2730 @retval EFI_NOT_FOUND Target for the specified routing data was not
2731 found.
2732
2733 **/
2734 EFI_STATUS
2735 EFIAPI
2736 HiiConfigRoutingRouteConfig (
2737 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2738 IN CONST EFI_STRING Configuration,
2739 OUT EFI_STRING *Progress
2740 )
2741 {
2742 HII_DATABASE_PRIVATE_DATA *Private;
2743 EFI_STRING StringPtr;
2744 EFI_STRING ConfigResp;
2745 UINTN Length;
2746 EFI_STATUS Status;
2747 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2748 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2749 LIST_ENTRY *Link;
2750 HII_DATABASE_RECORD *Database;
2751 UINT8 *DevicePathPkg;
2752 UINT8 *CurrentDevicePath;
2753 EFI_HANDLE DriverHandle;
2754 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2755 EFI_STRING AccessProgress;
2756
2757 if (This == NULL || Progress == NULL) {
2758 return EFI_INVALID_PARAMETER;
2759 }
2760
2761 if (Configuration == NULL) {
2762 *Progress = NULL;
2763 return EFI_INVALID_PARAMETER;
2764 }
2765
2766 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2767 StringPtr = Configuration;
2768 *Progress = StringPtr;
2769
2770 //
2771 // The first element of <MultiConfigResp> should be
2772 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
2773 //
2774 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2775 return EFI_INVALID_PARAMETER;
2776 }
2777
2778 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
2779 //
2780 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
2781 // or most recent & before the error.
2782 //
2783 if (StringPtr == Configuration) {
2784 *Progress = StringPtr;
2785 } else {
2786 *Progress = StringPtr - 1;
2787 }
2788
2789 //
2790 // Process each <ConfigResp> of <MultiConfigResp>
2791 //
2792 Length = CalculateConfigStringLen (StringPtr);
2793 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
2794 if (ConfigResp == NULL) {
2795 return EFI_OUT_OF_RESOURCES;
2796 }
2797 //
2798 // Append '\0' to the end of ConfigRequest
2799 //
2800 *(ConfigResp + Length) = 0;
2801
2802 //
2803 // Get the UEFI device path
2804 //
2805 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
2806 if (EFI_ERROR (Status)) {
2807 FreePool (ConfigResp);
2808 return Status;
2809 }
2810
2811 //
2812 // Find driver which matches the routing data.
2813 //
2814 DriverHandle = NULL;
2815 for (Link = Private->DatabaseList.ForwardLink;
2816 Link != &Private->DatabaseList;
2817 Link = Link->ForwardLink
2818 ) {
2819 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2820
2821 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2822 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2823 if (CompareMem (
2824 DevicePath,
2825 CurrentDevicePath,
2826 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2827 ) == 0) {
2828 DriverHandle = Database->DriverHandle;
2829 break;
2830 }
2831 }
2832 }
2833
2834 //
2835 // Try to find driver handle by device path.
2836 //
2837 if (DriverHandle == NULL) {
2838 TempDevicePath = DevicePath;
2839 Status = gBS->LocateDevicePath (
2840 &gEfiDevicePathProtocolGuid,
2841 &TempDevicePath,
2842 &DriverHandle
2843 );
2844 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2845 //
2846 // Routing data does not match any known driver.
2847 // Set Progress to the 'G' in "GUID" of the routing header.
2848 //
2849 FreePool (DevicePath);
2850 *Progress = StringPtr;
2851 FreePool (ConfigResp);
2852 return EFI_NOT_FOUND;
2853 }
2854 }
2855
2856 FreePool (DevicePath);
2857
2858 //
2859 // Call corresponding ConfigAccess protocol to route settings
2860 //
2861 Status = gBS->HandleProtocol (
2862 DriverHandle,
2863 &gEfiHiiConfigAccessProtocolGuid,
2864 (VOID **) &ConfigAccess
2865 );
2866 ASSERT_EFI_ERROR (Status);
2867
2868 Status = ConfigAccess->RouteConfig (
2869 ConfigAccess,
2870 ConfigResp,
2871 &AccessProgress
2872 );
2873
2874 if (EFI_ERROR (Status)) {
2875 //
2876 // AccessProgress indicates the parsing progress on <ConfigResp>.
2877 // Map it to the progress on <MultiConfigResp> then return it.
2878 //
2879 *Progress = StrStr (StringPtr, AccessProgress);
2880
2881 FreePool (ConfigResp);
2882 return Status;
2883 }
2884
2885 FreePool (ConfigResp);
2886 ConfigResp = NULL;
2887
2888 //
2889 // Go to next <ConfigResp> (skip '&').
2890 //
2891 StringPtr += Length;
2892 if (*StringPtr == 0) {
2893 *Progress = StringPtr;
2894 break;
2895 }
2896
2897 StringPtr++;
2898
2899 }
2900
2901 return EFI_SUCCESS;
2902 }
2903
2904
2905 /**
2906 This helper function is to be called by drivers to map configuration data
2907 stored in byte array ("block") formats such as UEFI Variables into current
2908 configuration strings.
2909
2910 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2911 instance.
2912 @param ConfigRequest A null-terminated Unicode string in
2913 <ConfigRequest> format.
2914 @param Block Array of bytes defining the block's configuration.
2915 @param BlockSize Length in bytes of Block.
2916 @param Config Filled-in configuration string. String allocated
2917 by the function. Returned only if call is
2918 successful. It is <ConfigResp> string format.
2919 @param Progress A pointer to a string filled in with the offset of
2920 the most recent & before the first failing
2921 name/value pair (or the beginning of the string if
2922 the failure is in the first name / value pair) or
2923 the terminating NULL if all was successful.
2924
2925 @retval EFI_SUCCESS The request succeeded. Progress points to the null
2926 terminator at the end of the ConfigRequest
2927 string.
2928 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
2929 points to the first character of ConfigRequest.
2930 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
2931 Block parameter would result in this type of
2932 error. Progress points to the first character of
2933 ConfigRequest.
2934 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
2935 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
2936 Block is left updated and Progress points at
2937 the "&" preceding the first non-<BlockName>.
2938
2939 **/
2940 EFI_STATUS
2941 EFIAPI
2942 HiiBlockToConfig (
2943 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2944 IN CONST EFI_STRING ConfigRequest,
2945 IN CONST UINT8 *Block,
2946 IN CONST UINTN BlockSize,
2947 OUT EFI_STRING *Config,
2948 OUT EFI_STRING *Progress
2949 )
2950 {
2951 HII_DATABASE_PRIVATE_DATA *Private;
2952 EFI_STRING StringPtr;
2953 UINTN Length;
2954 EFI_STATUS Status;
2955 EFI_STRING TmpPtr;
2956 UINT8 *TmpBuffer;
2957 UINTN Offset;
2958 UINTN Width;
2959 UINT8 *Value;
2960 EFI_STRING ValueStr;
2961 EFI_STRING ConfigElement;
2962 UINTN Index;
2963 UINT8 *TemBuffer;
2964 CHAR16 *TemString;
2965
2966 if (This == NULL || Progress == NULL || Config == NULL) {
2967 return EFI_INVALID_PARAMETER;
2968 }
2969
2970 if (Block == NULL || ConfigRequest == NULL) {
2971 *Progress = ConfigRequest;
2972 return EFI_INVALID_PARAMETER;
2973 }
2974
2975
2976 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2977 ASSERT (Private != NULL);
2978
2979 StringPtr = ConfigRequest;
2980 ValueStr = NULL;
2981 Value = NULL;
2982 ConfigElement = NULL;
2983
2984 //
2985 // Allocate a fix length of memory to store Results. Reallocate memory for
2986 // Results if this fix length is insufficient.
2987 //
2988 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2989 if (*Config == NULL) {
2990 return EFI_OUT_OF_RESOURCES;
2991 }
2992
2993 //
2994 // Jump <ConfigHdr>
2995 //
2996 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2997 *Progress = StringPtr;
2998 Status = EFI_INVALID_PARAMETER;
2999 goto Exit;
3000 }
3001 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3002 StringPtr++;
3003 }
3004 if (*StringPtr == 0) {
3005 *Progress = StringPtr - 1;
3006 Status = EFI_INVALID_PARAMETER;
3007 goto Exit;
3008 }
3009
3010 while (*StringPtr != L'&' && *StringPtr != 0) {
3011 StringPtr++;
3012 }
3013 if (*StringPtr == 0) {
3014 *Progress = StringPtr - 1;
3015 Status = EFI_INVALID_PARAMETER;
3016 goto Exit;
3017 }
3018 //
3019 // Skip '&'
3020 //
3021 StringPtr++;
3022
3023 //
3024 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
3025 //
3026 Length = StringPtr - ConfigRequest;
3027 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
3028
3029 //
3030 // Parse each <RequestElement> if exists
3031 // Only <BlockName> format is supported by this help function.
3032 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
3033 //
3034 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3035 //
3036 // Back up the header of one <BlockName>
3037 //
3038 TmpPtr = StringPtr;
3039
3040 StringPtr += StrLen (L"OFFSET=");
3041 //
3042 // Get Offset
3043 //
3044 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3045 if (EFI_ERROR (Status)) {
3046 *Progress = ConfigRequest;
3047 goto Exit;
3048 }
3049 Offset = 0;
3050 CopyMem (
3051 &Offset,
3052 TmpBuffer,
3053 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3054 );
3055 FreePool (TmpBuffer);
3056
3057 StringPtr += Length;
3058 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3059 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3060 Status = EFI_INVALID_PARAMETER;
3061 goto Exit;
3062 }
3063 StringPtr += StrLen (L"&WIDTH=");
3064
3065 //
3066 // Get Width
3067 //
3068 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3069 if (EFI_ERROR (Status)) {
3070 *Progress = ConfigRequest;
3071 goto Exit;
3072 }
3073 Width = 0;
3074 CopyMem (
3075 &Width,
3076 TmpBuffer,
3077 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3078 );
3079 FreePool (TmpBuffer);
3080
3081 StringPtr += Length;
3082 if (*StringPtr != 0 && *StringPtr != L'&') {
3083 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3084 Status = EFI_INVALID_PARAMETER;
3085 goto Exit;
3086 }
3087
3088 //
3089 // Calculate Value and convert it to hex string.
3090 //
3091 if (Offset + Width > BlockSize) {
3092 *Progress = StringPtr;
3093 Status = EFI_DEVICE_ERROR;
3094 goto Exit;
3095 }
3096
3097 Value = (UINT8 *) AllocateZeroPool (Width);
3098 if (Value == NULL) {
3099 *Progress = ConfigRequest;
3100 Status = EFI_OUT_OF_RESOURCES;
3101 goto Exit;
3102 }
3103
3104 CopyMem (Value, (UINT8 *) Block + Offset, Width);
3105
3106 Length = Width * 2 + 1;
3107 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
3108 if (ValueStr == NULL) {
3109 *Progress = ConfigRequest;
3110 Status = EFI_OUT_OF_RESOURCES;
3111 goto Exit;
3112 }
3113
3114 TemString = ValueStr;
3115 TemBuffer = Value + Width - 1;
3116 for (Index = 0; Index < Width; Index ++, TemBuffer --) {
3117 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
3118 }
3119
3120 FreePool (Value);
3121 Value = NULL;
3122
3123 //
3124 // Build a ConfigElement
3125 //
3126 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
3127 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
3128 if (ConfigElement == NULL) {
3129 Status = EFI_OUT_OF_RESOURCES;
3130 goto Exit;
3131 }
3132 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
3133 if (*StringPtr == 0) {
3134 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
3135 }
3136 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
3137 StrCat (ConfigElement, L"VALUE=");
3138 StrCat (ConfigElement, ValueStr);
3139
3140 AppendToMultiString (Config, ConfigElement);
3141
3142 FreePool (ConfigElement);
3143 FreePool (ValueStr);
3144 ConfigElement = NULL;
3145 ValueStr = NULL;
3146
3147 //
3148 // If '\0', parsing is finished. Otherwise skip '&' to continue
3149 //
3150 if (*StringPtr == 0) {
3151 break;
3152 }
3153 AppendToMultiString (Config, L"&");
3154 StringPtr++;
3155
3156 }
3157
3158 if (*StringPtr != 0) {
3159 *Progress = StringPtr - 1;
3160 Status = EFI_INVALID_PARAMETER;
3161 goto Exit;
3162 }
3163
3164 HiiToLower (*Config);
3165 *Progress = StringPtr;
3166 return EFI_SUCCESS;
3167
3168 Exit:
3169 if (*Config != NULL) {
3170 FreePool (*Config);
3171 *Config = NULL;
3172 }
3173 if (ValueStr != NULL) {
3174 FreePool (ValueStr);
3175 }
3176 if (Value != NULL) {
3177 FreePool (Value);
3178 }
3179 if (ConfigElement != NULL) {
3180 FreePool (ConfigElement);
3181 }
3182
3183 return Status;
3184
3185 }
3186
3187
3188 /**
3189 This helper function is to be called by drivers to map configuration strings
3190 to configurations stored in byte array ("block") formats such as UEFI Variables.
3191
3192 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3193 instance.
3194 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
3195 format.
3196 @param Block A possibly null array of bytes representing the
3197 current block. Only bytes referenced in the
3198 ConfigResp string in the block are modified. If
3199 this parameter is null or if the *BlockSize
3200 parameter is (on input) shorter than required by
3201 the Configuration string, only the BlockSize
3202 parameter is updated and an appropriate status
3203 (see below) is returned.
3204 @param BlockSize The length of the Block in units of UINT8. On
3205 input, this is the size of the Block. On output,
3206 if successful, contains the index of the last
3207 modified byte in the Block.
3208 @param Progress On return, points to an element of the ConfigResp
3209 string filled in with the offset of the most
3210 recent '&' before the first failing name / value
3211 pair (or the beginning of the string if the
3212 failure is in the first name / value pair) or the
3213 terminating NULL if all was successful.
3214
3215 @retval EFI_SUCCESS The request succeeded. Progress points to the null
3216 terminator at the end of the ConfigResp string.
3217 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
3218 points to the first character of ConfigResp.
3219 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
3220 Block parameter would result in this type of
3221 error. Progress points to the first character of
3222 ConfigResp.
3223 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
3224 value pair. Block is left updated and
3225 Progress points at the '&' preceding the first
3226 non-<BlockName>.
3227 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
3228 @retval EFI_NOT_FOUND Target for the specified routing data was not found.
3229 Progress points to the "G" in "GUID" of the errant
3230 routing data.
3231
3232 **/
3233 EFI_STATUS
3234 EFIAPI
3235 HiiConfigToBlock (
3236 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3237 IN CONST EFI_STRING ConfigResp,
3238 IN OUT UINT8 *Block,
3239 IN OUT UINTN *BlockSize,
3240 OUT EFI_STRING *Progress
3241 )
3242 {
3243 HII_DATABASE_PRIVATE_DATA *Private;
3244 EFI_STRING StringPtr;
3245 UINTN Length;
3246 EFI_STATUS Status;
3247 UINT8 *TmpBuffer;
3248 UINTN Offset;
3249 UINTN Width;
3250 UINT8 *Value;
3251 UINTN BufferSize;
3252 UINTN MaxBlockSize;
3253
3254 if (This == NULL || BlockSize == NULL || Progress == NULL) {
3255 return EFI_INVALID_PARAMETER;
3256 }
3257
3258 *Progress = ConfigResp;
3259 if (ConfigResp == NULL) {
3260 return EFI_INVALID_PARAMETER;
3261 }
3262
3263 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3264 ASSERT (Private != NULL);
3265
3266 StringPtr = ConfigResp;
3267 BufferSize = *BlockSize;
3268 Value = NULL;
3269 MaxBlockSize = 0;
3270
3271 //
3272 // Jump <ConfigHdr>
3273 //
3274 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3275 *Progress = StringPtr;
3276 Status = EFI_INVALID_PARAMETER;
3277 goto Exit;
3278 }
3279 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3280 StringPtr++;
3281 }
3282 if (*StringPtr == 0) {
3283 *Progress = StringPtr;
3284 Status = EFI_INVALID_PARAMETER;
3285 goto Exit;
3286 }
3287
3288 while (*StringPtr != L'&' && *StringPtr != 0) {
3289 StringPtr++;
3290 }
3291 if (*StringPtr == 0) {
3292 *Progress = StringPtr;
3293 Status = EFI_INVALID_PARAMETER;
3294 goto Exit;
3295 }
3296 //
3297 // Skip '&'
3298 //
3299 StringPtr++;
3300
3301 //
3302 // Parse each <ConfigElement> if exists
3303 // Only <BlockConfig> format is supported by this help function.
3304 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
3305 //
3306 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3307 StringPtr += StrLen (L"OFFSET=");
3308 //
3309 // Get Offset
3310 //
3311 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3312 if (EFI_ERROR (Status)) {
3313 *Progress = ConfigResp;
3314 goto Exit;
3315 }
3316 Offset = 0;
3317 CopyMem (
3318 &Offset,
3319 TmpBuffer,
3320 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3321 );
3322 FreePool (TmpBuffer);
3323
3324 StringPtr += Length;
3325 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3326 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3327 Status = EFI_INVALID_PARAMETER;
3328 goto Exit;
3329 }
3330 StringPtr += StrLen (L"&WIDTH=");
3331
3332 //
3333 // Get Width
3334 //
3335 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3336 if (EFI_ERROR (Status)) {
3337 *Progress = ConfigResp;
3338 goto Exit;
3339 }
3340 Width = 0;
3341 CopyMem (
3342 &Width,
3343 TmpBuffer,
3344 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3345 );
3346 FreePool (TmpBuffer);
3347
3348 StringPtr += Length;
3349 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
3350 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3351 Status = EFI_INVALID_PARAMETER;
3352 goto Exit;
3353 }
3354 StringPtr += StrLen (L"&VALUE=");
3355
3356 //
3357 // Get Value
3358 //
3359 Status = GetValueOfNumber (StringPtr, &Value, &Length);
3360 if (EFI_ERROR (Status)) {
3361 *Progress = ConfigResp;
3362 goto Exit;
3363 }
3364
3365 StringPtr += Length;
3366 if (*StringPtr != 0 && *StringPtr != L'&') {
3367 *Progress = StringPtr - Length - 7;
3368 Status = EFI_INVALID_PARAMETER;
3369 goto Exit;
3370 }
3371
3372 //
3373 // Update the Block with configuration info
3374 //
3375 if ((Block != NULL) && (Offset + Width <= BufferSize)) {
3376 CopyMem (Block + Offset, Value, Width);
3377 }
3378 if (Offset + Width > MaxBlockSize) {
3379 MaxBlockSize = Offset + Width;
3380 }
3381
3382 FreePool (Value);
3383 Value = NULL;
3384
3385 //
3386 // If '\0', parsing is finished. Otherwise skip '&' to continue
3387 //
3388 if (*StringPtr == 0) {
3389 break;
3390 }
3391
3392 StringPtr++;
3393 }
3394
3395 //
3396 // The input string is ConfigAltResp format.
3397 //
3398 if ((*StringPtr != 0) && (StrnCmp (StringPtr, L"&GUID=", StrLen (L"&GUID=")) != 0)) {
3399 *Progress = StringPtr - 1;
3400 Status = EFI_INVALID_PARAMETER;
3401 goto Exit;
3402 }
3403
3404 *Progress = StringPtr + StrLen (StringPtr);
3405 *BlockSize = MaxBlockSize - 1;
3406
3407 if (MaxBlockSize > BufferSize) {
3408 *BlockSize = MaxBlockSize;
3409 if (Block != NULL) {
3410 return EFI_DEVICE_ERROR;
3411 }
3412 }
3413
3414 if (Block == NULL) {
3415 *Progress = ConfigResp;
3416 return EFI_INVALID_PARAMETER;
3417 }
3418
3419 return EFI_SUCCESS;
3420
3421 Exit:
3422
3423 if (Value != NULL) {
3424 FreePool (Value);
3425 }
3426 return Status;
3427 }
3428
3429
3430 /**
3431 This helper function is to be called by drivers to extract portions of
3432 a larger configuration string.
3433
3434 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3435 instance.
3436 @param Configuration A null-terminated Unicode string in
3437 <MultiConfigAltResp> format.
3438 @param Guid A pointer to the GUID value to search for in the
3439 routing portion of the ConfigResp string when
3440 retrieving the requested data. If Guid is NULL,
3441 then all GUID values will be searched for.
3442 @param Name A pointer to the NAME value to search for in the
3443 routing portion of the ConfigResp string when
3444 retrieving the requested data. If Name is NULL,
3445 then all Name values will be searched for.
3446 @param DevicePath A pointer to the PATH value to search for in the
3447 routing portion of the ConfigResp string when
3448 retrieving the requested data. If DevicePath is
3449 NULL, then all DevicePath values will be searched
3450 for.
3451 @param AltCfgId A pointer to the ALTCFG value to search for in the
3452 routing portion of the ConfigResp string when
3453 retrieving the requested data. If this parameter
3454 is NULL, then the current setting will be
3455 retrieved.
3456 @param AltCfgResp A pointer to a buffer which will be allocated by
3457 the function which contains the retrieved string
3458 as requested. This buffer is only allocated if
3459 the call was successful. It is <ConfigResp> format.
3460
3461 @retval EFI_SUCCESS The request succeeded. The requested data was
3462 extracted and placed in the newly allocated
3463 AltCfgResp buffer.
3464 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
3465 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
3466 @retval EFI_NOT_FOUND Target for the specified routing data was not
3467 found.
3468
3469 **/
3470 EFI_STATUS
3471 EFIAPI
3472 HiiGetAltCfg (
3473 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3474 IN CONST EFI_STRING Configuration,
3475 IN CONST EFI_GUID *Guid,
3476 IN CONST EFI_STRING Name,
3477 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3478 IN CONST UINT16 *AltCfgId,
3479 OUT EFI_STRING *AltCfgResp
3480 )
3481 {
3482 EFI_STATUS Status;
3483 EFI_STRING StringPtr;
3484 EFI_STRING HdrStart;
3485 EFI_STRING HdrEnd;
3486 EFI_STRING TmpPtr;
3487 UINTN Length;
3488 EFI_STRING GuidStr;
3489 EFI_STRING NameStr;
3490 EFI_STRING PathStr;
3491 EFI_STRING AltIdStr;
3492 EFI_STRING Result;
3493 BOOLEAN GuidFlag;
3494 BOOLEAN NameFlag;
3495 BOOLEAN PathFlag;
3496
3497 HdrStart = NULL;
3498 HdrEnd = NULL;
3499 GuidStr = NULL;
3500 NameStr = NULL;
3501 PathStr = NULL;
3502 AltIdStr = NULL;
3503 Result = NULL;
3504 GuidFlag = FALSE;
3505 NameFlag = FALSE;
3506 PathFlag = FALSE;
3507
3508 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
3509 return EFI_INVALID_PARAMETER;
3510 }
3511
3512 StringPtr = Configuration;
3513 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3514 return EFI_INVALID_PARAMETER;
3515 }
3516
3517 //
3518 // Generate the sub string for later matching.
3519 //
3520 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
3521 GenerateSubStr (
3522 L"PATH=",
3523 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
3524 (VOID *) DevicePath,
3525 1,
3526 &PathStr
3527 );
3528 if (AltCfgId != NULL) {
3529 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
3530 }
3531 if (Name != NULL) {
3532 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
3533 } else {
3534 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
3535 }
3536
3537 while (*StringPtr != 0) {
3538 //
3539 // Try to match the GUID
3540 //
3541 if (!GuidFlag) {
3542 TmpPtr = StrStr (StringPtr, GuidStr);
3543 if (TmpPtr == NULL) {
3544 Status = EFI_NOT_FOUND;
3545 goto Exit;
3546 }
3547 HdrStart = TmpPtr;
3548
3549 //
3550 // Jump to <NameHdr>
3551 //
3552 if (Guid != NULL) {
3553 StringPtr = TmpPtr + StrLen (GuidStr);
3554 } else {
3555 StringPtr = StrStr (TmpPtr, L"NAME=");
3556 if (StringPtr == NULL) {
3557 Status = EFI_NOT_FOUND;
3558 goto Exit;
3559 }
3560 }
3561 GuidFlag = TRUE;
3562 }
3563
3564 //
3565 // Try to match the NAME
3566 //
3567 if (GuidFlag && !NameFlag) {
3568 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
3569 GuidFlag = FALSE;
3570 } else {
3571 //
3572 // Jump to <PathHdr>
3573 //
3574 if (Name != NULL) {
3575 StringPtr += StrLen (NameStr);
3576 } else {
3577 StringPtr = StrStr (StringPtr, L"PATH=");
3578 if (StringPtr == NULL) {
3579 Status = EFI_NOT_FOUND;
3580 goto Exit;
3581 }
3582 }
3583 NameFlag = TRUE;
3584 }
3585 }
3586
3587 //
3588 // Try to match the DevicePath
3589 //
3590 if (GuidFlag && NameFlag && !PathFlag) {
3591 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
3592 GuidFlag = FALSE;
3593 NameFlag = FALSE;
3594 } else {
3595 //
3596 // Jump to '&' before <DescHdr> or <ConfigBody>
3597 //
3598 if (DevicePath != NULL) {
3599 StringPtr += StrLen (PathStr);
3600 } else {
3601 StringPtr = StrStr (StringPtr, L"&");
3602 if (StringPtr == NULL) {
3603 Status = EFI_NOT_FOUND;
3604 goto Exit;
3605 }
3606 StringPtr ++;
3607 }
3608 PathFlag = TRUE;
3609 HdrEnd = StringPtr;
3610 }
3611 }
3612
3613 //
3614 // Try to match the AltCfgId
3615 //
3616 if (GuidFlag && NameFlag && PathFlag) {
3617 if (AltCfgId == NULL) {
3618 //
3619 // Return Current Setting when AltCfgId is NULL.
3620 //
3621 Status = OutputConfigBody (StringPtr, &Result);
3622 goto Exit;
3623 }
3624 //
3625 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
3626 //
3627 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
3628 GuidFlag = FALSE;
3629 NameFlag = FALSE;
3630 PathFlag = FALSE;
3631 } else {
3632 //
3633 // Skip AltIdStr and &
3634 //
3635 StringPtr = StringPtr + StrLen (AltIdStr);
3636 Status = OutputConfigBody (StringPtr, &Result);
3637 goto Exit;
3638 }
3639 }
3640 }
3641
3642 Status = EFI_NOT_FOUND;
3643
3644 Exit:
3645 *AltCfgResp = NULL;
3646 if (!EFI_ERROR (Status) && (Result != NULL)) {
3647 //
3648 // Copy the <ConfigHdr> and <ConfigBody>
3649 //
3650 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
3651 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
3652 if (*AltCfgResp == NULL) {
3653 Status = EFI_OUT_OF_RESOURCES;
3654 } else {
3655 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
3656 StrCat (*AltCfgResp, Result);
3657 Status = EFI_SUCCESS;
3658 }
3659 }
3660
3661 if (GuidStr != NULL) {
3662 FreePool (GuidStr);
3663 }
3664 if (NameStr != NULL) {
3665 FreePool (NameStr);
3666 }
3667 if (PathStr != NULL) {
3668 FreePool (PathStr);
3669 }
3670 if (AltIdStr != NULL) {
3671 FreePool (AltIdStr);
3672 }
3673 if (Result != NULL) {
3674 FreePool (Result);
3675 }
3676
3677 return Status;
3678
3679 }
3680
3681