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