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