]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
Update the copyright notice format
[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 - 2010, 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 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
457 ASSERT (*StringPtr != L'\0');
458
459 Buf = NULL;
460
461 TmpPtr = StringPtr;
462 while (*StringPtr != L'\0' && *StringPtr != L'&') {
463 StringPtr++;
464 }
465 *Len = StringPtr - TmpPtr;
466 Length = *Len + 1;
467
468 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
469 if (Str == NULL) {
470 Status = EFI_OUT_OF_RESOURCES;
471 goto Exit;
472 }
473 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
474 *(Str + *Len) = L'\0';
475
476 Length = (Length + 1) / 2;
477 Buf = (UINT8 *) AllocateZeroPool (Length);
478 if (Buf == NULL) {
479 Status = EFI_OUT_OF_RESOURCES;
480 goto Exit;
481 }
482
483 Length = *Len;
484 ZeroMem (TemStr, sizeof (TemStr));
485 for (Index = 0; Index < Length; Index ++) {
486 TemStr[0] = Str[Length - Index - 1];
487 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
488 if ((Index & 1) == 0) {
489 Buf [Index/2] = DigitUint8;
490 } else {
491 Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
492 }
493 }
494
495 *Number = Buf;
496 Status = EFI_SUCCESS;
497
498 Exit:
499 if (Str != NULL) {
500 FreePool (Str);
501 }
502
503 return Status;
504 }
505
506 /**
507 This function merges DefaultAltCfgResp string into AltCfgResp string for
508 the missing AltCfgId in AltCfgResq.
509
510 @param AltCfgResp Pointer to a null-terminated Unicode string in
511 <ConfigAltResp> format. The default value string
512 will be merged into it.
513 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
514 <MultiConfigAltResp> format. The default value
515 string may contain more than one ConfigAltResp
516 string for the different varstore buffer.
517
518 @retval EFI_SUCCESS The merged string returns.
519 @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.
520 **/
521 EFI_STATUS
522 EFIAPI
523 MergeDefaultString (
524 IN OUT EFI_STRING *AltCfgResp,
525 IN EFI_STRING DefaultAltCfgResp
526 )
527 {
528 EFI_STRING StringPtrDefault;
529 EFI_STRING StringPtrEnd;
530 CHAR16 TempChar;
531 EFI_STRING StringPtr;
532 EFI_STRING AltConfigHdr;
533 UINTN HeaderLength;
534 UINTN SizeAltCfgResp;
535
536 if (*AltCfgResp == NULL) {
537 return EFI_INVALID_PARAMETER;
538 }
539
540 //
541 // Get the requestr ConfigHdr
542 //
543 SizeAltCfgResp = 0;
544 StringPtr = *AltCfgResp;
545
546 //
547 // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
548 //
549 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
550 return EFI_INVALID_PARAMETER;
551 }
552 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
553 StringPtr++;
554 }
555 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
556 StringPtr++;
557 }
558 if (*StringPtr == L'\0') {
559 return EFI_INVALID_PARAMETER;
560 }
561 StringPtr += StrLen (L"&PATH=");
562 while (*StringPtr != L'\0' && *StringPtr != L'&') {
563 StringPtr ++;
564 }
565 HeaderLength = StringPtr - *AltCfgResp;
566
567 //
568 // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"
569 // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
570 //
571 AltConfigHdr = AllocateZeroPool ((1 + HeaderLength + 8 + 4 + 1) * sizeof (CHAR16));
572 if (AltConfigHdr == NULL) {
573 return EFI_OUT_OF_RESOURCES;
574 }
575 StrCpy (AltConfigHdr, L"&");
576 StrnCat (AltConfigHdr, *AltCfgResp, HeaderLength);
577 StrCat (AltConfigHdr, L"&ALTCFG=");
578 HeaderLength = StrLen (AltConfigHdr);
579
580 StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
581 while (StringPtrDefault != NULL) {
582 //
583 // Get AltCfg Name
584 //
585 StrnCat (AltConfigHdr, StringPtrDefault + HeaderLength, 4);
586 StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
587
588 //
589 // Append the found default value string to the input AltCfgResp
590 //
591 if (StringPtr == NULL) {
592 StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");
593 SizeAltCfgResp = StrSize (*AltCfgResp);
594 if (StringPtrEnd == NULL) {
595 //
596 // No more default string is found.
597 //
598 *AltCfgResp = (EFI_STRING) ReallocatePool (
599 SizeAltCfgResp,
600 SizeAltCfgResp + StrSize (StringPtrDefault),
601 (VOID *) (*AltCfgResp)
602 );
603 if (*AltCfgResp == NULL) {
604 FreePool (AltConfigHdr);
605 return EFI_OUT_OF_RESOURCES;
606 }
607 StrCat (*AltCfgResp, StringPtrDefault);
608 break;
609 } else {
610 TempChar = *StringPtrEnd;
611 *StringPtrEnd = L'\0';
612 *AltCfgResp = (EFI_STRING) ReallocatePool (
613 SizeAltCfgResp,
614 SizeAltCfgResp + StrSize (StringPtrDefault),
615 (VOID *) (*AltCfgResp)
616 );
617 if (*AltCfgResp == NULL) {
618 FreePool (AltConfigHdr);
619 return EFI_OUT_OF_RESOURCES;
620 }
621 StrCat (*AltCfgResp, StringPtrDefault);
622 *StringPtrEnd = TempChar;
623 }
624 }
625
626 //
627 // Find next AltCfg String
628 //
629 *(AltConfigHdr + HeaderLength) = L'\0';
630 StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
631 }
632
633 FreePool (AltConfigHdr);
634 return EFI_SUCCESS;
635 }
636
637 /**
638 This function finds the matched DefaultName for the input DefaultId
639
640 @param DefaultIdArray Array stores the map table between DefaultId and DefaultName.
641 @param VarDefaultId Default Id
642 @param VarDefaultName Default Name string ID for the input default ID.
643
644 @retval EFI_SUCCESS The mapped default name string ID is found.
645 @retval EFI_NOT_FOUND The mapped default name string ID is not found.
646 **/
647 EFI_STATUS
648 FindDefaultName (
649 IN IFR_DEFAULT_DATA *DefaultIdArray,
650 IN UINT16 VarDefaultId,
651 OUT EFI_STRING_ID *VarDefaultName
652 )
653 {
654 LIST_ENTRY *Link;
655 IFR_DEFAULT_DATA *DefaultData;
656
657 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
658 DefaultData = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
659 if (DefaultData->DefaultId == VarDefaultId) {
660 *VarDefaultName = DefaultData->DefaultName;
661 return EFI_SUCCESS;
662 }
663 }
664
665 return EFI_NOT_FOUND;
666 }
667
668 /**
669 This function inserts new DefaultValueData into the BlockData DefaultValue array.
670
671 @param BlockData The BlockData is updated to add new default value.
672 @param DefaultValueData The DefaultValue is added.
673
674 **/
675 VOID
676 InsertDefaultValue (
677 IN IFR_BLOCK_DATA *BlockData,
678 IN IFR_DEFAULT_DATA *DefaultValueData
679 )
680 {
681 LIST_ENTRY *Link;
682 IFR_DEFAULT_DATA *DefaultValueArray;
683
684 for (Link = BlockData->DefaultValueEntry.ForwardLink; Link != &BlockData->DefaultValueEntry; Link = Link->ForwardLink) {
685 DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
686 if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
687 if (DefaultValueData->OpCode == EFI_IFR_DEFAULT_OP) {
688 //
689 // Update the default value array in BlockData.
690 //
691 DefaultValueArray->Value = DefaultValueData->Value;
692 } else if (DefaultValueArray->OpCode != EFI_IFR_DEFAULT_OP) {
693 //
694 // Update the default value array in BlockData.
695 //
696 DefaultValueArray->Value = DefaultValueData->Value;
697 }
698 FreePool (DefaultValueData);
699 return;
700 } else if (DefaultValueArray->DefaultId > DefaultValueData->DefaultId) {
701 //
702 // Insert new default value data in the front of this default value array.
703 //
704 InsertTailList (Link, &DefaultValueData->Entry);
705 return;
706 }
707 }
708
709 //
710 // Insert new default value data in tail.
711 //
712 InsertTailList (Link, &DefaultValueData->Entry);
713 return;
714 }
715
716 /**
717 This function inserts new BlockData into the block link
718
719 @param BlockLink The list entry points to block array.
720 @param BlockData The point to BlockData is added.
721
722 **/
723 VOID
724 InsertBlockData (
725 IN LIST_ENTRY *BlockLink,
726 IN IFR_BLOCK_DATA **BlockData
727 )
728 {
729 LIST_ENTRY *Link;
730 IFR_BLOCK_DATA *BlockArray;
731 IFR_BLOCK_DATA *BlockSingleData;
732
733 BlockSingleData = *BlockData;
734
735 //
736 // Insert block data in its Offset and Width order.
737 //
738 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
739 BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
740 if (BlockArray->Offset == BlockSingleData->Offset) {
741 if (BlockArray->Width > BlockSingleData->Width) {
742 //
743 // Insert this block data in the front of block array
744 //
745 InsertTailList (Link, &BlockSingleData->Entry);
746 return;
747 }
748
749 if (BlockArray->Width == BlockSingleData->Width) {
750 //
751 // The same block array has been added.
752 //
753 FreePool (BlockSingleData);
754 *BlockData = BlockArray;
755 return;
756 }
757 } else if (BlockArray->Offset > BlockSingleData->Offset) {
758 //
759 // Insert new block data in the front of block array
760 //
761 InsertTailList (Link, &BlockSingleData->Entry);
762 return;
763 }
764 }
765
766 //
767 // Add new block data into the tail.
768 //
769 InsertTailList (Link, &BlockSingleData->Entry);
770 return;
771 }
772
773 /**
774 This function checks VarOffset and VarWidth is in the block range.
775
776 @param RequestBlockArray The block array is to be checked.
777 @param VarOffset Offset of var to the structure
778 @param VarWidth Width of var.
779
780 @retval TRUE This Var is in the block range.
781 @retval FALSE This Var is not in the block range.
782 **/
783 BOOLEAN
784 BlockArrayCheck (
785 IN IFR_BLOCK_DATA *RequestBlockArray,
786 IN UINT16 VarOffset,
787 IN UINT16 VarWidth
788 )
789 {
790 LIST_ENTRY *Link;
791 IFR_BLOCK_DATA *BlockData;
792
793 //
794 // No Request Block array, all vars are got.
795 //
796 if (RequestBlockArray == NULL) {
797 return TRUE;
798 }
799
800 //
801 // Check the input var is in the request block range.
802 //
803 for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
804 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
805 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
806 return TRUE;
807 }
808 }
809
810 return FALSE;
811 }
812
813 /**
814 This function parses Form Package to get the block array and the default
815 value array according to the request ConfigHdr.
816
817 @param Package Pointer to the form package data.
818 @param PackageLength Length of the pacakge.
819 @param ConfigHdr Request string ConfigHdr. If it is NULL,
820 the first found varstore will be as ConfigHdr.
821 @param RequestBlockArray The block array is retrieved from the request string.
822 @param VarStorageData VarStorage structure contains the got block and default value.
823 @param PIfrDefaultIdArray Point to the got default id and default name array.
824
825 @retval EFI_SUCCESS The block array and the default value array are got.
826 @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges
827 are conflicted.
828 @retval EFI_OUT_OF_RESOURCES No enough memory.
829 **/
830 EFI_STATUS
831 EFIAPI
832 ParseIfrData (
833 IN UINT8 *Package,
834 IN UINT32 PackageLength,
835 IN EFI_STRING ConfigHdr,
836 IN IFR_BLOCK_DATA *RequestBlockArray,
837 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
838 OUT IFR_DEFAULT_DATA *DefaultIdArray
839 )
840 {
841 EFI_STATUS Status;
842 UINTN IfrOffset;
843 EFI_IFR_VARSTORE *IfrVarStore;
844 EFI_IFR_OP_HEADER *IfrOpHdr;
845 EFI_IFR_ONE_OF *IfrOneOf;
846 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
847 EFI_IFR_DEFAULT *IfrDefault;
848 EFI_IFR_ORDERED_LIST *IfrOrderedList;
849 EFI_IFR_CHECKBOX *IfrCheckBox;
850 EFI_IFR_PASSWORD *IfrPassword;
851 EFI_IFR_STRING *IfrString;
852 IFR_DEFAULT_DATA *DefaultData;
853 IFR_BLOCK_DATA *BlockData;
854 CHAR16 *VarStoreName;
855 UINT16 VarOffset;
856 UINT16 VarWidth;
857 EFI_STRING_ID VarDefaultName;
858 UINT16 VarDefaultId;
859 EFI_STRING GuidStr;
860 EFI_STRING NameStr;
861 EFI_STRING TempStr;
862 UINTN LengthString;
863
864 LengthString = 0;
865 Status = EFI_SUCCESS;
866 GuidStr = NULL;
867 NameStr = NULL;
868 TempStr = NULL;
869 BlockData = NULL;
870 DefaultData = NULL;
871 VarDefaultName = 0;
872
873 //
874 // Go through the form package to parse OpCode one by one.
875 //
876 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
877 while (IfrOffset < PackageLength) {
878 IfrOpHdr = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);
879
880 switch (IfrOpHdr->OpCode) {
881 case EFI_IFR_VARSTORE_OP:
882 //
883 // VarStore is found. Don't need to search any more.
884 //
885 if (VarStorageData->Size != 0) {
886 break;
887 }
888
889 //
890 // Get the requied varstore information
891 // Add varstore by Guid and Name in ConfigHdr
892 // Make sure Offset is in varstore size and varstoreid
893 //
894 IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
895 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
896 if (VarStoreName == NULL) {
897 Status = EFI_OUT_OF_RESOURCES;
898 goto Done;
899 }
900 AsciiStrToUnicodeStr ((CHAR8 *) IfrVarStore->Name, VarStoreName);
901
902 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrVarStore->Guid, 1, &GuidStr);
903 GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);
904 LengthString = StrLen (GuidStr);
905 LengthString = LengthString + StrLen (NameStr) + 1;
906 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
907 if (TempStr == NULL) {
908 FreePool (GuidStr);
909 FreePool (NameStr);
910 FreePool (VarStoreName);
911 Status = EFI_OUT_OF_RESOURCES;
912 goto Done;
913 }
914 StrCpy (TempStr, GuidStr);
915 StrCat (TempStr, NameStr);
916 if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
917 //
918 // Find the matched VarStore
919 //
920 CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);
921 VarStorageData->VarStoreId = IfrVarStore->VarStoreId;
922 VarStorageData->Size = IfrVarStore->Size;
923 VarStorageData->Name = VarStoreName;
924 } else {
925 //
926 // No found, free the allocated memory
927 //
928 FreePool (VarStoreName);
929 }
930 //
931 // Free alllocated temp string.
932 //
933 FreePool (GuidStr);
934 FreePool (NameStr);
935 FreePool (TempStr);
936 break;
937
938 case EFI_IFR_DEFAULTSTORE_OP:
939 //
940 // Add new the map between default id and default name.
941 //
942 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
943 if (DefaultData == NULL) {
944 Status = EFI_OUT_OF_RESOURCES;
945 goto Done;
946 }
947 DefaultData->DefaultId = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
948 DefaultData->DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName;
949 InsertTailList (&DefaultIdArray->Entry, &DefaultData->Entry);
950 DefaultData = NULL;
951 break;
952
953 case EFI_IFR_FORM_OP:
954 case EFI_IFR_FORM_MAP_OP:
955 //
956 // No matched varstore is found and directly return.
957 //
958 if (VarStorageData->Size == 0) {
959 Status = EFI_SUCCESS;
960 goto Done;
961 }
962 break;
963
964 case EFI_IFR_ONE_OF_OP:
965 case EFI_IFR_NUMERIC_OP:
966 //
967 // Numeric and OneOf has the same opcode structure.
968 //
969
970 //
971 // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
972 //
973 if (VarStorageData->Size == 0) {
974 Status = EFI_INVALID_PARAMETER;
975 goto Done;
976 }
977 //
978 // Check whether this question is for the requested varstore.
979 //
980 IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
981 if (IfrOneOf->Question.VarStoreId != VarStorageData->VarStoreId) {
982 break;
983 }
984
985 //
986 // Get Offset/Width by Question header and OneOf Flags
987 //
988 VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
989 VarWidth = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
990 //
991 // Check whether this question is in requested block array.
992 //
993 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
994 //
995 // This question is not in the requested string. Skip it.
996 //
997 break;
998 }
999
1000 //
1001 // Check this var question is in the var storage
1002 //
1003 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1004 Status = EFI_INVALID_PARAMETER;
1005 goto Done;
1006 }
1007
1008 //
1009 // Set Block Data
1010 //
1011 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1012 if (BlockData == NULL) {
1013 Status = EFI_OUT_OF_RESOURCES;
1014 goto Done;
1015 }
1016 BlockData->Offset = VarOffset;
1017 BlockData->Width = VarWidth;
1018 BlockData->QuestionId = IfrOneOf->Question.QuestionId;
1019 BlockData->OpCode = IfrOpHdr->OpCode;
1020 BlockData->Scope = IfrOpHdr->Scope;
1021 InitializeListHead (&BlockData->DefaultValueEntry);
1022 //
1023 // Add Block Data into VarStorageData BlockEntry
1024 //
1025 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1026 break;
1027
1028 case EFI_IFR_ORDERED_LIST_OP:
1029 //
1030 // offset by question header
1031 // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
1032 // no default value and default id, how to define its default value?
1033 //
1034
1035 //
1036 // OrderedList question is not in IFR Form. This IFR form is not valid.
1037 //
1038 if (VarStorageData->Size == 0) {
1039 Status = EFI_INVALID_PARAMETER;
1040 goto Done;
1041 }
1042 //
1043 // Check whether this question is for the requested varstore.
1044 //
1045 IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;
1046 if (IfrOrderedList->Question.VarStoreId != VarStorageData->VarStoreId) {
1047 BlockData = NULL;
1048 break;
1049 }
1050
1051 //
1052 // Get Offset/Width by Question header and OneOf Flags
1053 //
1054 VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset;
1055 VarWidth = IfrOrderedList->MaxContainers;
1056
1057 //
1058 // Set Block Data
1059 //
1060 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1061 if (BlockData == NULL) {
1062 Status = EFI_OUT_OF_RESOURCES;
1063 goto Done;
1064 }
1065 BlockData->Offset = VarOffset;
1066 BlockData->Width = VarWidth;
1067 BlockData->QuestionId = IfrOrderedList->Question.QuestionId;
1068 BlockData->OpCode = IfrOpHdr->OpCode;
1069 BlockData->Scope = IfrOpHdr->Scope;
1070 InitializeListHead (&BlockData->DefaultValueEntry);
1071 break;
1072
1073 case EFI_IFR_CHECKBOX_OP:
1074 //
1075 // EFI_IFR_DEFAULT_OP
1076 // offset by question header
1077 // width is 1 sizeof (BOOLEAN)
1078 // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
1079 // value by DefaultOption
1080 // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
1081 //
1082
1083 //
1084 // CheckBox question is not in IFR Form. This IFR form is not valid.
1085 //
1086 if (VarStorageData->Size == 0) {
1087 Status = EFI_INVALID_PARAMETER;
1088 goto Done;
1089 }
1090 //
1091 // Check whether this question is for the requested varstore.
1092 //
1093 IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1094 if (IfrCheckBox->Question.VarStoreId != VarStorageData->VarStoreId) {
1095 break;
1096 }
1097
1098 //
1099 // Get Offset/Width by Question header and OneOf Flags
1100 //
1101 VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1102 VarWidth = sizeof (BOOLEAN);
1103
1104 //
1105 // Check whether this question is in requested block array.
1106 //
1107 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1108 //
1109 // This question is not in the requested string. Skip it.
1110 //
1111 break;
1112 }
1113
1114 //
1115 // Check this var question is in the var storage
1116 //
1117 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1118 Status = EFI_INVALID_PARAMETER;
1119 goto Done;
1120 }
1121
1122 //
1123 // Set Block Data
1124 //
1125 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1126 if (BlockData == NULL) {
1127 Status = EFI_OUT_OF_RESOURCES;
1128 goto Done;
1129 }
1130 BlockData->Offset = VarOffset;
1131 BlockData->Width = VarWidth;
1132 BlockData->QuestionId = IfrCheckBox->Question.QuestionId;
1133 BlockData->OpCode = IfrOpHdr->OpCode;
1134 BlockData->Scope = IfrOpHdr->Scope;
1135 InitializeListHead (&BlockData->DefaultValueEntry);
1136 //
1137 // Add Block Data into VarStorageData BlockEntry
1138 //
1139 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1140
1141 //
1142 // Add default value by CheckBox Flags
1143 //
1144 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
1145 //
1146 // Set standard ID to Manufacture ID and Get DefaultName String ID
1147 //
1148 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1149 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1150 if (EFI_ERROR (Status)) {
1151 goto Done;
1152 }
1153 //
1154 // Prepare new DefaultValue
1155 //
1156 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1157 if (DefaultData == NULL) {
1158 Status = EFI_OUT_OF_RESOURCES;
1159 goto Done;
1160 }
1161 DefaultData->OpCode = IfrOpHdr->OpCode;
1162 DefaultData->DefaultId = VarDefaultId;
1163 DefaultData->DefaultName = VarDefaultName;
1164 DefaultData->Value = 1;
1165 //
1166 // Add DefaultValue into current BlockData
1167 //
1168 InsertDefaultValue (BlockData, DefaultData);
1169 }
1170
1171 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
1172 //
1173 // Set standard ID to Manufacture ID and Get DefaultName String ID
1174 //
1175 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1176 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1177 if (EFI_ERROR (Status)) {
1178 goto Done;
1179 }
1180 //
1181 // Prepare new DefaultValue
1182 //
1183 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1184 if (DefaultData == NULL) {
1185 Status = EFI_OUT_OF_RESOURCES;
1186 goto Done;
1187 }
1188 DefaultData->OpCode = IfrOpHdr->OpCode;
1189 DefaultData->DefaultId = VarDefaultId;
1190 DefaultData->DefaultName = VarDefaultName;
1191 DefaultData->Value = 1;
1192 //
1193 // Add DefaultValue into current BlockData
1194 //
1195 InsertDefaultValue (BlockData, DefaultData);
1196 }
1197 break;
1198
1199 case EFI_IFR_STRING_OP:
1200 //
1201 // offset by question header
1202 // width MaxSize * sizeof (CHAR16)
1203 // no default value, only block array
1204 //
1205
1206 //
1207 // String question is not in IFR Form. This IFR form is not valid.
1208 //
1209 if (VarStorageData->Size == 0) {
1210 Status = EFI_INVALID_PARAMETER;
1211 goto Done;
1212 }
1213 //
1214 // Check whether this question is for the requested varstore.
1215 //
1216 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1217 if (IfrString->Question.VarStoreId != VarStorageData->VarStoreId) {
1218 break;
1219 }
1220
1221 //
1222 // Get Offset/Width by Question header and OneOf Flags
1223 //
1224 VarOffset = IfrString->Question.VarStoreInfo.VarOffset;
1225 VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1226
1227 //
1228 // Check whether this question is in requested block array.
1229 //
1230 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1231 //
1232 // This question is not in the requested string. Skip it.
1233 //
1234 break;
1235 }
1236
1237 //
1238 // Check this var question is in the var storage
1239 //
1240 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1241 Status = EFI_INVALID_PARAMETER;
1242 goto Done;
1243 }
1244
1245 //
1246 // Set Block Data
1247 //
1248 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1249 if (BlockData == NULL) {
1250 Status = EFI_OUT_OF_RESOURCES;
1251 goto Done;
1252 }
1253 BlockData->Offset = VarOffset;
1254 BlockData->Width = VarWidth;
1255 BlockData->QuestionId = IfrString->Question.QuestionId;
1256 BlockData->OpCode = IfrOpHdr->OpCode;
1257 InitializeListHead (&BlockData->DefaultValueEntry);
1258
1259 //
1260 // Add Block Data into VarStorageData BlockEntry
1261 //
1262 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1263
1264 //
1265 // No default value for string.
1266 //
1267 BlockData = NULL;
1268 break;
1269
1270 case EFI_IFR_PASSWORD_OP:
1271 //
1272 // offset by question header
1273 // width MaxSize * sizeof (CHAR16)
1274 // no default value, only block array
1275 //
1276
1277 //
1278 // Password question is not in IFR Form. This IFR form is not valid.
1279 //
1280 if (VarStorageData->Size == 0) {
1281 Status = EFI_INVALID_PARAMETER;
1282 goto Done;
1283 }
1284 //
1285 // Check whether this question is for the requested varstore.
1286 //
1287 IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
1288 if (IfrPassword->Question.VarStoreId != VarStorageData->VarStoreId) {
1289 break;
1290 }
1291
1292 //
1293 // Get Offset/Width by Question header and OneOf Flags
1294 //
1295 VarOffset = IfrPassword->Question.VarStoreInfo.VarOffset;
1296 VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
1297
1298 //
1299 // Check whether this question is in requested block array.
1300 //
1301 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1302 //
1303 // This question is not in the requested string. Skip it.
1304 //
1305 break;
1306 }
1307
1308 //
1309 // Check this var question is in the var storage
1310 //
1311 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1312 Status = EFI_INVALID_PARAMETER;
1313 goto Done;
1314 }
1315
1316 //
1317 // Set Block Data
1318 //
1319 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1320 if (BlockData == NULL) {
1321 Status = EFI_OUT_OF_RESOURCES;
1322 goto Done;
1323 }
1324 BlockData->Offset = VarOffset;
1325 BlockData->Width = VarWidth;
1326 BlockData->QuestionId = IfrPassword->Question.QuestionId;
1327 BlockData->OpCode = IfrOpHdr->OpCode;
1328 InitializeListHead (&BlockData->DefaultValueEntry);
1329
1330 //
1331 // Add Block Data into VarStorageData BlockEntry
1332 //
1333 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1334
1335 //
1336 // No default value for string.
1337 //
1338 BlockData = NULL;
1339 break;
1340
1341 case EFI_IFR_ONE_OF_OPTION_OP:
1342 //
1343 // No matched block data is ignored.
1344 //
1345 if (BlockData == NULL || BlockData->Scope == 0) {
1346 break;
1347 }
1348
1349 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1350 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1351 //
1352 // Get ordered list option data type.
1353 //
1354 if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
1355 VarWidth = 1;
1356 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
1357 VarWidth = 2;
1358 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
1359 VarWidth = 4;
1360 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
1361 VarWidth = 8;
1362 } else {
1363 //
1364 // Invalid ordered list option data type.
1365 //
1366 Status = EFI_INVALID_PARAMETER;
1367 FreePool (BlockData);
1368 goto Done;
1369 }
1370
1371 //
1372 // Calculate Ordered list QuestionId width.
1373 //
1374 BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
1375 //
1376 // Check whether this question is in requested block array.
1377 //
1378 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width)) {
1379 //
1380 // This question is not in the requested string. Skip it.
1381 //
1382 FreePool (BlockData);
1383 BlockData = NULL;
1384 break;
1385 }
1386 //
1387 // Check this var question is in the var storage
1388 //
1389 if ((BlockData->Offset + BlockData->Width) > VarStorageData->Size) {
1390 Status = EFI_INVALID_PARAMETER;
1391 FreePool (BlockData);
1392 goto Done;
1393 }
1394 //
1395 // Add Block Data into VarStorageData BlockEntry
1396 //
1397 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1398 //
1399 // No default data for OrderedList.
1400 //
1401 BlockData = NULL;
1402 break;
1403 }
1404
1405 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {
1406 //
1407 // Set standard ID to Manufacture ID and Get DefaultName String ID
1408 //
1409 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1410 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1411 if (EFI_ERROR (Status)) {
1412 goto Done;
1413 }
1414 //
1415 // Prepare new DefaultValue
1416 //
1417 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1418 if (DefaultData == NULL) {
1419 Status = EFI_OUT_OF_RESOURCES;
1420 goto Done;
1421 }
1422 DefaultData->OpCode = IfrOpHdr->OpCode;
1423 DefaultData->DefaultId = VarDefaultId;
1424 DefaultData->DefaultName = VarDefaultName;
1425 DefaultData->Value = IfrOneOfOption->Value.u64;
1426 //
1427 // Add DefaultValue into current BlockData
1428 //
1429 InsertDefaultValue (BlockData, DefaultData);
1430 }
1431
1432 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
1433 //
1434 // Set default ID to Manufacture ID and Get DefaultName String ID
1435 //
1436 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1437 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1438 if (EFI_ERROR (Status)) {
1439 goto Done;
1440 }
1441 //
1442 // Prepare new DefaultValue
1443 //
1444 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1445 if (DefaultData == NULL) {
1446 Status = EFI_OUT_OF_RESOURCES;
1447 goto Done;
1448 }
1449 DefaultData->OpCode = IfrOpHdr->OpCode;
1450 DefaultData->DefaultId = VarDefaultId;
1451 DefaultData->DefaultName = VarDefaultName;
1452 DefaultData->Value = IfrOneOfOption->Value.u64;
1453 //
1454 // Add DefaultValue into current BlockData
1455 //
1456 InsertDefaultValue (BlockData, DefaultData);
1457 }
1458 break;
1459
1460 case EFI_IFR_DEFAULT_OP:
1461 //
1462 // Update Current BlockData to the default value.
1463 //
1464 if (BlockData == NULL || BlockData->Scope == 0) {
1465 //
1466 // No matched block data is ignored.
1467 //
1468 break;
1469 }
1470
1471 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1472 //
1473 // OrderedList Opcode is no default value.
1474 //
1475 break;
1476 }
1477 //
1478 // Get the DefaultId and DefaultName String ID
1479 //
1480 IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
1481 VarDefaultId = IfrDefault->DefaultId;
1482 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1483 if (EFI_ERROR (Status)) {
1484 goto Done;
1485 }
1486 //
1487 // Prepare new DefaultValue
1488 //
1489 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1490 if (DefaultData == NULL) {
1491 Status = EFI_OUT_OF_RESOURCES;
1492 goto Done;
1493 }
1494 DefaultData->OpCode = IfrOpHdr->OpCode;
1495 DefaultData->DefaultId = VarDefaultId;
1496 DefaultData->DefaultName = VarDefaultName;
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->DefaultName
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 (Status == EFI_OUT_OF_RESOURCES) {
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 (Status == EFI_OUT_OF_RESOURCES) {
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
3228 **/
3229 EFI_STATUS
3230 EFIAPI
3231 HiiConfigToBlock (
3232 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3233 IN CONST EFI_STRING ConfigResp,
3234 IN OUT UINT8 *Block,
3235 IN OUT UINTN *BlockSize,
3236 OUT EFI_STRING *Progress
3237 )
3238 {
3239 HII_DATABASE_PRIVATE_DATA *Private;
3240 EFI_STRING StringPtr;
3241 UINTN Length;
3242 EFI_STATUS Status;
3243 UINT8 *TmpBuffer;
3244 UINTN Offset;
3245 UINTN Width;
3246 UINT8 *Value;
3247 UINTN BufferSize;
3248
3249 if (This == NULL || BlockSize == NULL || Progress == NULL) {
3250 return EFI_INVALID_PARAMETER;
3251 }
3252
3253 if (ConfigResp == NULL || Block == NULL) {
3254 *Progress = ConfigResp;
3255 return EFI_INVALID_PARAMETER;
3256 }
3257
3258 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3259 ASSERT (Private != NULL);
3260
3261 StringPtr = ConfigResp;
3262 BufferSize = *BlockSize;
3263 Value = NULL;
3264
3265 //
3266 // Jump <ConfigHdr>
3267 //
3268 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3269 *Progress = StringPtr;
3270 Status = EFI_INVALID_PARAMETER;
3271 goto Exit;
3272 }
3273 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3274 StringPtr++;
3275 }
3276 if (*StringPtr == 0) {
3277 *Progress = StringPtr;
3278 Status = EFI_INVALID_PARAMETER;
3279 goto Exit;
3280 }
3281
3282 while (*StringPtr != L'&' && *StringPtr != 0) {
3283 StringPtr++;
3284 }
3285 if (*StringPtr == 0) {
3286 *Progress = StringPtr;
3287 Status = EFI_INVALID_PARAMETER;
3288 goto Exit;
3289 }
3290 //
3291 // Skip '&'
3292 //
3293 StringPtr++;
3294
3295 //
3296 // Parse each <ConfigElement> if exists
3297 // Only <BlockConfig> format is supported by this help function.
3298 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
3299 //
3300 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3301 StringPtr += StrLen (L"OFFSET=");
3302 //
3303 // Get Offset
3304 //
3305 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3306 if (EFI_ERROR (Status)) {
3307 *Progress = ConfigResp;
3308 goto Exit;
3309 }
3310 Offset = 0;
3311 CopyMem (
3312 &Offset,
3313 TmpBuffer,
3314 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3315 );
3316 FreePool (TmpBuffer);
3317
3318 StringPtr += Length;
3319 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3320 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3321 Status = EFI_INVALID_PARAMETER;
3322 goto Exit;
3323 }
3324 StringPtr += StrLen (L"&WIDTH=");
3325
3326 //
3327 // Get Width
3328 //
3329 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3330 if (Status == EFI_OUT_OF_RESOURCES) {
3331 *Progress = ConfigResp;
3332 goto Exit;
3333 }
3334 Width = 0;
3335 CopyMem (
3336 &Width,
3337 TmpBuffer,
3338 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3339 );
3340 FreePool (TmpBuffer);
3341
3342 StringPtr += Length;
3343 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
3344 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3345 Status = EFI_INVALID_PARAMETER;
3346 goto Exit;
3347 }
3348 StringPtr += StrLen (L"&VALUE=");
3349
3350 //
3351 // Get Value
3352 //
3353 Status = GetValueOfNumber (StringPtr, &Value, &Length);
3354 if (EFI_ERROR (Status)) {
3355 *Progress = ConfigResp;
3356 goto Exit;
3357 }
3358
3359 StringPtr += Length;
3360 if (*StringPtr != 0 && *StringPtr != L'&') {
3361 *Progress = StringPtr - Length - 7;
3362 Status = EFI_INVALID_PARAMETER;
3363 goto Exit;
3364 }
3365
3366 //
3367 // Update the Block with configuration info
3368 //
3369
3370 if (Offset + Width > BufferSize) {
3371 return EFI_DEVICE_ERROR;
3372 }
3373
3374 CopyMem (Block + Offset, Value, Width);
3375 *BlockSize = Offset + Width - 1;
3376
3377 FreePool (Value);
3378 Value = NULL;
3379
3380 //
3381 // If '\0', parsing is finished. Otherwise skip '&' to continue
3382 //
3383 if (*StringPtr == 0) {
3384 break;
3385 }
3386
3387 StringPtr++;
3388 }
3389
3390 //
3391 // The input string is ConfigAltResp format.
3392 //
3393 if ((*StringPtr != 0) && (StrnCmp (StringPtr, L"&GUID=", StrLen (L"&GUID=")) != 0)) {
3394 *Progress = StringPtr - 1;
3395 Status = EFI_INVALID_PARAMETER;
3396 goto Exit;
3397 }
3398
3399 *Progress = StringPtr + StrLen (StringPtr);
3400 return EFI_SUCCESS;
3401
3402 Exit:
3403
3404 if (Value != NULL) {
3405 FreePool (Value);
3406 }
3407 return Status;
3408 }
3409
3410
3411 /**
3412 This helper function is to be called by drivers to extract portions of
3413 a larger configuration string.
3414
3415 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3416 instance.
3417 @param Configuration A null-terminated Unicode string in
3418 <MultiConfigAltResp> format.
3419 @param Guid A pointer to the GUID value to search for in the
3420 routing portion of the ConfigResp string when
3421 retrieving the requested data. If Guid is NULL,
3422 then all GUID values will be searched for.
3423 @param Name A pointer to the NAME value to search for in the
3424 routing portion of the ConfigResp string when
3425 retrieving the requested data. If Name is NULL,
3426 then all Name values will be searched for.
3427 @param DevicePath A pointer to the PATH value to search for in the
3428 routing portion of the ConfigResp string when
3429 retrieving the requested data. If DevicePath is
3430 NULL, then all DevicePath values will be searched
3431 for.
3432 @param AltCfgId A pointer to the ALTCFG value to search for in the
3433 routing portion of the ConfigResp string when
3434 retrieving the requested data. If this parameter
3435 is NULL, then the current setting will be
3436 retrieved.
3437 @param AltCfgResp A pointer to a buffer which will be allocated by
3438 the function which contains the retrieved string
3439 as requested. This buffer is only allocated if
3440 the call was successful. It is <ConfigResp> format.
3441
3442 @retval EFI_SUCCESS The request succeeded. The requested data was
3443 extracted and placed in the newly allocated
3444 AltCfgResp buffer.
3445 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
3446 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
3447 @retval EFI_NOT_FOUND Target for the specified routing data was not
3448 found.
3449
3450 **/
3451 EFI_STATUS
3452 EFIAPI
3453 HiiGetAltCfg (
3454 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3455 IN CONST EFI_STRING Configuration,
3456 IN CONST EFI_GUID *Guid,
3457 IN CONST EFI_STRING Name,
3458 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3459 IN CONST UINT16 *AltCfgId,
3460 OUT EFI_STRING *AltCfgResp
3461 )
3462 {
3463 EFI_STATUS Status;
3464 EFI_STRING StringPtr;
3465 EFI_STRING HdrStart;
3466 EFI_STRING HdrEnd;
3467 EFI_STRING TmpPtr;
3468 UINTN Length;
3469 EFI_STRING GuidStr;
3470 EFI_STRING NameStr;
3471 EFI_STRING PathStr;
3472 EFI_STRING AltIdStr;
3473 EFI_STRING Result;
3474 BOOLEAN GuidFlag;
3475 BOOLEAN NameFlag;
3476 BOOLEAN PathFlag;
3477
3478 HdrStart = NULL;
3479 HdrEnd = NULL;
3480 GuidStr = NULL;
3481 NameStr = NULL;
3482 PathStr = NULL;
3483 AltIdStr = NULL;
3484 Result = NULL;
3485 GuidFlag = FALSE;
3486 NameFlag = FALSE;
3487 PathFlag = FALSE;
3488
3489 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
3490 return EFI_INVALID_PARAMETER;
3491 }
3492
3493 StringPtr = Configuration;
3494 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3495 return EFI_INVALID_PARAMETER;
3496 }
3497
3498 //
3499 // Generate the sub string for later matching.
3500 //
3501 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
3502 GenerateSubStr (
3503 L"PATH=",
3504 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
3505 (VOID *) DevicePath,
3506 1,
3507 &PathStr
3508 );
3509 if (AltCfgId != NULL) {
3510 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
3511 }
3512 if (Name != NULL) {
3513 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
3514 } else {
3515 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
3516 }
3517
3518 while (*StringPtr != 0) {
3519 //
3520 // Try to match the GUID
3521 //
3522 if (!GuidFlag) {
3523 TmpPtr = StrStr (StringPtr, GuidStr);
3524 if (TmpPtr == NULL) {
3525 Status = EFI_NOT_FOUND;
3526 goto Exit;
3527 }
3528 HdrStart = TmpPtr;
3529
3530 //
3531 // Jump to <NameHdr>
3532 //
3533 if (Guid != NULL) {
3534 StringPtr = TmpPtr + StrLen (GuidStr);
3535 } else {
3536 StringPtr = StrStr (TmpPtr, L"NAME=");
3537 if (StringPtr == NULL) {
3538 Status = EFI_NOT_FOUND;
3539 goto Exit;
3540 }
3541 }
3542 GuidFlag = TRUE;
3543 }
3544
3545 //
3546 // Try to match the NAME
3547 //
3548 if (GuidFlag && !NameFlag) {
3549 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
3550 GuidFlag = FALSE;
3551 } else {
3552 //
3553 // Jump to <PathHdr>
3554 //
3555 if (Name != NULL) {
3556 StringPtr += StrLen (NameStr);
3557 } else {
3558 StringPtr = StrStr (StringPtr, L"PATH=");
3559 if (StringPtr == NULL) {
3560 Status = EFI_NOT_FOUND;
3561 goto Exit;
3562 }
3563 }
3564 NameFlag = TRUE;
3565 }
3566 }
3567
3568 //
3569 // Try to match the DevicePath
3570 //
3571 if (GuidFlag && NameFlag && !PathFlag) {
3572 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
3573 GuidFlag = FALSE;
3574 NameFlag = FALSE;
3575 } else {
3576 //
3577 // Jump to '&' before <DescHdr> or <ConfigBody>
3578 //
3579 if (DevicePath != NULL) {
3580 StringPtr += StrLen (PathStr);
3581 } else {
3582 StringPtr = StrStr (StringPtr, L"&");
3583 if (StringPtr == NULL) {
3584 Status = EFI_NOT_FOUND;
3585 goto Exit;
3586 }
3587 StringPtr ++;
3588 }
3589 PathFlag = TRUE;
3590 HdrEnd = StringPtr;
3591 }
3592 }
3593
3594 //
3595 // Try to match the AltCfgId
3596 //
3597 if (GuidFlag && NameFlag && PathFlag) {
3598 if (AltCfgId == NULL) {
3599 //
3600 // Return Current Setting when AltCfgId is NULL.
3601 //
3602 Status = OutputConfigBody (StringPtr, &Result);
3603 goto Exit;
3604 }
3605 //
3606 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
3607 //
3608 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
3609 GuidFlag = FALSE;
3610 NameFlag = FALSE;
3611 PathFlag = FALSE;
3612 } else {
3613 //
3614 // Skip AltIdStr and &
3615 //
3616 StringPtr = StringPtr + StrLen (AltIdStr);
3617 Status = OutputConfigBody (StringPtr, &Result);
3618 goto Exit;
3619 }
3620 }
3621 }
3622
3623 Status = EFI_NOT_FOUND;
3624
3625 Exit:
3626 *AltCfgResp = NULL;
3627 if (!EFI_ERROR (Status) && (Result != NULL)) {
3628 //
3629 // Copy the <ConfigHdr> and <ConfigBody>
3630 //
3631 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
3632 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
3633 if (*AltCfgResp == NULL) {
3634 Status = EFI_OUT_OF_RESOURCES;
3635 } else {
3636 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
3637 StrCat (*AltCfgResp, Result);
3638 Status = EFI_SUCCESS;
3639 }
3640 }
3641
3642 if (GuidStr != NULL) {
3643 FreePool (GuidStr);
3644 }
3645 if (NameStr != NULL) {
3646 FreePool (NameStr);
3647 }
3648 if (PathStr != NULL) {
3649 FreePool (PathStr);
3650 }
3651 if (AltIdStr != NULL) {
3652 FreePool (AltIdStr);
3653 }
3654 if (Result != NULL) {
3655 FreePool (Result);
3656 }
3657
3658 return Status;
3659
3660 }
3661
3662